From e8f141a1c75a157093f6148cfab85cfa6d5f2216 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Mon, 27 Nov 2023 16:40:50 +0000 Subject: [PATCH] Update documentation --- .buildinfo | 4 + .doctrees/api-processbuilder.doctree | Bin 0 -> 14642 bytes .doctrees/api-processes.doctree | Bin 0 -> 2093354 bytes .doctrees/api.doctree | Bin 0 -> 2098824 bytes .doctrees/auth.doctree | Bin 0 -> 87707 bytes .doctrees/basics.doctree | Bin 0 -> 60290 bytes .doctrees/batch_jobs.doctree | Bin 0 -> 63875 bytes .doctrees/best_practices.doctree | Bin 0 -> 15054 bytes .doctrees/changelog.doctree | Bin 0 -> 245195 bytes .doctrees/configuration.doctree | Bin 0 -> 23343 bytes .doctrees/cookbook/ard.doctree | Bin 0 -> 26857 bytes .doctrees/cookbook/index.doctree | Bin 0 -> 3013 bytes .doctrees/cookbook/job_manager.doctree | Bin 0 -> 54753 bytes .doctrees/cookbook/localprocessing.doctree | Bin 0 -> 26081 bytes .doctrees/cookbook/sampling.doctree | Bin 0 -> 10090 bytes .doctrees/cookbook/spectral_indices.doctree | Bin 0 -> 100572 bytes .doctrees/cookbook/tricks.doctree | Bin 0 -> 13007 bytes .doctrees/cookbook/udp_sharing.doctree | Bin 0 -> 20815 bytes .doctrees/data_access.doctree | Bin 0 -> 51260 bytes .doctrees/datacube_construction.doctree | Bin 0 -> 26664 bytes .doctrees/development.doctree | Bin 0 -> 80657 bytes .doctrees/environment.pickle | Bin 0 -> 8727160 bytes .doctrees/index.doctree | Bin 0 -> 8414 bytes .doctrees/installation.doctree | Bin 0 -> 19971 bytes .doctrees/machine_learning.doctree | Bin 0 -> 18521 bytes .doctrees/process_mapping.doctree | Bin 0 -> 309167 bytes .doctrees/processes.doctree | Bin 0 -> 63037 bytes .doctrees/udf.doctree | Bin 0 -> 128164 bytes .doctrees/udp.doctree | Bin 0 -> 67182 bytes .nojekyll | 0 _images/apply-rescaled-histogram.png | Bin 0 -> 5777 bytes _images/batchjobs-jupyter-created.png | Bin 0 -> 56503 bytes _images/batchjobs-jupyter-listing.png | Bin 0 -> 46962 bytes _images/batchjobs-jupyter-logs.png | Bin 0 -> 24868 bytes _images/batchjobs-webeditor-listing.png | Bin 0 -> 63115 bytes _images/evi-composite.png | Bin 0 -> 31940 bytes _images/evi-masked-composite.png | Bin 0 -> 47434 bytes _images/evi-timeseries.png | Bin 0 -> 45092 bytes _images/local_ndvi.jpg | Bin 0 -> 96185 bytes _images/logging_arrayshape.png | Bin 0 -> 65288 bytes _images/welcome.png | Bin 0 -> 92455 bytes _modules/index.html | 144 + _modules/openeo/api/logs.html | 227 + _modules/openeo/api/process.html | 290 + _modules/openeo/extra/job_management.html | 607 ++ .../spectral_indices/spectral_indices.html | 618 ++ _modules/openeo/internal/graph_building.html | 571 ++ _modules/openeo/metadata.html | 670 ++ _modules/openeo/processes.html | 6332 ++++++++++++ _modules/openeo/rest/_datacube.html | 455 + _modules/openeo/rest/connection.html | 2099 ++++ _modules/openeo/rest/conversions.html | 261 + _modules/openeo/rest/datacube.html | 2895 ++++++ _modules/openeo/rest/graph_building.html | 206 + _modules/openeo/rest/job.html | 734 ++ _modules/openeo/rest/mlmodel.html | 254 + _modules/openeo/rest/udp.html | 263 + _modules/openeo/rest/userfile.html | 239 + _modules/openeo/rest/vectorcube.html | 725 ++ _modules/openeo/udf/debug.html | 155 + _modules/openeo/udf/run_code.html | 366 + _modules/openeo/udf/structured_data.html | 172 + _modules/openeo/udf/udf_data.html | 281 + _modules/openeo/udf/udf_signatures.html | 221 + _modules/openeo/udf/xarraydatacube.html | 522 + _modules/openeo/util.html | 826 ++ _sources/api-processbuilder.rst.txt | 87 + _sources/api-processes.rst.txt | 69 + _sources/api.rst.txt | 148 + _sources/auth.rst.txt | 614 ++ _sources/basics.rst.txt | 453 + _sources/batch_jobs.rst.txt | 413 + _sources/best_practices.rst.txt | 93 + _sources/changelog.md.txt | 2 + _sources/configuration.rst.txt | 95 + _sources/cookbook/ard.rst.txt | 113 + _sources/cookbook/index.rst.txt | 14 + _sources/cookbook/job_manager.rst.txt | 9 + _sources/cookbook/localprocessing.rst.txt | 180 + _sources/cookbook/sampling.rst.txt | 60 + _sources/cookbook/spectral_indices.rst.txt | 88 + _sources/cookbook/tricks.rst.txt | 82 + _sources/cookbook/udp_sharing.rst.txt | 125 + _sources/data_access.rst.txt | 344 + _sources/datacube_construction.rst.txt | 178 + _sources/development.rst.txt | 419 + _sources/index.rst.txt | 75 + _sources/installation.rst.txt | 119 + _sources/machine_learning.rst.txt | 118 + _sources/process_mapping.rst.txt | 332 + _sources/processes.rst.txt | 465 + _sources/udf.rst.txt | 556 ++ _sources/udp.rst.txt | 514 + _static/alabaster.css | 703 ++ _static/basic.css | 925 ++ _static/custom.css | 139 + _static/doctools.js | 156 + _static/documentation_options.js | 13 + _static/file.png | Bin 0 -> 286 bytes _static/images/basics/evi-composite.png | Bin 0 -> 31940 bytes .../images/basics/evi-masked-composite.png | Bin 0 -> 47434 bytes _static/images/basics/evi-timeseries.png | Bin 0 -> 45092 bytes _static/images/batchjobs-jupyter-created.png | Bin 0 -> 56503 bytes _static/images/batchjobs-jupyter-listing.png | Bin 0 -> 46962 bytes _static/images/batchjobs-jupyter-logs.png | Bin 0 -> 24868 bytes .../images/batchjobs-webeditor-listing.png | Bin 0 -> 63115 bytes _static/images/local/local_ndvi.jpg | Bin 0 -> 96185 bytes .../images/udf/apply-rescaled-histogram.png | Bin 0 -> 5777 bytes _static/images/udf/logging_arrayshape.png | Bin 0 -> 65288 bytes _static/images/vito-logo.png | Bin 0 -> 8365 bytes _static/images/welcome.png | Bin 0 -> 92455 bytes _static/language_data.js | 199 + _static/minus.png | Bin 0 -> 90 bytes _static/plus.png | Bin 0 -> 90 bytes _static/pygments.css | 75 + _static/searchtools.js | 574 ++ _static/sphinx_highlight.js | 154 + api-processbuilder.html | 194 + api-processes.html | 8523 +++++++++++++++++ api.html | 6062 ++++++++++++ auth.html | 666 ++ basics.html | 518 + batch_jobs.html | 444 + best_practices.html | 211 + changelog.html | 1135 +++ configuration.html | 237 + cookbook/ard.html | 232 + cookbook/index.html | 215 + cookbook/job_manager.html | 316 + cookbook/localprocessing.html | 302 + cookbook/sampling.html | 191 + cookbook/spectral_indices.html | 448 + cookbook/tricks.html | 206 + cookbook/udp_sharing.html | 248 + data_access.html | 409 + datacube_construction.html | 294 + development.html | 516 + genindex.html | 2179 +++++ index.html | 364 + installation.html | 224 + lib/openeo/__init__.py | 26 + lib/openeo/_version.py | 1 + lib/openeo/api/__init__.py | 3 + lib/openeo/api/logs.py | 99 + lib/openeo/api/process.py | 138 + lib/openeo/capabilities.py | 210 + lib/openeo/config.py | 209 + lib/openeo/dates.py | 202 + lib/openeo/extra/__init__.py | 0 lib/openeo/extra/job_management.py | 455 + lib/openeo/extra/spectral_indices/__init__.py | 2 + .../awesome-spectral-indices/LICENSE | 21 + .../awesome-spectral-indices/bands.json | 785 ++ .../awesome-spectral-indices/constants.json | 107 + .../spectral-indices-dict.json | 4616 +++++++++ .../resources/extra-indices-dict.json | 98 + .../spectral_indices/spectral_indices.py | 475 + lib/openeo/internal/__init__.py | 0 lib/openeo/internal/compat.py | 13 + lib/openeo/internal/documentation.py | 56 + lib/openeo/internal/graph_building.py | 422 + lib/openeo/internal/jupyter.py | 177 + lib/openeo/internal/process_graph_visitor.py | 266 + lib/openeo/internal/processes/__init__.py | 0 lib/openeo/internal/processes/builder.py | 123 + lib/openeo/internal/processes/generator.py | 287 + lib/openeo/internal/processes/parse.py | 114 + lib/openeo/internal/warnings.py | 92 + lib/openeo/local/__init__.py | 3 + lib/openeo/local/collections.py | 240 + lib/openeo/local/connection.py | 275 + lib/openeo/local/processing.py | 82 + lib/openeo/metadata.py | 488 + lib/openeo/processes.py | 5325 ++++++++++ lib/openeo/rest/__init__.py | 92 + lib/openeo/rest/_datacube.py | 321 + lib/openeo/rest/_testing.py | 217 + lib/openeo/rest/auth/__init__.py | 0 lib/openeo/rest/auth/auth.py | 53 + lib/openeo/rest/auth/cli.py | 381 + lib/openeo/rest/auth/config.py | 224 + lib/openeo/rest/auth/oidc.py | 911 ++ lib/openeo/rest/auth/testing.py | 317 + lib/openeo/rest/connection.py | 1815 ++++ lib/openeo/rest/conversions.py | 124 + lib/openeo/rest/datacube.py | 2530 +++++ lib/openeo/rest/graph_building.py | 78 + lib/openeo/rest/job.py | 531 + lib/openeo/rest/mlmodel.py | 117 + lib/openeo/rest/rest_capabilities.py | 54 + lib/openeo/rest/service.py | 58 + lib/openeo/rest/udp.py | 123 + lib/openeo/rest/userfile.py | 99 + lib/openeo/rest/vectorcube.py | 552 ++ lib/openeo/udf/__init__.py | 13 + lib/openeo/udf/debug.py | 30 + lib/openeo/udf/feature_collection.py | 110 + lib/openeo/udf/run_code.py | 241 + lib/openeo/udf/structured_data.py | 47 + lib/openeo/udf/udf_data.py | 135 + lib/openeo/udf/udf_signatures.py | 87 + lib/openeo/udf/xarraydatacube.py | 379 + lib/openeo/util.py | 686 ++ machine_learning.html | 242 + objects.inv | Bin 0 -> 6176 bytes process_mapping.html | 607 ++ processes.html | 537 ++ py-modindex.html | 260 + search.html | 144 + searchindex.js | 1 + udf.html | 775 ++ udp.html | 595 ++ 212 files changed, 81870 insertions(+) create mode 100644 .buildinfo create mode 100644 .doctrees/api-processbuilder.doctree create mode 100644 .doctrees/api-processes.doctree create mode 100644 .doctrees/api.doctree create mode 100644 .doctrees/auth.doctree create mode 100644 .doctrees/basics.doctree create mode 100644 .doctrees/batch_jobs.doctree create mode 100644 .doctrees/best_practices.doctree create mode 100644 .doctrees/changelog.doctree create mode 100644 .doctrees/configuration.doctree create mode 100644 .doctrees/cookbook/ard.doctree create mode 100644 .doctrees/cookbook/index.doctree create mode 100644 .doctrees/cookbook/job_manager.doctree create mode 100644 .doctrees/cookbook/localprocessing.doctree create mode 100644 .doctrees/cookbook/sampling.doctree create mode 100644 .doctrees/cookbook/spectral_indices.doctree create mode 100644 .doctrees/cookbook/tricks.doctree create mode 100644 .doctrees/cookbook/udp_sharing.doctree create mode 100644 .doctrees/data_access.doctree create mode 100644 .doctrees/datacube_construction.doctree create mode 100644 .doctrees/development.doctree create mode 100644 .doctrees/environment.pickle create mode 100644 .doctrees/index.doctree create mode 100644 .doctrees/installation.doctree create mode 100644 .doctrees/machine_learning.doctree create mode 100644 .doctrees/process_mapping.doctree create mode 100644 .doctrees/processes.doctree create mode 100644 .doctrees/udf.doctree create mode 100644 .doctrees/udp.doctree create mode 100644 .nojekyll create mode 100644 _images/apply-rescaled-histogram.png create mode 100644 _images/batchjobs-jupyter-created.png create mode 100644 _images/batchjobs-jupyter-listing.png create mode 100644 _images/batchjobs-jupyter-logs.png create mode 100644 _images/batchjobs-webeditor-listing.png create mode 100644 _images/evi-composite.png create mode 100644 _images/evi-masked-composite.png create mode 100644 _images/evi-timeseries.png create mode 100644 _images/local_ndvi.jpg create mode 100644 _images/logging_arrayshape.png create mode 100644 _images/welcome.png create mode 100644 _modules/index.html create mode 100644 _modules/openeo/api/logs.html create mode 100644 _modules/openeo/api/process.html create mode 100644 _modules/openeo/extra/job_management.html create mode 100644 _modules/openeo/extra/spectral_indices/spectral_indices.html create mode 100644 _modules/openeo/internal/graph_building.html create mode 100644 _modules/openeo/metadata.html create mode 100644 _modules/openeo/processes.html create mode 100644 _modules/openeo/rest/_datacube.html create mode 100644 _modules/openeo/rest/connection.html create mode 100644 _modules/openeo/rest/conversions.html create mode 100644 _modules/openeo/rest/datacube.html create mode 100644 _modules/openeo/rest/graph_building.html create mode 100644 _modules/openeo/rest/job.html create mode 100644 _modules/openeo/rest/mlmodel.html create mode 100644 _modules/openeo/rest/udp.html create mode 100644 _modules/openeo/rest/userfile.html create mode 100644 _modules/openeo/rest/vectorcube.html create mode 100644 _modules/openeo/udf/debug.html create mode 100644 _modules/openeo/udf/run_code.html create mode 100644 _modules/openeo/udf/structured_data.html create mode 100644 _modules/openeo/udf/udf_data.html create mode 100644 _modules/openeo/udf/udf_signatures.html create mode 100644 _modules/openeo/udf/xarraydatacube.html create mode 100644 _modules/openeo/util.html create mode 100644 _sources/api-processbuilder.rst.txt create mode 100644 _sources/api-processes.rst.txt create mode 100644 _sources/api.rst.txt create mode 100644 _sources/auth.rst.txt create mode 100644 _sources/basics.rst.txt create mode 100644 _sources/batch_jobs.rst.txt create mode 100644 _sources/best_practices.rst.txt create mode 100644 _sources/changelog.md.txt create mode 100644 _sources/configuration.rst.txt create mode 100644 _sources/cookbook/ard.rst.txt create mode 100644 _sources/cookbook/index.rst.txt create mode 100644 _sources/cookbook/job_manager.rst.txt create mode 100644 _sources/cookbook/localprocessing.rst.txt create mode 100644 _sources/cookbook/sampling.rst.txt create mode 100644 _sources/cookbook/spectral_indices.rst.txt create mode 100644 _sources/cookbook/tricks.rst.txt create mode 100644 _sources/cookbook/udp_sharing.rst.txt create mode 100644 _sources/data_access.rst.txt create mode 100644 _sources/datacube_construction.rst.txt create mode 100644 _sources/development.rst.txt create mode 100644 _sources/index.rst.txt create mode 100644 _sources/installation.rst.txt create mode 100644 _sources/machine_learning.rst.txt create mode 100644 _sources/process_mapping.rst.txt create mode 100644 _sources/processes.rst.txt create mode 100644 _sources/udf.rst.txt create mode 100644 _sources/udp.rst.txt create mode 100644 _static/alabaster.css create mode 100644 _static/basic.css create mode 100644 _static/custom.css create mode 100644 _static/doctools.js create mode 100644 _static/documentation_options.js create mode 100644 _static/file.png create mode 100644 _static/images/basics/evi-composite.png create mode 100644 _static/images/basics/evi-masked-composite.png create mode 100644 _static/images/basics/evi-timeseries.png create mode 100644 _static/images/batchjobs-jupyter-created.png create mode 100644 _static/images/batchjobs-jupyter-listing.png create mode 100644 _static/images/batchjobs-jupyter-logs.png create mode 100644 _static/images/batchjobs-webeditor-listing.png create mode 100644 _static/images/local/local_ndvi.jpg create mode 100644 _static/images/udf/apply-rescaled-histogram.png create mode 100644 _static/images/udf/logging_arrayshape.png create mode 100644 _static/images/vito-logo.png create mode 100644 _static/images/welcome.png create mode 100644 _static/language_data.js create mode 100644 _static/minus.png create mode 100644 _static/plus.png create mode 100644 _static/pygments.css create mode 100644 _static/searchtools.js create mode 100644 _static/sphinx_highlight.js create mode 100644 api-processbuilder.html create mode 100644 api-processes.html create mode 100644 api.html create mode 100644 auth.html create mode 100644 basics.html create mode 100644 batch_jobs.html create mode 100644 best_practices.html create mode 100644 changelog.html create mode 100644 configuration.html create mode 100644 cookbook/ard.html create mode 100644 cookbook/index.html create mode 100644 cookbook/job_manager.html create mode 100644 cookbook/localprocessing.html create mode 100644 cookbook/sampling.html create mode 100644 cookbook/spectral_indices.html create mode 100644 cookbook/tricks.html create mode 100644 cookbook/udp_sharing.html create mode 100644 data_access.html create mode 100644 datacube_construction.html create mode 100644 development.html create mode 100644 genindex.html create mode 100644 index.html create mode 100644 installation.html create mode 100644 lib/openeo/__init__.py create mode 100644 lib/openeo/_version.py create mode 100644 lib/openeo/api/__init__.py create mode 100644 lib/openeo/api/logs.py create mode 100644 lib/openeo/api/process.py create mode 100644 lib/openeo/capabilities.py create mode 100644 lib/openeo/config.py create mode 100644 lib/openeo/dates.py create mode 100644 lib/openeo/extra/__init__.py create mode 100644 lib/openeo/extra/job_management.py create mode 100644 lib/openeo/extra/spectral_indices/__init__.py create mode 100644 lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/LICENSE create mode 100644 lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/bands.json create mode 100644 lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/constants.json create mode 100644 lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/spectral-indices-dict.json create mode 100644 lib/openeo/extra/spectral_indices/resources/extra-indices-dict.json create mode 100644 lib/openeo/extra/spectral_indices/spectral_indices.py create mode 100644 lib/openeo/internal/__init__.py create mode 100644 lib/openeo/internal/compat.py create mode 100644 lib/openeo/internal/documentation.py create mode 100644 lib/openeo/internal/graph_building.py create mode 100644 lib/openeo/internal/jupyter.py create mode 100644 lib/openeo/internal/process_graph_visitor.py create mode 100644 lib/openeo/internal/processes/__init__.py create mode 100644 lib/openeo/internal/processes/builder.py create mode 100644 lib/openeo/internal/processes/generator.py create mode 100644 lib/openeo/internal/processes/parse.py create mode 100644 lib/openeo/internal/warnings.py create mode 100644 lib/openeo/local/__init__.py create mode 100644 lib/openeo/local/collections.py create mode 100644 lib/openeo/local/connection.py create mode 100644 lib/openeo/local/processing.py create mode 100644 lib/openeo/metadata.py create mode 100644 lib/openeo/processes.py create mode 100644 lib/openeo/rest/__init__.py create mode 100644 lib/openeo/rest/_datacube.py create mode 100644 lib/openeo/rest/_testing.py create mode 100644 lib/openeo/rest/auth/__init__.py create mode 100644 lib/openeo/rest/auth/auth.py create mode 100644 lib/openeo/rest/auth/cli.py create mode 100644 lib/openeo/rest/auth/config.py create mode 100644 lib/openeo/rest/auth/oidc.py create mode 100644 lib/openeo/rest/auth/testing.py create mode 100644 lib/openeo/rest/connection.py create mode 100644 lib/openeo/rest/conversions.py create mode 100644 lib/openeo/rest/datacube.py create mode 100644 lib/openeo/rest/graph_building.py create mode 100644 lib/openeo/rest/job.py create mode 100644 lib/openeo/rest/mlmodel.py create mode 100644 lib/openeo/rest/rest_capabilities.py create mode 100644 lib/openeo/rest/service.py create mode 100644 lib/openeo/rest/udp.py create mode 100644 lib/openeo/rest/userfile.py create mode 100644 lib/openeo/rest/vectorcube.py create mode 100644 lib/openeo/udf/__init__.py create mode 100644 lib/openeo/udf/debug.py create mode 100644 lib/openeo/udf/feature_collection.py create mode 100644 lib/openeo/udf/run_code.py create mode 100644 lib/openeo/udf/structured_data.py create mode 100644 lib/openeo/udf/udf_data.py create mode 100644 lib/openeo/udf/udf_signatures.py create mode 100644 lib/openeo/udf/xarraydatacube.py create mode 100644 lib/openeo/util.py create mode 100644 machine_learning.html create mode 100644 objects.inv create mode 100644 process_mapping.html create mode 100644 processes.html create mode 100644 py-modindex.html create mode 100644 search.html create mode 100644 searchindex.js create mode 100644 udf.html create mode 100644 udp.html diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 000000000..bf41d2871 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 5becfec9c73062105eefb391fbbf0b09 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/api-processbuilder.doctree b/.doctrees/api-processbuilder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..80d0e102a2d712fb255052eec991113b16401e4a GIT binary patch literal 14642 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%0DT#S-7x< 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
  • WIdfYu6ALfT8i@*2!*5^-mNS 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%0Dqq#_dpJda}}@P<4?d4ZzhM)nq^9E2351 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 z%0D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 literal 0 HcmV?d00001 diff --git a/.doctrees/api.doctree b/.doctrees/api.doctree new file mode 100644 index 0000000000000000000000000000000000000000..dbc7d8aca3d59930ad16b758e4c42061532289e9 GIT binary patch literal 2098824 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�x%6g^|wr!2Q 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
    D>WQqFH6g{``K7O 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

    0PuqkX1T)1R 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 F{2y<9{Vf0h literal 0 HcmV?d00001 diff --git a/.doctrees/cookbook/ard.doctree b/.doctrees/cookbook/ard.doctree new file mode 100644 index 0000000000000000000000000000000000000000..b9a3546f46d67dc9530020dde130088290fba00f GIT binary patch literal 26857 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 literal 0 HcmV?d00001 diff --git a/.doctrees/cookbook/index.doctree b/.doctrees/cookbook/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bb03640383853a186d102c47a483d9d4d6ecee63 GIT binary patch literal 3013 zcmZuzU2j`881C98P1+`DyA2I(1tv7MiM2t93$!b=0YVgtG!S>wk#p?CCO-DT_F2=5 zNpLYlC0{Y~XZUqIK3_=+m5v&}e*Jzv&ujnI`TL)}jq=ZrY|e#RoDxcvrpyN4qdF}z zrd)U%9{(O*hey6|$c5E~Nm=k4&`7zE)G!rZ20x7IPDp!NpWm@8bwaE5IPdT--+37x z@xJdk;Urtx@*|xy_0;+zqa!Xd|))0Ut%#=nzFVl9OD-BBc~e)VXPFBcP%&JCMJox<-p zGK*V*kN91_&+qXqe(Zl7bDgoVDU@Pne4)*J91~;uB)@cAtCLg;1pEI&1aHSFlAquk z3q{%D)L3Np-q~g`K{0x%&T?HSx>C8SsC)wf>C_pvTGe{*eI&~7qnsb&dw}mDzQ_3P z`r*1e)B({MQD*<>-0!#B#L)0ZIQNIG#F8vWU1z2ERx2)Oo>)#yv-57dV{;(F5Sbt| zk-|l^w>1!cM8;cN>nCwYlb-+!)^L*n*n@Y^$~C*jI>xu6u-zVd_GYAfie zBAYP7XgJ&OyCsyZR`L?MyP(Ljg5|RD!e12pWBw^W=1VWU!bI98ElKwqNkvxQv&=cP8?)%J z9WGN-c8Uhy{h7!DU2dmSR~IfXTsY^WbKjqVbcQ%>fU!O$pt}QJvDm8|Ch#)Ha<^U< zMq)KU{gX)ZxC_Uf*vre{kEU8Xr5#(@JiFlsamE1*$zrNa79bf~z%ft2(>OXUOx~>| zOtMmvTnNXLX4t@EeW0E`pqyd3HZGCu6+`(p{Vpf6U3UB-TL@Im5m(qospC78O^O-Z z4KIjMs2Vg3BN-%pv?ygUsqm*C3WXXaOr@GeD*1llrYE1DSb^X7);AMoj5Y};ib_Bc zZI4uQaTJ%8Ua`_CtptC3ZReT^{+AzCMwbCJNAIm~Ts!FxVgdk~<*1KDLctFtQL_T` z0_CPyZ-TA3=+)_@in zrdWeNRJ9Zc3<;x%j0Q)gq(p!0{Zf=$R#2TRvWTYxw#c<*n0U*RB}7t}yb@Ma_#7ov zSTd0@kvhtqh8N)2K9aFuLP;_h9n@+`Gv@p|@fVy}W=bM56|GV9dk^yneX5qg=V2rl zV54S0p%j^L;roM!ewed7K~XT&RGiF!VU$b=Vvo%5cer!8eL5aPY)`AZ>{OfCIQZL9 zvkU;5iDS4GKsP)OAU}EV$!DnN&`i^7=A&e3{-ee`m`WmE=ggc6=BA|&uz$>5CgH5_ z$OIIkaf0{!F#wq*EjQZ)5}QYaT=@fgsT^4(T+Fz{2k>r79dW;JGXj?VT7c9Rg}Pa; zt7TGNI1uA4aGc^UBPrTfkquQYONi6+B8Q9k@F}l=dI;dYfJCS%Fwjheqc|sQF}bEE zvIt(ONkzr@N|^^>2A2y3e=l)~amE~++)kl2Pgq8TOz=jFQ??BIuzqC$ta4h-v@5^G z)T{W~@x5x6fV_ZWymdhimpEc(46_N@9U>?|%i-mQ`HhP+&TfCSCavB-5X0KEU34Rb z@N|NFCkm_Ie8#Eu{U~skIU;-=`0UE^`}j}!zV(CEW|gN0sX)u4dswU_k&}&H73Qj> z(nIiQZZ^@f?SH9y>zc6D?yp(wH(tv_M{D*mTaAmu{PuNQ^$sq5OpFu{F~B1Dy;Mty z!XgJ;89UEw`CBCaCcFUp@jwNS@T9cpcjd4h9BbmeR$R7huYPy{BD2`7T^eUwJqF@! IT})2@1qe~G%m4rY literal 0 HcmV?d00001 diff --git a/.doctrees/cookbook/job_manager.doctree b/.doctrees/cookbook/job_manager.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a3b75a55ec114f10775f2eac82904817dc18f251 GIT binary patch literal 54753 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 G3;zSf(W5T_ literal 0 HcmV?d00001 diff --git a/.doctrees/cookbook/sampling.doctree b/.doctrees/cookbook/sampling.doctree new file mode 100644 index 0000000000000000000000000000000000000000..e99014b0ef87a59fa1f9d192202baed3c211da30 GIT binary patch literal 10090 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 I^Rs^U@2+KAivR!s literal 0 HcmV?d00001 diff --git a/.doctrees/cookbook/spectral_indices.doctree b/.doctrees/cookbook/spectral_indices.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c20e36d903ba578ca2bd7799a13aeef1b99b3478 GIT binary patch literal 100572 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 literal 0 HcmV?d00001 diff --git a/.doctrees/cookbook/tricks.doctree b/.doctrees/cookbook/tricks.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d86f89bbb94af624405af1db35574e2a634e9be5 GIT binary patch literal 13007 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 MBzBn)6mDAkUtOp|8~^|S literal 0 HcmV?d00001 diff --git a/.doctrees/data_access.doctree b/.doctrees/data_access.doctree new file mode 100644 index 0000000000000000000000000000000000000000..1d3cff7bda9cbb7417c085b2c40e3ed5c6e83ee8 GIT binary patch literal 51260 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

    `^TD0@Vlle_7 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 literal 0 HcmV?d00001 diff --git a/.doctrees/development.doctree b/.doctrees/development.doctree new file mode 100644 index 0000000000000000000000000000000000000000..b840edea9381bb8a8a64cf5019590ea2c751e74b GIT binary patch literal 80657 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 z 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 z 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

    VK|$LG58@-<~8bB!y{`wtkra&AmK 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≷>)fL<6N@L8d~FiBP%v4c`31_*3Y6Uz()9{IL>PZJ;p6S5qJ z4f}*F`wtL!4w9bEUD$hZu|a0cUjn6oz)|>~-&B{+=NJ%pF*N261mdi#Y9R1IB3T|l zV9j411E);{1fC-Hun-W4MzzvjMMHi}rS(;&%ahge&UljvY`Ba!DGKJ%JUS2vjNfG( z=~v4U$k)a->^n&n0$j8iqmZeUXj8yoYk)vLceiF_C4j(2yATlAXp2DL?I^!cAn=uf z@CN~bKHcY;avKP2v>hPuHA2UHR4N+?gs#V1TonKUA$Tyh82LXW~Pt6V& z2)t->F(430aDl+LV83#Jz_`yx<9yQw0wp~NupM#&2}QelN&l7$A@*L~Wm59tgY_IG}*Q&*3iu0_oSP0s=1rKpnvKsfEeD7Z`X> zf#rd5yUPg(Ui#Q>XEN&bu3Bicpx%2tMNKFuIAYq+_D#l?zQKmxAEW$r>YWcPITlg| z9Q>jCxuq8ld%0jDYl9Q*uK?k}Z}*nA&(UKCLGymICIKM)6{t#RV>tj}hW0goi5fXn zfbfJ|KQIU+%%CS9B>XNAS~*C#2^ES!!i(US3lgUNP68C3luK_GSeTNJ8gjqSTnI!! z#WxIlz}2RjF*bT@9b4uT%wb*;U_!#QRfj42oEuc!-pa@YZVv}EypeUI&@d(C8_b;f zG1xGLiAK>dtX{RC;as(xGH^@-8V1H3jj?;yGD5tc7fBQb4W&jxCjpdKnx@|8L^P7B zn4I~fV!*FK!wNvd+XZC_5R%c-mnk9TYAN2AwR9+;q1Y`OF)I!lzDb}qfXxOp6#Gle z_g+0HHfgh( znL)#!z(?{tO@J6o$nqm>*e7J!e?Y^-U}DY?77;W&0-yHHZQKnJf4G;8}hs1cAI#F=uwoBg&@+t;gA3{|;51RvF%bzX)8UU#kjS#C=D5 z3v*t;Vv&7Eq0Qw46*E>DA{C*4A}%Pz98{C+upM;h zwfH=Re4lVXH~b|x#3^zH`|~Qp@4Kwms8gQb^H^p0ZD`&v^m5eX4y`6%FVR>Ih?t>y z&95O#wBYxVRfedIe1aK|G-lt?3|h1(oni4KKxE|r;*oy~oFf47c=+W4h>5RBz{8Av zN727!tTIf=M7fNQqL8$Qf+(jraCl@2IE2qxprLb@ImT0wLj74Df#;b^A;56x+bpNt zo#ODxj8x$8aKOR~SvN{^+{~5F$A)RHY?KSb`6tGb2mW`AZ z2Md2+pf-Tb1}qf&8wM7NP1-Cd3Kss!@E8yV7D`+wc7OrBFks~~hmJL63rgbkPRCg&Cd3vrHZ0fk;~GHzU2EjK9lPnvWQH0)=>4oHX$twfUo z23i9W@_9R-FgqY&@oh#yibViIcuWKbpM>%Y1qXja5WWKr@@+=Fy3aG@8qQMNj6zEe zAUG*>%xA<;0714#Cw9H?>Oy$f1p<+8FoCy$z#`j>LVF?zxFrt+bV+alz#jH12LO!w zoCyF*dJtecwSa zQMCyG{3HBD03iKZRRG{caK1~ly*JyKu6T8!X?Hn+z_T99R~MSEj?$SmW3`2LqrWln zTcgd_0ceui$#iMNypcSlGIQx0Y@mGyO4~1FE3=mHt?uWByoe^vF^vWR>cIGVXo~#_ zV@I8{2G`M3$^E8%rl56OWw6vMOe7z5d87fJJQwAG)%_zh?-v0HSlwOJn8S&+sHeG% z;CG1+>JnqaHeIc#~zyMTKHTOI|!T-Y-0BNOP-UiWC|&4Mpe@=@U0o0$$nY*rk;y!eKCyD^Uk zC&CG4_*pox3{EHOH|F3M97|T8nrieLoi-j_)?3)o@75>rPi=H$R-uhBLp%Zb<~KwP zECI$aY@c)dN@m9~azSRp0Yt}HH~9Q6Zxj#`AtoPiE;dYIuu)f>HY_6`ddmTD9$GJI zP2;(IH^WgSsL!=g)aTATYAqaxw@9kJ5zo|{)0#hCt36_x4$7N><3ro(y{S&rYoFb( zHQJM{g{g>cqgjlNU>!4*G*W3NtN~a+Q=#Mc@CH6YXQXu6Q5)Xw)i!V5O8@ty+Gt}u z8n4YYrrM2}+5Q+bU3>h^S8p7r&dxPjtwt|`gVm-+=Ih;l4Gxgh4MH;s31pw~X@T(F zPHl6o0Y^>3v4Yfjof~lv_FId*;g+i|F*|%jwHjd{wQHeaPyiK>Kuzq+YkV_$yr1U) z)LTo{2=yD!epLlx_2|5fIvqNpb;3I3?ht*0H@{urO@Nsi0B$hTpSVnF%Lx?wVe{{x ziOm+@4%p0_+c`Xb9buUxGcJitCp__~OSp=RD?k+tEcXyB(>(EBMy;zH;r=!Wf;QoqEjBc-1cZ>sknPPCR1H}8X1MH#$Tv<+YyAr$T zZ>Db&C=SqN`O==0_Y63*;{rVxMmI6WE>&UZ#*d& zja8YJiXtc^(Z>cuxD#!Hn4{4K)5UkxvBvdX^+v0{qZMtf)i#Z!0+_9}8%#9Qt8Ib< zi7~F(TDyt<#Vf6-J|AD^XC#B?P)E#x^}`{vYP+N8X7+X#eIm*5+{jri$KyFUx$;6K>>VpN9@-wOZj)oOa~gdMHzZuDpAYs6H1a7?{E zMxR3e2Ca@vb!zQs7n~EVdaC*eE^{1XP;_K*+^54+YP=iu7Frm!z$5Tq=xSq15rV?Q zuoN2_ne24o$$8*49QLe82AA9IEVR+-PIY#JTgJ1Z!RY*PA>Z;;m~q?;-2Am2Etehf@kf-1J^rkpKqIsw#kF{iH~L*c z%mLonj6z~>X%sqe%$fv=uh;}0JVBOdQMisSauWaFY9(>~1iER9!nJsf6L{#~<(uj< z%Wy4vcHSE=DXyD)OCT^*ak_`9~r3UC7$Pdgxav%n# zx>0|jiy0lAxu8!Z2+^pT7++gSKX_p91%c~LdzP~v;^Tf~#T;w#8gKOLLZboWvzf+; zy`^c~dA=-WIw-Xt5EW1XBH8b~z!5*k=~N-38dqY!0fd+;WDb^dl-j96F1S?@Dv+w- z8(4{K9u=#R55Gf?qOt9qEbW@awf9JTc>{XgZ+`he+SBQF7IwkwneZdGL36swdk$g5J$ zCdaK*J`4MoQ>h&Ho!p8&iIH?9z`n>)oPa8KHikD;@wGu!ryNQg^bx63sr>M`QaQtR z>3cz5#Z)Tunx`g_VJc0^S1R8C98i_YkH%kAsZ76CRi*OfQveOLdjKJ92cRZu^}IGM z+C1nq6ub51tXe+Du3EM!)1472m+!A1iuu9apnIDQ)HA3FIX*haR?1W{Pr9F5`n{o^ zh~jcjmxYt_Y0^@ z0dDLdp@n##s$C@-%ci~5B3YICfqfk0a&*;D>w z%)H*gIzof4mPDR;32B0@XbUI6fA&$grnvt%jA-Ega4K~_!n#qK_a;;EVQd(ska86m zJ}+aX?$U8qnQpx{3Gtv*DNv|(^;^~Q$W#h^4H^cPkga5$aDw-Zg>vDjw~oLx3QRB( zN|{|ruR9*jr!4R*)b9Y(H0Z<^73qb`0}`6v`7`*Pr9*F|bZV`?I3MxBmEB>I zyhc!!05KS!z6~2b!NaHTKUmgwB)u?}Rri-bDJ<(L@IAj7gn(r|4I1;uvM_|L8q2y> zB+CQKdc40pieXtdiaiv9RO409s8-smXw-_Sw7$x`$t$bno$)5Gz=q3sljCu~i${6D zs-T3Gj)l;py&4vCpJG)0WwlgpMJGvU$)7{Rex~W5CCI2sG$ddEHE0Q+uvo#UeIoqR zB#6SCh@j)PIBzx>Y_QUEB69LklxgTbE+5C2_3YRp_uj+U_`US#YDwY){R5L#fv~rW z%`gW``DdZqK4X7^rJR_2{B--%38FGCAO2v!=He>IX^4DnT;=>hM?lyui|ERQdFYBn zpo_753;UXbvBY#_Vl0w21z6=)bT8yO{{e^H6XDP64^#f;Bg9P~Q9BsRtue-uVew7; zUXU*`7z@uk*&{%CjOEb32bR!oFo)qU!dU3ns=`>#pK9!COhsPE%E03wRGZ6*r)+RC zlSIX$fS#<6d&OdrGeDkwJ?Vr85$p3`ABAd(@G01bZ~#mkWC&rk{Wv_6ZD$V@x867wEw-B@;Cm zJ`g{p9R>s$#UYO4uL1vy5I5x*cf<0!g}EJ3*E)$I_bKMLcCv2pSTe_N4V-@B=)X^S zBgOGHBNaG499ZK8tQ(~{ZYHhI!-gsHGRlV0>vF;x$1+%h!h-gcp5=z_$nn~0S!6QV zuZD(!Be|#s-Zw_cWux9YoKOu-D6=K$ZO4E4fEs^D-3~BElcxRyMR{RRvvPALzZ8%e~wReC;!vlK}ba)^l6dY@J_R zvz3luUbA)0#F}Rfs8m~H%E#Yj;WlH?lxk_~#GqzOEAQd0G*3dF7DgRT@s~g;)Zqm9 zo?qB5pblq4WB#ZEMvzsb4#$dQd7utQ`O9Nq*he|#Bg7sSLLJbkR@$p*e1WO7zRJdh zo2%uW@g|SMhJ6A!+nXGNgPGb(1QxldttoUcrs9|EM;Lukwe)SpIS}c_j`F&JEUH8| z0)|e5H}IK+6(-tvL%}`b)zq;7%795L5nFg6$}bdK_#Hv`&Z>;m9`U~2*ZCfb-Sj#F z!V!={2R(SH&@rDeJV6i42J3Oxi|rAw9!}=>_W;1{L6`8rwscM+N>7Rhv+OyYUyH0`zNDp#qmpbvyIhHS*|iFa*U%4fbbRfb4xEC?otcJ=)ER^Z7;M~ zi!#vT$DP(piQl!+1b&x1pSr|k@pG3sIuV^C3!g<5KZEA|CMN=>@Z%DV(DV!o2<{)e#gC;FfXFU5n5L-F6@WA%~2MJp^3x2uSg6$m=jKNtct6ix)LUm$&bj~#m>o*(Iv&smop>S1=>Ur%^5TFO3Ze+0*XY3W6ur4RfcIq`c;EoandqhF zN{Rm2L`MKCY|#hw!XO!s3+;tLGSH(1%@PfgaRoK8%t*$2;Ujs95g-QR(*GVC_HpTU z?s4@Z8DBus3nLj{@|Qp795-sDJZxQsWsXPa3%O1pJ+7SyV4+^f4W z-N4qm32n1isDPHO@8Yu|{gIBRgwPOSs&!v14P z!@ZGiG*^fH$rjpb<8xCNqr$lTlt!juXH=_Ultw1&tU<$mZZXap8|y?Rt;9M5f)|4& z@wpFmHzM44cBVq@WdS;ACW!QHU zzZc|r3?{`>diGdb9+P@Lsy<;-FTh`fNzt!Wg-MP1EmApc5DXP9C-QW(mEeZHC!WhW zk+}JT*@F^CtfGkntj$4RgJScGi_73if8>5{=~+X?lK>*pc!doi9cWnFJP81#XYL(s zo&x_qWp7i+d^sr0+jVJ62Kmi5Axm@@h5?z}-`1!>C`kqx`6$WlKwsr3$z8}aLP|VU!0uE8q7OIT!7$mB8dG5D>Pl2%FxrJB;1mWgRKaZZpOG7B)=L zgV8XIzH%{;{U>2|;QN5|!U?mr__VgSLJ}yIFk1uP^P3q839}=hG5>@ax~{4dX1{7@IWw*Qp7QG`voYF_qR=nK!xIUza5;+jx^p zvEee_hR%@`#dM9b3?JDPBbv_A(sWWQEH*7n|VRxPU>c}N!=9dbTZ9RT6ttD zLF3i|?-qLE6F((6nM0GWogO7=m{a96Oyp)>kUbfhmjV*gr1NRW(%QzesJ$aA!voj)ASIf36&>O#*JTy@z|rZUJiPgG4%+LmZ$gdsZJk(<||f5pWwmhc20GAhBs^8i+ZLV$}m!` zM>#{wpj>MP9onln40|6CSb47XLR2KmwLTbrIk{FE$dX*^104FYD$i4LP=VeDm;(T3 zUp(3RfNOUyz)Thjd~roR|Y zyCdig7iL!=s)b9ZGFeSuIMS5Y;9z%QE+!RfAppt8#Ue!d0C&>gLaO7!AU zq&-vXn=RAmc+viBqX&9`)qF7En4?7DY7Y-==+x>X^Bpx0thGDsO;3-y$);;`)J%jU zRinRX?Z;Mw1}0~t$)`cJVtocm0l|;JIx3uQsst@oF2Xa7-bh4sjZj6nSX<~t(+g_c zYjh_U=62!XrI4foI_7%nW#PZ1LPOH_~4WCFiu(j6eN2B!} zz0tWwd!aY_7?7PhA?l{t$B3NiDdNMtKVK4bBS0z5 zDZ3J(rM&NZN!tVZ7VLeOewWXZi}~PQzY89wH(t9MTot(5IMtSl_aO<_uI-3MrW!r; z<5RUAi|CTk_ko)N7iOF_cYz{TM9H&GKFxIL@+Vc0#p!|eFlYL&{&P_M#u|r6~5<}%@nGETF{t(H4rA(s;&lll1P?EHP93MoM~c~!N%Gv4HOY`Ba!xvt+`h-!`L+8&(e(exCju>f|q z7ht6t+^Dx~2UQ#kpUxSFWbovBTAAXN&P zQp$AJ;Ao6g4dTwhb$C0)Rj(JK3Wb(VUM%RJQ#!fDzuP>Gq4xxZ)veJ^XGQB3LT7x2 ztfYGKFi1?(V%pQAok{s*Z9w_tPPcv%c?95j)8K`U3Io#JZMOY;gSdAHpP${Vmh zITe&~Uo$fWlB@&lLgUTN8__OKgfRK~V-)1Og*fITGN*#_b#Vn{hRxCUg1o_%kowPp z{_SwKda}y>YuTW6%6@)=(bfe$FhW zbc-Pm0{XazqAP43_4_El9H*b7;boSp{;vDErDqSf91?j%)}2)kS@~ks3 z9D|iYYCX*DJ7%aD|9(a%Fn&07Ri9_wD9vt@XSxR)raY6;IgG<{>#FRm^{MGiInC-b z@cE>4rK_d>ty;4ia?i~J=}3bZ*NzUP}sUYoG%v`V#v|^lr%Gj0eFkATn=31_#XZ=Ki2sf=xnsFu`_0S$d;Xc=2?g(a!_N z(-;$8pgmOL2m%N(31uF_TY;Q?RM+DQCY1Ng56&p>nHN*accBu6rj$PnHpWr4D&@!hFQ_km}z&q(e`#{3XZ<;SdV{j%m{7JWMKL#iw;jg zf$LNoA1-oCqD(6K1ov}Gzdhtsw34sM1>4K>PaQ2L2xkrYDdKxtI)HSsmHP!>BcTp> zmWld8m-hpcm>#S8H$(G&5tLc^96QuIfD_6mkCkXFXBl;d>NU?rme5#$IK(hOfa9`l ze-IFmL5!BAGddmvR8|fIJPBDxK)??88z& zQJUo@hw%(-m~t3K=P-cI1q3QsXnk^mA#8(1h}~|TR#B?c9D1bzgg>m7QwBh|9U2D4 z(5RCIAmDvtqFhAktz$CjWu_%H;PC{5hS*{u(oy+#&&9PY!9>nYM3eLgJs%yw-3v8>F*vU!sc)_ z*iOz?_|3D8DYIRtYn`qwdMt?S59t>sD z$}K{r?MOH3FLc|Gf{QDsRdNpMrh5yMv#_R@{uY$=a7Mfibx3=xdrSfD60|5ldPaTU zr=*vwzIb0&-^mpaAJ4mqeX`Sd#p^@AAdnisW0TGk`%9d^Fhn&=Fr{dH@V^d^CFlEF z9kUpT>7`ueyUAh#6vB3y0lhG5^?on37bY)@V|-8o#=yRd)WkBc)qCKF@?B7X7)+3J z5;p7;VxJk7I#Mn4xH=R!^Vf(BQKrwJg$ z;L1D`WXC8cRGd=BM&d5B-4B43T=wQs5 z8kBJ7i#O-t&KXp=*z>2bXF1q&-0MtlAgM!u5s^2b5pxelTZA{DQ{lo-dhhzz$p8?K@!0%$^qj zJvIn{PPe?ADD-12d?x+fQKHL+pvP*v>$@N@YR~j%d-l!L?s%`W0M5hGO>>9HZ?S;( zs1JjBXbgxCKsg3f2B|*W{oK;;3>B&7Tq7@%wR-Bpa>BaP64tSqqSsQh!RrB!le^7% zhDm$WWxobEbENIF=l6r4dB3ns0IO@%m;?WxBv?l-{|dcCToj*VynN{L^76se^U`OK zHG;_j{xdAOc`C9*o6s|o&{@0=;DqaFgr;NwxikdR+V#1}DgzLnV@9=$b*0d7G%z=X zG2%Wr$SB_T7{S2%;gkZrn02Ex-%VcYMc6P!=|=5vUbCE~0D3v$wi@BUlMt+{9gj&x zQ^_TJhvBtYM4(3z8W7YarlfyfEwc=q`Z{PBcthXKss_OO#!$JG)LX~rk<18?+HpLc zPeH(Ih=9CELdXCcbnA~54~iB9-10Wq!B=@6s0G+oYc+6}{b^X544bl(BO0$=3vfJ? z1z^H*q21UC>tXcW+UQ)=ualNcH=>q$1-HMZCO2Ze04zZrfd=tySQ9e`d&20qd(P|X ziS77d(~3@nI$y_5Lc=3*!}J=YZ>M3y@xIEiIvyhaJz zP8Z4(X!mf;&CW-Y4Im0O4aahr5h!th{k&BYmpw?NVsDW|Z7|g7IjD(f%)`#->Y2HE zpXwA+-5rA+zgw_bINXS)M$}_eaM7M@ElgplgK8JLIRhJvw}7M2N5KTwQ5)O_<7-TZ zKPlKkfC3sL{HRjETqDH$vJqZYUJZF7P5fj=o*1;xT70w?Rf{+JZGnye2AVvv*jr-j z<;FI=EsPT(e#_>};S(wIv>0?~>K6aReM95ZEvJBQGpzcx8;L+$xEo=RD$6*T&sYp;ZJSRd% z^-`%PsAi+FNyhk6FO1ioX!2HAbT?u~AUsc^G1=|FV2ky0qn~*9+{OZ97MA4=9CR#`)OA?l5&d`5*HKk^o&ZBiIILSPCQYzBq#2@?6lq zU#pvmrP3kN3aT4Z7fEWRyxXy)E&&>6d$)jIn3A+th5A?n>Ec{72$wM>Y0sx7mboPD zCc*v!#9$`dkHv<4CfoZ@Nm?68S3q@vlC*h$36v^HYr*&Y65~Qi+S8#i|B^J!C{|sP zHY<|lQIa<0FOPv~KPpM9i#-$)62_~bQLVIB(Zy#>rS(-dF1(>y-WhN5XV`EVZ*pHc z8P#gcHTr7zkvayeSnUPzX#;{-9n{k>tD@AY1{9t3;J7i!c0eGi|AdqWK)c<3BkGNe z;-nVRB#ZO#-&TD`)as4ZV9TDU8?`4P0kYWZ!|D!vy&Ls9tpz;2Y$N=}4SgUJG&x&u z&qPyWwP?>|G!F-~;TjIgfh6CC4vt{!afFDemsZq+_%%M>tOwuUnChGALn^sJv)zyE zH*DY&g5_ft|y#mq$#j~*1K&Wy%G(|o4eC!Szp07h`>-q*h_~h6_ znHsmN+|Mn&XrHKYL&2K*9D7HW^@{nLt9M#8YxaG+NX@=a{w}%51o9M@L%Px?M<70B zXtzT1eo>RDc8Y!89XbSie2K<#N~bauq?G!R{*7z zS57?-*+-RAFNR-kO{GMnM%0JkN3~yp2&H)4)EPI;!%pe|hbwmm zr*-3UtvalVT7c~g;3t`CI-gbO4Q6F8XWc90_68x9!E6K2 z8DgNXt2HuwyQ)5RU)#KGx#=XYJk{mXAsZ}1IE5H zv=;_8!O;!zz zZ+a+zv2AF~AB@FGO4VTOZ-``hfU&pu%VXfYfxy_ui#-$q9phEds8-smXxNphw7$y5 zg+Hp6cgCB%5*se#O}>|kY!MIbccI2y;jxH$rh~x32y9Iuu!NCTioo{b*|COwdn2<@ zTZNB(&*(k)IR#>7#227^!yv z(O@J}67R^du^1K!Z@5q-G88flHWWEl6pDmKMI>@d9uk>DkqbnA7kiikM8>_RshbT% zN~#iIXyh?yym~FhI+WQyLgnc`Mm+Qps{=&-XADGU7;zK77vx?H5Xlp}_OM$Xh&N=C+LtM6Mcq~VXK5*yd(7fM#R)9M%p~jqDHxAK}cs^I$ zM-*4gb;gw^E-zPZS^=&cpW_K~c{K0^;#lrejDMZw<=@k)=buj)VN^5+M9=V5&5MyG z6lx3$M9+bgWB7p4L3Cph zM!x`yDkvsQ2};F;r{Rb7KnD?aaVUN4I<*Cfb~AA)I6+jf<3DW5k0Z7k$F*gWq4~Ya ztnc-#!-YoXfk`rC&AvF^DiOVoQ4As)4!nLR>qcqDn+)5#uwhF(ajv)O;Prc|<&Z&9 zKMf57L&$Wp;B~xjjF^jNAiOTU>^eWN6xe%QNEy@olQLGHpkC+2Swa&AQTwPOyfD0e zkM=hTVK;x$8WY?D8ISsaLrY+Dju}{u0(+LwB5uovC7WmHh14VZfpJ(4uK!RTPp{aX z>~tZ)JC8mODv4-yG<I5PiuYv=y=$8pEYymi)h8_uRf{y+c>MYa z6t#uMuf=P;(PKWE&&U7?nwkT#we=b@fIo-U^~#yCzw@_UKN3+b+0M-_eRj)DkyHWW+X}+8xNWI@N*g zf#7%~SP%!BOGx&v-{J98YL>|C{jzGc#n}5r(6BTj;eFZOFA8EZHwN)5wuK!(ktrd| zaud^6887?Qs)8}FdE#Y$$cOi30~_Dw#}7uA)O;x& znX5`i0(xP}tnLmSVGNjxvz8#V!<1RQgPK_8GONE56eYk^&9v<=uwkER+x}B#^HC_dcYNfr3E~sKEt*^3i;aAo2&UlkwV8dm+$tTlgR_YwkS=fpKHi|G4 z?VeR&1yggtLupToxS}d=Pm7V@JuR%ce$GY*Cch9TQFVNxLV*2_I;K_khjZEUf|-CZ z%A}wUhlc%JVT=tJi$ukBO%7E?6EbHG-H&n}vZyo#n2L{hYDN)S}cGUQX-wSd$SHe-=s#y-|*~4o2GO8}BJ(W@Q@E4U) z(XUliMs-s*Twga6;8ggqy#1VcRZYbB7~1E4VwfZ?d6# z2^B!&$9!PQF_AKbQZI5pxAfwDp-?Ijw5fuyE2Tz^Bs72Tv}&NTp0SIdvYsK2n7+Ye z^rtSX$Jl?4pPO+r{R}dv0{6Tq-5n(*@wCa5=8(ZD))Q3f#N8a?9N9**EyA?<}3}6|(^bO{?wg@r`;E_>|abk16a^QVgIUZV?PmEIO zgQXPeT%t69S++t2^uoYezaX6q=!Hplp~nlFeHvKnd&)9)!*q1xbM`)S?`ZQN7{z99 z(>bAM@HlzY{oF?kerhe@&_s7?R_jLVN!&=W0$?|};p6)M?f#D}j$##o96b4J) zi>b7}%Dl;Ys^y*WCU;`PWxUCc)3BDidw?!bO$8Aa$Tft0+~Y~C0kwJndj;(x@V}3I zrk9_nRxc^3O*Z{eGRS~|(%3Yrb|p3)5b_vcjL$%=`GpOP&3FN0u@)Ca#^T3CXza%* z&roRWr-Cv#(AXm#Xe^i<9+I7$KvZUDfw*M{9s7SmhkaBpLB}>EpH9%RgrpcA8!H5l z#V@(|81ffpbT&SAUO{{;ZdU}zF3bbS@=0?MvO_)r{mengVj3uTw(GSe{Ryx^awasi zeHX(bN~Xpe4g82W=_6tXAv+^R$TIA^iQfzIJO&}-DMWjOE{~9H1{o=Y?0o!12pRoa zRS4PE7#4!lT;@C7ddmwUJFg%_mNdSc7}>V$q;vA=c=z+vUIQLm3>;}OiMvbZE*sw; ziOQif*?jcMF`qK%*>&#cmX`Jf^ehpCuu1wEUP8Ll0@jjUPm{TT4XWAq$$=&pnaJuc z4>j_VBQhT_?J3Z_-z--E({824oIM3j(5pynHP^ap^QXWo#4_PI#>K_u<>Es1T=W?s zjYx7J$qYkm-hwQlQFK_4WX@`GZJa!x;$V^)L}|-#xVH_ctsIkl4YH6h$v40+7n5|H zaRN%#28<6GsANi93Jbd$KdyZ_1d_#3$#ZXx2iRnB8SXVqE9ev6!-7;ez!%o8_OywT zy?MRKEbuL?yM>0Hf$1WQ2KUVYMTzK5jAjtgaNx=hvTl@Sy~#Fx02`)|+-N6GX;vLv z`PFJUWDuz@LBqfhvYjlr67L%$=As!0S4uBC4$ud#{5H z;UH?WSN)@+>Hen4R)<#7CB7c_F?HQwi0igKNTdat%)5l)fst0U>#065b&18U3JI+g_1V2xyZq1752 z*|E^CwIeuh0Pgl@1$a3Lijzn>KT^KmC-ZG7K$ndXuZ4ysBgXr(5x-%TC^TPpEYh|2 zJO;Ne9d^z+i8-8e4i6gcm)zjZKTu#>fV^G~9a6)t*l*IG&I(&BCtU1b2453-&N!h)36svQuQ@yRxd)hGGZbLs1a-QF@nMKypv&^ zf)ACCtkvh|Tk#NIZ?#N7r9TU+A=4X}j9inofk}Ku_pmlFd3v=8)zd~KZO9f&BjK{bJvA5(}uY_adA>0qu*%HjDZaVSEbAi&WSMZQMwy(MUg*(@A(BdJc-YWB7Xsm`4>fEs=ex>$RCJgc@#x{$6p=;v)oib z^-ZydLQ2kf6*Q`q_A0vkk*T!4%EpC_pUMw`0-U<>CTC&8CA`TkM?s8Tv@TMI+bWwW z7e|gjg;B8$L298Jf{f@6nLxZYIu!xDGuLQC5)pECsXO!aE^J`}H#gGJpr(vcKVxqg zGOB{wFYnI`;$h!bK~bA_Onlgc=3LL3G^grS`3J5NJ`i9DCO#H>PVw=%uz_7+4PfRg zwH**pQMnhnzDs}`eq&CYGBB=M$=1xrYi?ua#{7vqpq%Xvt<`j{} zRFMC%i%2Ck3NS|UDijL52g67ze>q;E1});HkCQCFOyaj(z5h?vzRYjzm3GDSM9X)e!=_ugG%ULjbfm09!9~^DW zv|+vO_I3yNm$hr>gzZ(<5ev8^)RYEhqw~^73=J)b^Nz5Iy5laRsT9VFq_&%Vq@}kFep9aQJ z(c|Ip%Po409Zgc|cw82hqZtK`DS;?O_y9^sdnX8UiWfK@ejOJ4By~61+|X`bu@(_C z_}`NC5Hpx#kx2dRLY{G89tXpYeaYV`E+5S(1uhS#M)4fhjnWJ^$)B^aVT$;Sf?>?O zoHdG@dr@newut97YOQE4YGc*ZG*qua+66{++JrzTe_D%8F$G>ymzcUNKlU2Wn_w(#Ty*0Y6C=VD#Qp1j)^QmpTk|@d>^n^sJ0f{bGOetF1xb#UD44_^- z0?yr;gj0dwFpt>?@W?J8@S8{-@VFqjT<=1GAw_>sDu{RchwHKw929{0gM07ZOsL=o0)AgZqp0D^R&IvNN7 zQgooy8>$0Xn4E><)#z_QTMuWHa<#SYF=@92H3|@w(ch*LRj&TxeOZ4eS3p)g`zQ9v zPA?ujL4vk2i|gnjZ}ztZQUiEwl8Rz~iSwrq)Etd^*NQ;3IkdCO`}(%=s`j>=Wkf zKZyCako3Zc`FH#!Pzo{s27J$NZp>$Z3^D&PH0F<(<21ZXDa2L@g^r?!)3h5nOLl-V#s9GO}rSS(VmB; zAGC5u2a;;0Q1Bhbf$?fNK=1%*&$-aBpV`K#8lyeP#7eX$U~n~{BcI>%iFMNk9Uos5 zbcD%40b~xI5&_1?qVz%m#v29EI{@RQX@JqE^L!5TfEcH%5ts<=I1u8kLa%%V_yj^c zGWjAvh}iFV>zOkK0f+FcyWW@Kb*PiXWU_~Y#8QU9!C7E;E``sw&*%%{i z1{_6G_EiCSJU)+j7R}^7#m4qGqNe#phGo#nKX*U3w0FqpWTq4ayz=3rl}q?eaJ}gT zcI(v_^tfn4nD+gn(RC*mnS4LsGF(GhdA=5Q;sQiV2;ScZ4=7;cJL7%bpoSK1*;h_0s)6lYH52V3-o!B+2un5>{1vo^|WW-4tA8F z9?WP5K@F!^;bztio>R$-Tm%uAyxZfjVVZ*)9mN^@auzH6UQ(=pDZBYD?EW$d+rQvW zFou^@B1D~U#)1mi1pyKUoyi8N zwLa-N{#c^8y8Rm|u~55CjRWNP)f%w))SX2-kr}MRZnQq4sx9DFY=yPaXnbZIwp4+w ztzZzZ+GSw0aSeIjoB7!8RghK!6IV z22?2Rh-!3HRUM!sC}o<0v4%D}QQMiJm3QXRM!;6PQLVnK-hktSTM_I4w~4kVn~Azx z=>>H>I!sD;K+zRIQi=VllB=X#3inonku9o2)f4q+9NK|hO}4`JXDzVPICDm2TH-sc z&de6|VfY2F^=IeQes#FxW^GF{7H0H^2oc-vv>_$g=uSbWV5o&3LTh?z$XZQ|*jokVXSd6ue+rjZ=-t^}LdIK1J z4Rj{X-w6$?fNEQ5ljfv|T(Yaq)=hvvu*&WZf=j%~?+Zi(aK{wgiG8Kf_Iz(=#k($k z!RE&L3G{RpJJ#Yg-spc1j~}-zmmlU7da-R}B5~pt>+Y9a=Zzo!&-u<}nbqmKYK9q3 zj~BDnPv973F={Pd*VLo}*J;q+#<-gzegTpPYSIGxJwpl%)@t-0;(;BZBa$i9#H@Qz{gqif@Mvmc znHLYdvs!gDu*2K2VISCG|5-fnX(YYy;(^clOQ6)^fltEs{K73^@xWK0G5^H_2+vl% zc;KTVSssfA{?T6^Qt=RBp;Z3;L9vGdmS?;Q8r4dB6}?P=skFYz#)Xl4^2h7|r*6E- z!PsyaZ*t2v1(?@5JDLD7LP!s3-$^*{1G2z9IM-Lj`t)=ATx&aFEKtG;zzc?107=GA zjI=uSsnipx_=?8ZvxZoj?>ry5KO?B3#{6>0RN@hn(5Xk3? zXC^C2Xzfbox17~1O@S64|C6j{IW6e}tY*pVL9)K(qCx9hGT(Mryr3{3lVY!UxpeS~ zm&^}{YhW(PTLV*oYIjx4)3N6{t72lR$WPneNm9Q6qt@kN%^NTfJQ2#PuRmFhA=`&P8vCujgY<4+UzFd}721>N(eQaTY%k)B@}Is6vu9)zR+&Pmx|Xa_RtiB&;5F7Fmp#HK#^s_efzA<{PkH+%pn1Po&QzqwZt@Pjl;xkOF^4htOVm1-E$$P<6myxek zlJBelOAgVSZRheN;}K#?>N?}ff%ke_w~wOyvU;xg4D&|oa@Ij)c$?-&P*Erp7}h$7 z4S8;V(8`Alar_>~*5_ZAXhETYRClELKje2Wj2KG+WrT%lU9;IJvMRiz@1?5!c zU<B-@$5q%Tr-X;UpMOs+73OLaj)@Hn#w(*snhg)-!;@r_>y3PGF3sRaJDP zd4IOsS(urn$7tUds0N=|z|CVx_3`aSdn$s%x2N!0QjlKTgH7Pwo;r9uc?+uL;q$c3 z=VWIN+QHMq;iCkW&e+%|R1;EI{jkJ-oS333LZA z+|b&Lc}!wwRmfEhf{GlkwUO z=v~nlne)t)*MX%#Q49TIy+1++n$=-XW!MzCHrg16g+vf|L|s^^-HJ~(!wr{VU+!pb zzSD(^`kNd1`Ng$svd%9afiu}7T8fnHq->5*)-BbhIuN&DV zsltC$Yi-88{e)B@Kf=ZPvU__qy0?8+nA~ZJ)Yv|-x`TZW{aij11FX>aN|7G&l^2C6 zE>k|~E2aFfPxhBUsY=5q!uR~}3Zc?4g2wzS4KW>Bb*14=B3T}lhL7==hm>5SjOOtO z@H|TFp^$_zUImS6rM-%-DP$_Gud;FBW!3V|c$1f4!)3h5C8?~No}mt&nCgH{#Y4fZ zFfRRRwOle9_9vts0r7*;Fl2Nk8Wu1Bo3b*VXScGbc3Ig|Jj%*&9#O2$3ZE29$3BEo z3@sh|M?nRg(y@nHrDNViB-wPO#K$KIo}@es+j9!SJ|XnbN5hhWFukF&DhMMQ;w_HP zE>Hr7&$~rm$VSM<+eKgJ6e{|{CdD$ZOY_RSGHG!OyZ!}xms8jk_nabfyRb`AjsUaL zm|F8X9CuH|!mi^Ko^==T&qth2Vb|}+gIxd^N+^yz4 z#D@M;QOPty&j+>~Gb~d;c9Q$KrI!!AfXo%){<6{W#V)^f%}I`UeJY5yK=Xc6H&gWE zl$woGV@|1=wbf1%^xI{4IginJX5C{3@aW~`&?8rXL&9#vdE6@S3UN+&j&X5%dAYb_ z1-O{KFL53N<)?{v*^e-`J!^T{_Vnu6<`eE2ThA%*%NPxsn~)_G5)P}t@61Aj{Ge*T z4BE8kb(nY@5M6n--=85TsoL*N@XM|C%Zm?^(!a9{@gb`YFeO73)^EVBY`~n;H@|!! zPLPV%0iKn;%P|hwP!o`|!*S7G%(MG8KQkUz)|w~8%8?FXEOzD2HE`@ zGz?Op(K4%c5$_wf!SzAC^_<}|m-!H>$Bx(cDVY2Uu_`ZQ7jpHc9^#9N+l31z|8Jp9 zjf<*ryeTJWd9tDL$TDtdtSY;pENo=uH#9!{3;9|bAV6a-hd{%Ux!`@-T)vOylI$U6 z?M}U)36hzm#FH4Ak|>Ayyci*Z)UvjZf2Z#x$LcnjfsV9dpuxU<|O&&u28Vj zAIX$E#U~{ABM#l5QM(ym%gP%MUP#VUpl@ap`)!wXiO0_uIrc6}9BY z7^#hlS$vVY&NzHWwQ6Hxi@zlf=jRmgz8qUzN!8-vJYsZ8pDU$FZ(Dgy+HW^6{)V6v z0r8hn#(x>0jCfyG#^v6;SnPotp%mM^_~!yy0sJ%(o7h{5*s9ySSo&5e%l#55MF1b{ zF(9B9W=X;4LKBLnG!wJxLDf`dNx@wzC%K!if1bT99z#Z(&)|2K4!tpgL;YYO=;C~o zj7G}YvpdWOpZmppD+>^VffYuv;S&(nDhMm=KT8U(L(&T`DR{WQ1WGL_xCXxG7iI}d z3T}kP{FfBG2{gOvB?S)^$?{lI@L+#=41_w5M?1Jo?4bZt7_WjxwbEWiFCJhjt*|vN&Ulk&V8dm+$v(Y#@k<4^Rla%gD}|2*czm;Yu}B34AcHqA7Tc(L^WrxSj}vwk zxkPtBD6_SUU z+}FhQC-G06Tj zn-^~xxU9u#e>s=5OxRVP&eul`p<}RxRCgxo8`{Uz&L!J>5pJFY2Vh+B;P~ha_0N^U zX2(anoaF8|>j4&vZ$>@J88vb&t<36`G52#zFB$IY6-Qda%9V#yCdoU&ucdcb9x*DS zC1@|u$a;oca{307?!#Pm>k{f5>G~{Qxf+`H3mZ*Ad+eI;KzC0u=tHP6XYtDYZF|XO zPyUm{B=mve<*Bt{N=n(=k_^76G;Jzsr-7NgHO3p6qu zUh_(12?aL8TA*>-z#(hU;*1Qsv}bV`cs3AR`QnUMBNu6L#_QpiyEr3j=t~x6oH3C8 ztVJ0qxha>m5xbxVPYC*pFUq*!>dxE_*qafym2CAJ^RNM<8315=NZ5_B4%MaYne+{9 zzhs6%Eilu3GwVK|G3Jd9LIQGY61nfQBf65>8yVRkwc#w)_y^XF(%d&$(Dz}(G=nk< zi!;*YT&l4wJ3fDUN_&vU|2MsdmdXZNFd!RJlYvI)TKX@Ob_fV zJ=ty0PL9dOk7}(%J$vIv*vc`r@gp2qXf~dX`=7B9WUu&6km&%O0VL@g%r~$9a=r=% zsDRP^1EFC__wl~0`yW{KI>3wiM2hVKj_US{JXv6LfP_tnhe!|kyz45`cc!t@XG{6L zU#+;`Tl$GT>C}aPsr_u*(e5~zV`4YhwZ4YewI}Pr&Sb3??rb~Rjq12_Hm=zk>BA}_ zb?`iHs*2m-!)Dx2kWuTv9oX9z{abx%%4CT~HztluZFN?!-As9;Ym$9zuf@%1dwe5M zXER;=tnp;DpDS%*D{ay3&YPJBb8j=P*jBBU8$Wi%06&KJWj_`rek>WvmPMf4*NDBc zea*oWqz%>{-RtNgZ}y1-v88;8*kAG`>y@(d{)n$-0JN5>JEzN9_xZ;f)e>)@YLN;e z{{FU6@}7we*wQ|JBGaNR=^vZ<5dZ9NR?84GvWWB$LoN$=UtO>zau*&l&)iuQ4IUyR2IAF=$G)v~^-o zGo}^GcQn_21xPPk>AW7F)=71qe9JL}QkBjJ!uR|l0-@6R{?M3zr85E;RaZLyQuG`i zmCpZFtwj(@K!ERkVh;tN!FUxks+IOCx~7?_w7$y5g)97ZS*j8@-efB_T*jNcDs%I6 zoB{V{>+^92*9378BF;k~*??5VD5ecy7=>&_T)F~hba$ias2jB>A>vu=!Rb3An9zXj z#X7BpKI|~Iks{bSBtlevLpR)mhvp!Dgs^pTw%(peo$04yuYI_mOwy08R?@~wu7`&G z+*3SZF;;@gQi+uW1QDh*m&0z{uQ%<|+)lyLT&H+vaNVl&idd36k8%wy$?XbC;cN+i zW2z+A>0=mKI!2(_R~LoiCh^V}oHE=+q4PQ8aHj7{%5YCkrkSU^A5ThfHxDSmb$acV z-y+We->}PXFBn*U>$EME-d?gfuk=PBnPn{Cf;W zPK2QH`r{Q|-X@Ovh&-mpl-+(bF1yX}0rb5f?{uXuyXAEl_PAKS?Dnl_3RHIcH~5Rn zZt2&mD!bi0-Rg9@UX`|I4wyQOQ&e7_4EZOB$`g71fmr8F8q+T6Bt>G*SH;XV`l-T0n^?3Bu)abUSfAUv0N42 zXFtLW^;fI|JZ=mal=MKiFPWcW^)DEu!0O=?rXBMyX^EF+xS6ybg$-L;hOt_1VVa!+ zJ2lx57(jNly9}OMO-hEUC14C|@lCFJ>Jn46jnz_a(1bIgVIY(OxvYXSyl;$*vs}G( zd>+Y+0I8kOppb^I(}{opb2GD0lzvd0XEMM?C^jx{2KZ({76A+}>i;-wxQzO*-VAUD zNiUoM-svxaQW@Ym_?};iMaTgECN$=s0mebR>I`s0B+DZM9Qn&5Gdzxi4H|*TtLzYa zSSSOGMzzvjMdx~%O6#l4BmYIUyffb9_1JJ3Z?b{PpVTl)V3jkQ;=j#4P8RP=$7Q;{cq6<9*4$dmCGr6TFqs!By}n(2Gx zAx|Hahn(pzXA;uR5kc=4g%sq0&>I#S-~~2XUWBsKNfka83~JeT6=kX>Xvd-i=64#yIjyoyBwzbEQWs= zH19WyaB`)0U>c4h<7-MZma`H$LkXH!BTKX#PUF=-dJjpD^zYIkPzj(GPwZVfVf$QX zYM~YN&Qs=lUOa?Gy}e88;JL=s-le0g^eZR^pIpTbyr#jP3_7$JozZ3t2&_E!x)ZrZ zxz|Pb<>p?|+>^xX104FYRu-q^pyWS}pU@5hY@~SB_4tR;LX$356}NH89BeDn=yj~b zYwlCbPd$fqqmZ8(IP=3f%Rb|M6t|zn$OLW=C-Hha>qcpAo4Ml4v0<7k8b!nSGdJ;i zTaG6fZ5CZRx^!HUtG%w#?e%Nm0lH8VR60fbH`VgUq-fs^4FgMZQ?z*BSR@yYdg};_ zQf5ig>yFnt6-)$RHX#ABRgV;Jq<-g(UqTb6Lii1e^unS&W)asf+!R6W|I}c?vf(^) zVE&@O+5p0gOz%~M<;oQA%Q8LErjiL&dcTxVKT91CpxqW~Krc+$_n(FK!lYi%^90SP zOw#|Q)I@W6lm7SrTD~R(h{3qt!?9r>*K1>5t2gO?E|Ok2>A%Te0;Q7v8{vC?;X02? zDbk(lVDakS<|WXWf6^bL$EuV5XNqKbB>hkGmq)Py>w#hqg#pWW6*Q`q_9{BP&s17p zW#htBwY)Rlq>c@j@g|S&cNbu{jOp5*TBAp+(7M%i(1!D;0Mjp5E_ct;x#@uU#ym6X36S;(69>I z)*_j_H{we+i3d&WvFJNs4{z?pLLUMK7a!tI%oj87qbJFWHpy15<<-L@c`d4M3F6jI z6g#5jEyE-60U4IL0u+B>coZL&b~+_UJ$QmVmZiPx=pt|Sv%@3SF7=jdGa$e>bH^^w z=obUU**G&4}7VXHI!fxzlaUqn@Zg(?(^svhulcv)uv zEt2f*+_xB1wP?3>8l8sZ`zPoo;Hfix2TZ-6&>5c*ECEvwOFnlxbT>v)Yci4wIn`MC z?!n!>DNBw#f}D*Fqnm4QSG?s&> zW@tfk23exzFbq8PXxGjL0je2o@T1_lCPnuyY?y*Cqk$Ntu0pK!o@#ky zaJf%I!@v?6*0Yww;C*ANTsQ@=R_S%ep`EIX=d=N)MDvYLP`?AL(ZF&aRiqCMYyG9b z+5p0gO#e#}mMc@dFUwTMTBY|(3H3hecmVCTPy>2lu-3andtp*B=y`%BUj}P^2Q{(G zSnGw~$k&7bF&Ni-J~r&*diNi!^)X0#VXXCW{t_sKwcY^V^9$t#to6yzm_OEvfo0WL z>mx+6Jh0Yl{pC>%YrRVB;c59}p7APZR4eUOG^)x}T3=;x^NXtGo$)5m$A-&zlP55& zl|iiODa7K~N`tMhu9js6k9?KTa4y&?zT^+KzD4Lm!06&b+$jjQ=E|9;d_AcigtvZR zcvK%aW}&TKq!mS5KRY}E2cxaaLh-kUN3npmdXZWjZM|=J#M)@9L}5UPPl*_sJ>Cv9 z`b9ww+KOXRC4+GQAqH*bDI9BhZlkS_D~h&81>n|5#9Pn!rVfHf)o^pN^l|Qx&%~E? zde9=u##=8;gRT!647x@l>Uu#Q>T31egyvoa8SdHJj3)aYr%fM(on=!py27So&qV3wxX~Q_F9XFcx}O^|;6Xeh z+s}Yvmukhie<#e&Q>$W^)+@Pb0la^}eR6rpOH4+4U8ZTkFGof`!0k(+dA~SE0B)D4 zG3Qk1n&|%WHtGZF}wK&>j;mp^PG;5pxg@Hj~dx`+`VG> zR~ena@ZsRw_pxr2X17U;{tO$Yw5ZWFoDVD~zP%w?OT4YNqtk)2S=;JV*wn(4*YFj~ zOT{*PJo;N{>nP17gN7af4FgliK(Y{Syl>2se^|YBe}`6PPErGo`|`oK52c<5SfqhN z@27|_jB!6yMK-voc$*TeIuQ-Bsoki*&~3xcWUxjD&LQLC$8;;^*abC6;vW{ZCKnk) zFBc>dzzw4cmnd%Jssi4ZRpESZuJF``_ys$|UUbFQN~oWUWO-CV{S2k2(-nMPlp~K~l~6ws zdnhCtj8{RUT4}GMYo3@&>#Hn2yTo6YCEgitav?Tc#+y9y+6GMCaC?cU7SHvd0xFJl z>)n}!xv1T*O-1t&`t2=RfkUJ&G^Z<4^6eqE&JgDH=1@7aK8!FEo)tP=0x$a zLc;+nYQi3|$3$($)&}BBE}4qwHknz`{*K|1d0x#^Czu&X90>?aDA7pu8`lCy{CsyD z9vK&cmQ;xg2_VGOZ}1c)ce2h&j0NjAARj%jegmEn>oY?h>DF%`qaZcuUB3a1iS-*74zAyz zp1buMZ@?bq)NjPSCHH4fgd~v%7>I@xnm@)6i2$u5)Qo$Hc;+Lvm>yHVan!+C_<$N# z@q0mT!PIYXoW~xm%hzvw0@a!7H$I8KsD6Wft*ZKsEsb_>9*Q2kYBH5#JHSi80U`vj#=rQ;dJ-EieDht)72AQHfFGoKl<&57_)qG)9VCu=;Em zr8xFUqls7Kd92tnO*u{mG1`kbT>C0eS$R3m<58Qa9Oo(U%Pq&zV_{N~vms|p&e)71 zB^Kq?zK(LzgC&Tncv;R#+ok{xZ%=o+b9Jo8L5vR*E3M8`oC2Mvvu^N7c;2unu-s(pc4NbotutDO6Tamv&^ab4(7C4GucJbO zG76Y;vErOpRLdcQH{S*g14GD0vWj!?zA;WN8uiv;j80}s(#wt`^C`^ved=|9Y8Z6x z#ftF4g*orWa8i{bwCXz|+VN&KYR%UgQ;@K2Ov6sW?FhG9o$GYT0oCAgw-NQ=T4Scs z2LA-v-05y-4m=bT>&$mMlQ0JX@1;Ceqt_qlz#hY})i5Yb^744?5&haE)OgXSK$&LX zc*1%7%ygrLyA-FMh5d=a8TM)mJ=l;3HZsN%h=q1zr&tuU7RlnSQe9$#e6OGd0a7sP zcc+p99& z^XpTpf;@>>ryy7mwEy6^39kS8Dzkvoznia!0ZcF!@IYu-iWTs_YyszNs}<%2qe*JI zly00vGzGB5){TH(m^z;qg=(mQ(=gNx%A1=ypFTCQ%ymAu3Q7_n1{3Q)0UP#-_4l7T zpFWbVz(N(1+Xv+^TiWF>fl_roUHG0~?v3Y1Se?(ap)vnDAIxG@UFXvl$?~Z4Y5L1U zN*7bYfk65hv4_G0+IST-s+IOCx}t}vw7$x8`OVex&UlkIV#8&;$yFHa;iz7#!(^}C z>%qc}I6FmGVXM^oT!d4&-B1wJS?JU8GH^&}W4bX($*fd3K=IOv`7QF8?!5w2oN}M_ z6WAR)P{eDz(GLra2Ka3gD2lx$!XE_u8_X=G7gD1EBek)qzXvw>IkPyuYitTts}h?E zAjA~D@YJ7`*s(V*xmDUb#O(hO=eGwJzbNEcEP(kb>RV_5%+Ca6bqZh}T!sK1kRO|5 zbzmctm>Etn%zq1g^D(5P7)BT0oSv{hE{Hi(-q0igBVzqDo0=f=Ak4RmVnzpTY7#dn z7RFqZR~VB)gkLBj z@$0LB!piaMoyazIDn0yi@oQ4{1iQ{QotUZ@pm=B=kP?OR_1EG@w0*#cSsb_C@Q8Ll znt|9K0$Vr_9AF<S~RmaV-BaW~k3$9Vuj}11FG3^1fq!is8>1_lX3qI?Y}nE@jKp%$YCD5ZpktU-D+G}xnb%AZk}b4EVNpv=?{B^(sLnI!E?72}ro2=IFa?gucysQ72G z;W8?2XEu`&`0G}Hvt`ZJ`NcI`CtHwtS+jM`#F}Rfs9auSQXucL_D>murc_H?Ck8cR zT6qs|rTG&iy>OED|N2XyRFd}J;d_304ITurB<=q|WBy6nMI`x4I8nLpGWhjn__cKE z0I4NQI^Kz|pJNu;>0Lz#?c0NnYh!Vh;-?Y0;=w+NHQId>mGiW;8nw0~?F3xr4c4tb-=Kh>U{B&rUB6+%p-ar&+)!+;mdy#d)bk ztLJW7aToR|C#@LwHZ!d#i9EnS$kNH1y#xmvn)Q#UVeHAoGas?V^q92b#c^6O!}yx` zy&$(>(u#aCY&+%hX~kEgI@6lF|AW6Mtw_ICRa)`lMsGXRU^Ute&m(Kk9S{eNry5?) zG~>y3oqw91#5&z{e8n4-j?5q^KOOnkKxyUa$S))NC>{AN_~oV}nGqyuN!iq5|8CNgDG{kL znRc3}#e3F^-4_SA3&=)YU>A`Z}Gg8I=?=yOV z{liIC9`J*-7L;bYnS1>b>7!`HXdcFOg_D&hCdo=&)&k`*le5v})AZD9^#8N>C17$K z)%~&#%U;W}t;6@xmamn(l5b-KHjz(!8`~HGCfeEEUhNFCGwV4dEnvU_n;4b=K|m62 zNJzNve_~^E6Tkry0+?`xU?7k{xC04+@PF@Bch$VA?&_}Uo}FFA{yxy`bWc^ivtIq) ztE!qGYI%6ML@U&C4KxfirlOYkT-hAww)oYW1ZtU`*qZPSDhX&fgvRb+YHIn2GWUuT z6@2+W)I^_aOt)FY;K2Z;^cP{nMU;N=!k4!q>AB&{-*=ZlA^7r1(4QMNVu3HGpfPv& z5~udE;mcdBWI4c>H@eHimeHWum%PgL))D4{FVU#x+p9>RlBu-(mU-ltmCHNjP5u}g zF5*oth;P+I*pjMB6GOI?9C@d5}yb)-0^Rdw)MFkM3 z@uir$2O$c7=ApS3rRk-wm7JxoYO$VO{;J-!;?dtnrSiq2|J|aI1|EHBPYJ9VoFgGI z{3ERNsNPao)uvGn`%}v}T`VWYsbvZ7h91l*#;Z4Gl*FoWnz%JG6k>lJw;stXi&c$U z@#{yV;nyh?nK<@-KY$UY;MmdV6LD;ts(2WhT${*pzB7o#{O+{P!B6ooGWS6^gyH}{-D!__E01rzHhzLj1u zo4|wG4agUAIfFu~*C#4j7D$~yOFBsXNFcIwka{O_jzH=rd@@1mSnFeaI@OpAXu3xx z0vml4b|q~ECe{4V^m++RL6RFwmHaMB{U1Vw~IJSD8q(tqI?-kT9b^ zqp_zA^!JeT+(`7lxl5oB z68&B1&kZH9AkjaE#@vx;oWILPqQ7M&%K?f01`bZn{oFBmScF2NziJ&}E+iU_YQDXS z#GIK*%WqlG68x}K-YIW#95!6Uo1C45ME6E${lK8lE0-M#bUn+`u$VlDbqqR(^uds~Q!=_vqp`*_>3JV1dTYyG4ziOb*sO6=Yw+A5#edggfcYsFq^AmET&#?B+ zgV(}qR?NALs^p6~cP)BoV9r|^=Ik_l4#%wHNHer#fXvUZ49vwqVvzaJxJv|?ap=*J z3nypd%kZ)ZEhFC`nAf4@({ez|(4G}lz90=%Hc2o64AssC_wp6 z3?6y`<=cpJE+RAl<(nfwIl(S#*q@ijP=GSWI`m1lIH3GqRBbAZejk1!K$$)*DnR*M zw4){_be%Bejd?I-YPO%SazbrtOiS#kOl0{$Npbv+h%9=(XR+UBQMzt%a}j*`(`I*b zcMTk07NS)6Zr>s11UA&ZhO8MV#B7|l9~(~=%A7z>I?DWUptE$8`De&HLYaRJpG=gw zNBv`<*=Ak_*4!f;fqwoib|~!zX4(8$^N|v32AsLMnaWLeVP!P8*!0(!0WbZJ-huGA z&tn3Ulj1@%OTqTv>1-bi=zK)EOjj%Bb=WYin3cw147U(K=aF)WR-p4RG;9N%@wu`! zuHrdCXIm4#p(BCLr_k6v3{8Q~D08o9P=U^e2@dubbbf+G3?2+nN`EspTtw*?FX-Gt z(sP5(9d`*70-a}|KR0m10y;kv8gmDoaXK#>bgo;;asZvD+~r}*L($wzUL~}SFc;{I zMm67FMZ(KWrRBFQZh33Dyi?xfudv}F-sHR_&{+%B`hh!txLl4Xxb;3u!(#qCUB{g* z2Y%rSMH}Pm>V*(z%DGwekBrI8za8So1(;(?YT1-^> z2pnAsDjkhH5tX(nhlg3o1$gaHR9OOqqB7^-_&N-AT*r8XN+*~s_2=bG6e`V85q%ae zj!IvIYEG#1WAGE9()4Ljq0;Ao9RuJ~op1uBhjW0^)M`I5>7#BC_sd<}t=1>P7M>3h zQ4*V`2}vIizZAbBVh;5+iwn1-U{ic;iYF@qNZ)LBH+Sct0cjyd1qSyWk51r1Z4x;{ z?q^UX&k3c#f-`)T898lrP;de@>2UP*KxXN1^zFzyf}`(*PbM6#bU#L;Erw-)(LIt8 zsOaOcJ83gcVD#Es;xjpjwY1%n+iBt(%w%84y653hipgd!gK+`3zzk9F`uU7l;Pqe- z=r^!o6y~{FKED4MW7$Dh{1yaO6k9e4Hr@R#fw1y7D>;IK>yBN0)-Ih z|AGG8FcKacu=9ft{IL%LjWc-J2=uS4WH}(vKX;c$=G04G|SQ-|y=7~D)Y!J!OW^0T7 zX!BDn1NG1Z7Y^uXvyH++VZx(@^FlLQIhP4LG(GkU1K6BFJph3J+^i zAoD9RfanF8pGVwt5oJV=0-0M8$eduQHSEvJhbWMlqaFH0TO4HmG^#j(%n#rv0-5R4 zq5_%EfGbMe?wUI}3t+|;`w1?et%1u#L3L-N*$Sg7?h7B?9IJ)naJLoxbCJ9%%|xA- z(`Z>3D86Db;I~o25;^0ONs0{=L7Ts6b~ks&K+$HwB?M^<+LCg@%5r^pg1_(9wOxHiGwvr5eqD3O9RCc>`*iKS!v!B2p1gzXQ*CllKj zUM9x%^0H3FsiTKrUZXPg-Yz-Tp&2klNi zoh`wY^mjXe_oss~P@izJ(ye#44BZrVI@QKbcmOBUPSz{%sVUB&4aS>|b`?q!+Ik1= zCcIwhzoq+tqh`9z?}aJ?ohKQN7n%NcG^cLiMcUCC+ciR>J};*nbpt zSU*e|zvGR*dvFXm!_~r=b=VkO$QAwpS%-)4byw&yiWf_7dXw)cRK^zPcrO@5Wo#cq zP4xN7gzrEnY3{~D3@XU^7B=h>d&Jrk;vHdNnm5XdG8QX(k z@a}tta9vh*#`eFhWI1GP{}TsS@-mCUyq{S|XbJO_S3#qiZ?7VAvrMJsw`^Xxz+IPZ zOH}1e&clX_c$1TFo(cnsAfshBu6Q79g=?;6x^SQpuhl7oD0&llCkDM&ZvOAew~GZTaOk~Jy#RFqx3uBIUISX=iz zlAE>&-bf0buabf;L+6VZna+Y_Ahu#80y~x=IeGu(jmmVmcW$*z1k#|RB;W>n5)faF zu{3oREOHB$@OlF9l&l0Gwq{NKot2jS(+6)R{+^3tN=f`h<0Ylg>j7+%_plU+%GEBy zdFW`s=dNBY*7#N8nv3WndQ{@?&M5JhV1?A5mw!-+KMslN{XpdLw;f_|Nu`_hqXL5FC8qjFJpGm=|>PZ5l_hFi2udOyl#B6(Q zWe=1|bvrQe!k2o=P(G^c(H~i|iEB)zYW_0e1vYno0#(W_?kkdM{D|4z+=~XAX*2|9 zIn@8EehBqm@OC{o_uK)o;z&{I=}7Ypa?ugxVL-JShkq)E>VRGpF~g zihu;Vq}MeVcpng4dPTrhs901Ha3g#&D*}>&hqylAq)hsU6RHJzCUsi=X_} z0>jtP#2j=WRBTT+Thof=6S`ZeyYyv}eNc>SPu3z<4RWSTw)|^%Fzl zkIEj2+xgxb{`_*eu9CfXLBqi0HE543f`^{{(tt-__&m+n#ILT}7PF`@?;N_;bGk#L zG2^wQW=f#_ItyJMYOFH5*$i7js!;;1l|9L{>JjvN21l!oMcKGx%(N~QD$fBL-2%`E zdQxfGXHyfk+!ZQk#2SaiDF72xr@PZp^@oD($14q}H11TY4T}#@I?6H_>T5RteYsq5 zDqrvg!GJYsz5t)weZfh2*uaRfwOL3Z{(*?`Fy+DuQQ1QZQQ1>iA#$#em;5|kE*=a} z3h|o^g}~=o3Xy{is1Pq(wq(C0_}}e&hef<&YrK$V{P+B8#v>#EVET$E%Qq3Wt1Sp2 z#G4{swz!M~Ws5wf?)jeC*~Wh9$SKgUEr7u1b{*NooraYkj3!&tg*0RX(d1z|{=OsD zkR<0}<%moO>UD*&Cg@J2=X=J@8!dwJV1@D`*JWr3KF`t+=0&XhU^Lm9E~Ft>m!%;d zqfk{~xBGfBm2<~cmsd_rRe@Ehi9T0>-EC145A9UT&bzQ-mu2U^Qw8?tNP6xnus69& zpimXq8=yb8h~82K_AY45y$TGmxU#FjUSlQ8p$hEJ+~tu8gHaXOE36~5U^&XGpi#}Y zSCREzOr_g>ud<0sZSutR?#{r0fX2ZuVa zHTdHc^xUWeyRm$-_;MwPOSZ5^%;17iF?N(?@Gj~YA02UQ-2Dc#^Z4exGc)SPj8U7_ zWXN+^Bk9#-=VVrs8Eso@%g#=#EwhtpR+??Z@upOoMYOCzkVr@OY`W!Pr!q5Bo5G2h zl8kEwIIx;H>LPNZ((KhyrCEXxp#HqP(?xQJ22ZEyb3*Y-vm4M9sM73l_=zgb=+mOA zG}~NnI8~Ny$gC`D^s|!8*lrG^j~$wMe#FvxBYr5{G=9Nm=o*SH#Tln4cae&&Nwd4T zXAQQZ3phk}jl~1+1E11cT(wj&x5iIvuUS$9s)`{p`S(Jz!fPbZU)zH`kwX~783u>x z`TIszy+Q&V>GcW~Ah7g$g%=^$s9xa}@X4%KKuwS96B3Okl8rjOphpfuSmW4*v<*;? z{PhTjT~~pPxs`fQZ|<|~XtV_*?+&4z(vKG!mslsP2P zXT>7-26gLgeOv1Y=4ocaR;L;o&ny7wAsSb?k2IdLN%~8uO|D_~ zI}qx7C;VTS=q?Rt@bwZJ{Jh!S+}vQHQ7$l$Rp0rV_8z%x z{UMY64^3f6d^640I_!e|J~Z#PqB0cc9;rCrp~j3|u!m@dmCB{m7l}>AQ^u#|zjU?{ zmrb2Zp!t6DX?>!%_B^cNpi6?Jwt!oCnSwo$iuT*_Y=x#6#PQjFIQ|myu_d z&q$X5P}zOTj@X20qxNm|UKAt_YDetx_8=fDy_7(dbiW4oJ_FR2o?dzqY89oI#^95g zUNS<5IM)=|DNou6+aoTK7Wo{?PevZF9&$)LT?3OgocXE(Nok5?R)?9-nKjistjPjI z$%V_p3}pnncQTrR-Gj+OJ&O&4Lmp`{hlTYD3VQ}NOshwwX}HQx%|exMmiEzc;!2=s z@v0`MPDtR)H#zlZokoeV_1ZtUi*_tpMo2A4cTEmlh z5%Bj?8oP&@s0|}87UbvMeYpLBWlNUuKpeLgT~nQ|!ailpO-@ug72K$dYp`Il)tshp zm1l}KF{|Cnw4E8x#2#zzfdjOMW}5Zcop2WRmVh=wL%cB_w%Y+@KjEzHV5Yh!gj28^ z(OzikZXCdh_%Q65COiw^v}_!VczGO_oUoM|zK6rLVWABtc|&r32w%|phApzQ@%e}G zFoNMq8_(~CqBz=VjX%4oIz3YlgUdq%h~Z@Lb_bTPmDU6v^^MQ3zv7aOV)#Q>gw3mN zy8gNVcVxmSn+^D%IAC!Smi^7$Ncf~^C&2UN+gpQRQ?M<#L2v<26u%Zu4zI?4?+lyM zVW%}a0&i7@q7jHQ>nr(w6c76n2|M7K&$w3<#{!(Ihj5%6j+8eak0514uttXys#-X# z0EnhRCU+4vG?d;DY=LhE)42Pl`ZPR=5(I}hKxM32uXcd+g!bE0&2Ak85C)Z9O*lp! zWi>PjpSvw&cn{wzb!ZNt{pv1|TxG1eD+E!&x$Gc0I9z?E(t=a{P+vg9=)`sSw+&Al zpwp=4m}@5?M`kc2FpVw2#gI9Gv*0JYbs-LF4$h2kkS!o@>y_3{VIk09`^4bNjyP-@ z5)N?T1&$f|>b5b--#Zf6&)@EZU`{|sw@nIDMH+UDfyDr11ml?$UqnNK?f-voO- zA9huxyDDB>XcdEge!_vHku%Va6j&L3&71y;MZzAcrA|+0t656p@B14pBYN+Wz_^fhn#w}YekfOsb5BXT6xMW+w> zRl3*OM|Jwd!I7-#bPwVx!lk!eU14B@9^n^W5=pqQ|F^{v~Cxb zf8pQ=UXBaP0)+a8YOfs}$*1?IeAe2z0B6dugm({)OSc4l0SO8)H1B;_9~&Ig_97;+ z(C`ljmfx>k(saT{7@Z4 z;>3S%aKxXM7tUfpl#Qu{VE6lAed<=A5Fz*euzMX~cdfLeFz#LtCp(+R>&V>`0FD-*xg18^t@xqrk+9NA zV;sj7bYQ61O0_Xw?+QqmT2#M1JNkJD2>3)iptxgzWc6;Ld4N-iKS;am7P`P30Pi;3 z6Ll-oAnMn|I`#9Itf6+N1vo8S4NA#@;K?^$eo1i7Ip;j`DZ_DH?e5*Xx3nh5H-{6| z4($4BwsxKYf8zh}y)9Fn={n>dw$2zLR3Jl5$?T%HTW7o;LV>qIKE!4 z(&9zt15S^XT@S9}YIwTCT*9@~>6gs+U0xEy>9n#M-^auui|B7GTn zShNgOZ}1LpFIOIF5uB};e(OM6yM@+)E6@RrdCbE8>%fmJU9yBq*KzfCeFN(|Cg3Uv zS|-WsAjAtWw}|T^REZQU2|80y;3Hn3j}y(tX&orF>5NZNEA?u-GX!fbdfbTqs)Nj!gJ;gW~DRH2J?ycFG?;plS; z@B;!lusMw#;!a?utPc#18;?SZC#ku+(*m41c(lhCYYaN5=MnGX>jUG{_9~zsz^aGm zjQN-|xYVsCt;erxWc*449p0!1udCzijhK*lS3fFO!BpgGrGea1cH|mOjm&e{+AS2h zz7jYw&ynjJ!Nk0z)l}A6sOZr;(CAR91!(g5ROs$1EWX;<1f2DxD+=^Tv~09 zLjihgmPV!u#oAkjZiZKBFcA1bQUnXz6;;77l!>=C$J-L3JrWzE{7Zbv&8(}N|CFhE6Vhd{$NxEr6_ zqqL@82Ht1oIk6KKN z8HbIlg?#%eG7b-k>!^gsDAXM>FZ9iktFsYt2cy?1H0o@`S!$xscf{OUuHmUIoKM7t zkHRA#a&F<&4-#FxXCv-L(sQ4UIO{HfLT4j(p+C3q$#O@`bD%Nzvk`HFdf8_q-ex7s z;cUcdcX=cpoMUWwtyxESBACik_SQ}k|C~bqL`^8Kf<`spUPYdQ$W&T>%jSi5mCHNj zP2P?TA63Ac{A`R zQ01@=yGLR3WY`L^il#jaK;tytSPNgaoAoZvts5bPZNZ;2SgR9(+bXC%tu2=iB7KE1 zuk1VOgTQQP0)p~!ijTExl<_xm2WVSH!vYZe#lmI)Acp;50n^Tpl&hU;EBgnbVKBx#C{f?jEx&6~2jg_hYsw^uFF}usS%v3ba^j6cFn?$nvrE(*AA)&Q z+_xd7y|wQ_;lG&9Vn5>~ZM^33n8;*U?dr#4o|$<(CTE28tju%M&dRh< zXC9pS8ysoM!I=>igof!C_}J9Q!x-iHGqpV!B^?cO-qmM{s;6%eFI~hO(eo*gB(-$y zx1xhH6AYdD^KwBK$x?8B43Iuy7e6@jq+bI|=-|wg@e>`KNuL(g!I>A3)lAoSOgAUO zI%FP)Ba>1#c7upYF78(An23dS`BZaaf~H zr$HUqb}Y9MP4oGhHS&XjbW{l>No6ve_PIc7>BqH=Ap_~SwiAJulqH83j!l7Hk6a%9Nb4c6s*f0t+UaiTWiw&a)dYl2qdZ~xB=?GuD_r$fEZr*kYl=8s3 z85YMlMNryjx-vcmXIJ5=PAxj&iS&+Yki~Lc{frV#bhH&NL@3uaUEeI;r_CFDRaxscuZNC}T|B4^wv5}{0tOL>WKSQIj47423 z0rB^|@%LD$^zafY4`dxRG5sL1#Ybofb6vLI8k2>~5qK{nnS0Qs5J5CTub^G!8SbDa z`kZI@O1XknUg$w=xQG{8ym^LSAnCdD48L@jK%qRt&!9gyP>jcHa|Z&VI?^#GdtYkUl8UEc}9+?5r5jY!v&pN_fc?LA9`SvO@qrg;Je#<=aW>AN; z$(!>$#m2O9*yvIAg+|s#+lvT-_ zm8wLL&-RN#A;6=6MmH}Rt?*O`fI3@>v3d}qQU`psqs6D6*7op)3Pa9J9mI%7zQjTN zwl!_gLdEh;8+0sMX`~GvtECO%;W-n-m)gffz9NWI264Ma!rM8o||5+vTN716^FVmEKk zinnk^w``d&P!+xYwdH25gL=5h-6?y*0?p5$_DHal&uS_5RV3-~DYLt|KOB70AyO2D z_rDLEP4D$q+qK)Ybg3A3rkO8fN%LN<%j50(BL%GAu$A|Bd;lJB)K{f8*@ETr~0!Xuf2PbcutMdZ%18mEcWlUqxl2SZPps%cE~#xqXqh zj65tyz#^+vS<3{1q=zv$_c5Tf^sMD0QKKkpxeY#Za{Dr4Cr zBH^q)!5jcA5b|d%52uXf7@ZJMYmQ+(Cd5*0X?bKyX)iHby3)gzELhuCbj29GFTD9( zF#U2yFED*D*~{N&!^jnY*-%o2^gS6Hrsb2;H(Y$CW-m*)V(RqXglCn`=c~XDXFR?F zm6JBvMHVDS~x*V%FzrxKN2Xc+iJmXnmI#OG-tv-s6Xn5fJm zpAlng({Ow)8Mqb^lNOy>>{snKY6^bjzJ%)U;WSJhyC&@?jkCA%^hKp6LPO#ja&#XTYqo&}(hnuA}-Ji?UaJ+GsBU~nXBSN9AR60^%iHD4bb%_-MWIf>d$r++j!Vh5$uOMaW~t@~`o znoeuCmN<#I_;plk2FHiI*HJlf#O>0#lLtqA;&oJxq`KVAbN=8+9h8kfc5o!;xQ@z6 z)@5A6^Q6JC!*U&!6C2#7wff))PPmTBiBR8A?U{ok+5b8!C(e{%2`?TTm*(X*thvk!BOZdYdjyp5@a z0QgtJlFcoL9A!oQ0r-~ZbyV4i*8iPrWb{M1)mr+-%iz z=gGs@jKFe+YWe9b);P4pi)ye6ZqZ*&bw{~ANG+#shlXv-DSU2SPA#shsjTGa6L$Wq zsa|2>l83ugp^J6AG({Aa*o4n2KDjG~|q2ldh(+wOc51eHw70lx&8_DAe^Ob>EzdI#UF9$9Qe= zSI3HNrzZM*tk{y@rN<2(Gosoa^jp+vm+e81()K4W-ebj%L7wJ5R_r);2^2b3>?r8Z z&BXYoN_MQ+Y0#Ma^(DCVvFu~T)?3MPI9BX1cX`-0%+WqY+A_Y{Izr144e{Al zqD|vus~20w=`!`lCtI!OCtF37MAu+!%yA8d_(i;*U8PQtp@4npr&^8VI@L-vYCY5H z{IoNzQYbP{w0a$mFy%z6X!I0q>sMdcRK>&4QlLBg;wM^t64jkfwE7f&q7$v?)1o@j>LNOWsXK%J zgcCd9!sD>*bh6bsxlXp?9rW{rt4oqj^WfbN!?~S+1B}4kxpb$me)f^&$f~so?Bd=s z@eMYue+$)R{*JKvhS}ZRiwA#%6&H!+_KXu9#C5N>=G$LLT1rSidrE&!PBs3L3GKg3 zF3OW$(!AhjU^Eq5EdL>RLHNL5K=W>kD0SFQKjs1igGtQDaB1PR(xs&+=Vpr;0 zjDLqNS>dYmE+-$Yg62!+pUZrygpqRcQGyZHevB$bbLyZ@KH8A&EBErndZcUW1f&GQ zq+J*s{3oEe^b?TIN6n%WkS>Bx<_SoN4mmyv>Evt<3@4n3)FV1!zh6aJN}mqFW&RV9 zHqePkH1X0k8kD%i``Cls&DK-lV3P4rS|}M@o*yvVyWGR}EbxJh3K#A)B7|}YqZ@=W zm=lwp%!a`iscBP(h5ZV|*p3Yoh@tcm7dHJoG3k!p6O)9}!pS(TurjeFxV(vXqqT$a zO5?N+o~QY;o!+e4kHR&#eFs7}JgM);~~ zkGhGC!S}+LUFC{HrPN!{FmRu2H0c~Be6D;1*8}mZ+wmNxbf&_UtR=HGZc#9nISt!r z4aa^0#2#>0vPEmjX%KALBsO^{zA7fF3r^=g;pqaX{1%ZQp6nDeIf%ZB^f$W02+ppd zi;F;gn`-00u1dWNl{lTL3SDFrfP3Br9=a9IG+UiEUJcOh&fsS#N2xYux*egpq6fH( zc=uEl&J^pmyP*HG2^SByr{K526_;+i=8WsFxDj5MfO|cID<^3(h{g$~(P(zyE`n;O zG6rS=U(>xza8ok9hE@F|U^AD~>gMqc`J%F}-BmC@piGz;Uf5J^s~d{Z_{J-3I0~%M z4jb)ir@AY&9D5eW$qdJhzht`fT8rj;D1tJ%R|-W)H9354H@Sb=*R_Esp{)$j>ps?u z>Z+vO8Fi@soOkwq3->+5uBv0KRFE=k?wL}um7WjV+WKYJ^0WWeY|<@eQ#?TlpMI$R zoOkxga(Q$q3{M0CuF4_68HD`%faJE%iScGuP$ZBQ~SUn(k(FY zM1YlpGz)JDuI;uvrn?^M{e9|`0G>LY5_;Z8uZOP0C0u&}5 zIG8b-e$wX;Idees0Byy{mc@IojM&4qResC-_YcceQsuwDPnwY)GU0Q(|Nb-Ge@iC9 zY&}@faznS0qI=#0Mui+Tf15bDF5NGkM;!3e3WR@e2tUTyeXw1Dl2ywx(%Y&}6lI2hybh*1c@~yKkv5wHPR99XFjcUHViYx?T zDlNZd^TOTb@=ke^yRhLR-XvGC52G;GFBtWIRxb4lp?L*~-6M8Tnu821MRPnRR#hIv z0bmVr)33n0&7nMqCol7r3Gv@p%Z2Vk$@-QHebAy7M!C?Jvqc;-({8ZTSA1TYBrPo{WNI5RxAbY>RPtkYpy{&nB@gcfkH9WmVNdm<9{yW$VB#w# zfXyaHWZ^=J09*=EHbV1m%N|ujVife8QlPPvf|LY>sGW=~ks>*f-*Pkck~myF2BdNO z-r?GDBI#$z{n6U3Q)%rCJA3Dj+A-an=t6nn8N#B^i00+6y?1T}+$>+6*gLnzG`6e) zlmtSg91V|qFi==}0m@CtHYz}QGJG-%P{{b>f|GS7g-Hb_J)#g3;UU{bigE;dXHTcu$bwDz-PWJ_E!vMp$Ir^g^|4r&NzSU{E>GtnU=v19!N)Z3D> z$al}yOUvb*N>;oG8U|L8#U#~t;B#f7TxjA~r{?4UGd)|ghJ&*><6hIFLX0`0CvC2? z07NP+ceh|k-a?GIW6<}+2{}-PuvHzeKt%$4Ym>X_u@WZq`z-ADAX3TwZv>I4a>wU( zxv#|}l};`bvaO9mLViCD-h+N!$R49m8IHSrN1+fU^juy`HI?CLQ4@X6aQqxPNz(=o zF(}vl6KvSUb?-YFj@8S6^xPSaL-B1HDsexYB7s5~j#bc~Tc~fza2ySdxo0>q@GLvS zae$R9hYZJZcX?#Sjx>SoXC0ws0#jZEjcUHVip*s&m6qSKdEtt3d8fR|rPy#0Z*m0A zX;Bn6p+Y!0jf;pU^({u__HwDD)dgwDJB`f4b1dUYnK%+1Rh)S^ zIPMQJ4?E*b!--j$hMi_+0T~4=4?VMRa&~56r!|vsL0Tq38@ZV|cqxu3C36ssmRPRW z7}`YcVIUGmsNIG$AYoUl#7ce-@ytbR5j|>y@|98MAi?;kKQFhSG6x*e(VcPe4a)bT zI#a^n1Ney&2J~rBB@8y#J5Kq64Vn3ZPCwHH2ENxBp0%V3mexDmN8uN2Zu}z3&NZ5S z2jXk*g#Sy+yY>G5^8rZthuwO%wo!$gmUg1hoqvS{lzk#(vlRW+iL&6hY4; z;ihIe)BoM%f&`V*T#CbP-+zVX-Bt{S#O{$2`*wlGQj!A+N>F}Te}YKkck|)+MJp|hZLhR+x#66SbA>Y(B;52$_*R|pUm6rl?&8=C5_v|7!?Y9 zxgb3^)W2>PasHda@h0qI$rLP`$P=gJSqp1D2vaic3c^xliqGvbJw&IH3Dx%dLPBlP zz&&W!h3YX11?^wrI|>EDq37{hODSmo3~Hj!(EdB2lQd265QB2PZ^MRNT<^XE?LUB| z=Z5w_<1T?h(Eg{OKes@gN2F}?!h_J5JG75+W7*LD$E{>JK>HuY!Id2P(K7UY>j*8; zqw*?fRP*gsB#6&cT7Jvsg=H&B<(={-OR(W0-sFZ(s|$w!Oa^=4M1Y{(fh2tgPA!1a zt!S|@I|A8kI7tAH=xEHwvpc?wU&Fa-P}R}eU4>NtWTnnh`}#)5{YSAcZJXnA{Ejck zk1Us2YLnwSOT!{!TaIM%(O7?^lelbjk4E2qdw6r3EMxGPS6qlYB1OV{fR6Oe>hx;p z%A*HI@6wSXqRe}v*>!^>aBYH777%7$ibn@W@v2^bQ-IW!qvWhK-CaRn@@89uBUaC+ z*euf{tS9V+Cg8(>Mz_c(Lf_N`jPp<_6R-y%Ds#$V8;+M4nbYfYW==cViPMfXZ~7Wk zA>X{|>n!?b>XB}u%9W@^+w(!wB}5g0fF2_(Kl>y^9*3u^l#OQakIkv28UIH~lf_ ze(8DBbCGS7H+?jGGV`Wn@p0nRthoRO7>5LRVWOPSkRDNpjNVU~)k3t8KXV$W%qg7b z72XEtI>x(NlCr4TuQTs;DN^s|y%G!2BEiZ@f8qEfA%Ja+P7uIgQmRj6!{AEP^%{pHr$|fKJjh!9xtn_5K4k?BaU&os{a2ko4Rs)t|UapioNnhtQu}5YK~EmQwvS zH0GXC#gMY>ls!_l=1QreQO&nkk;zl0((+ptH=nk$RNg6X zaxykt#GBm2QmQJG+PiqjomCwwE35kGa`~kaj~7@PPR*)Xf8?H3z0NWQkEz9lxT7(v znk;0F?mCj3l~^4e9LYvv)rqvcX~x#z2+U5b_J!i-4vym9#OhE1z0IFkefi*s)f1~W zVR{7j1i{cWd>+u~7XL&jjtcH^HY#Nr_8>$hRylaXQ4=Gvns-ZTC(Myq4XvrwkD?O! zrdB_0(Lf`$+Pft+_rQ7Pf^A9dghqDt?=0hSnZ)AkYR|?_7;$u$Zq}Am0E{CYRCnki zqX4$i^Q+lgQahn7!TQKE(-N%O$juDv*KkBB8P;gDi5XU#$UO{1f~~b1F_I_f|6l=k zewcXXBDRPgwI#J4Wmpr8kNWd+3o66P5pg}@EuLXrdH}G5GOWw+6J=QG)1u0-o-ti% zKh-J4dUDpLRBW-IIo9*F94k?P|2KknSk>WlCTaJ_;CX-vw1 z_eeuTB7OB<%bx*XyKQC$HU(6IRt4_yYz530k>Mo1!3^dO);(WBq&Xi8P`Ncu z^)Dc&FZldSMkw%kFp2J$vtbnGx57tXiVYJ!s#FY@2mMTR9~18#-WIDMUVs^lLkL`W z1M$1dWt7T{z8x9{zNBVG@wqZcE+O%&wMpbMtFpCWcrTY-#BZU&dl;t5j{c>fKX=M| z0^JI3B;H021}<7v9!H5gxC}01oegHHdqUWh)ClMa-Qqe`*%iVs#+$8H*q(u{$aq<5 zSf^+g-WW(%~A3tf6(y4?EA1RdwJ(O1Y> ze1UY=gBpKl@#vm~KzztB-JIETy(g`8$(MxkTFu>XHoCwgr{#}%vZ$A8c7Qq|&@blGHW0#@xn0igT{};9!V=G2V{704{xhPVc5?>v6xPb;8 z<-|AGw;bcEW>Orv1;M$V6h9?v(=oPY&5ECumKE0rZ>Gin7sr&67LUeDYZ-lEXp_8$ zrATbH_96@dC?#;H07t(~TyqhfkruxrN{c60A@%3wA5>bL!{qvWR6H$y$`G)G(&DG$ zCrXRcr$v<(e*~)Wj+thCc4xEUlpY_+lOB&-?q{0(mV`8U+;4WOb_5W`c6B0jNTaXn z8pvNwK3MY4t~$-Ob%S@U(g?m-KDUbB`)TX7~0X?S6~NQkh{) zk)X>?=^LSWx3!+i?nch_9!#cDjCLJ0ws6z#jsEhoHV?c!JlSzbhoDz4WW7%_dfH3O zmE6@|=KVqW%yS7olvbzIEF`$L+O^0M3Q(|QXAm_D$5^JJtiAgQ6iLrwuywe;GB zw;}(icHw>S$*f)A6I)!vaGZtaq*{g^DG4`q0d^}VMUY(nT84FTEkhK%Bos3wzrsxE zJ~n_{vvMYYgwV$VoNEQg?_mT3#|Kl@@Od_j!hBcY)90{Z0-uz!;rec|RyF*vTt=y+ z)c2ub;0w(01ZE5hbgH(h^S&>X9U;~l6~XmkKB#6pEi2X>J`c~#JCghAw+1Udh=81M1cg+O3RL>(vgBp3r`Ks@bhiAX6*5n#6HH zawp+)w-q!edpTW!W2st=N~gLD1W_4l?y{C4q4;HZM~0J7ShD`0bi46TSY@z>LBlqK z#piZ|ZEizu&7a=#stoJ+^s0;lMX9kb8?)N?)>>yLCo zSC95ur$+6n-elY5bE5vh(a5c6gs+Ug=1pHeIGPU-nWst-QM>7M zWpKnU2c6b7k2*=!SEt*9Be_JKUK{JQn(;L4J}lC1^#a%PI|s*yqf+O8K13&daI^AP z437H!g_Rc~)n(p#^WaDwl#PF2a3rsb=dIrGw1BMFjheBiX6b9pH+YAi9UMDW^_n^# zm7{gLsQfnvM=+{>J473O+JJ4fg56WqaZ$xL(*!^VAv1)%#8#kj*wYSM6DOL0 z$Pn7o24HGPfLd^G(M*JeRRBMWYW!7go_Y7={$flVwTZuEcKbMsoITj66ztjz1;gid z1shWA~*iRc316 z$KQ!8!tVWX-Kbbq|#t^Xo24VkP>(~<}$+wlOd@5P?W^C9cS+?)&`}ic1 zo_pWNr`;t`Xy3;tpg*@*&$9313(%PRz7MPeD0|<>N33Ky?EARiT^^Zfd#and*E&K= zVo`Y&G^+XbDsqPhQ)&4v^Cn9UPLDS{oVxNRzeS-G@g@s%Qw3w`!W<%#?_uT2mx{p2 zHdaH!ZcZs$fGXQS6)D9wJVFPx?}OLCXr&GMzK`+z`#$38)?E8P;+L)aK+Zu~`tAcc z&!Py%K9I}#K9G2HuB7mg=4dE+7{?oEqkSQ9tH%D2M_Y#K;*;Y2A&18u)BcdS+xYCn zP1*ZI;-8rNMUbn27wG#%Hs{$d61QsIH*$8`zL7Md%>5(R;22Z(k3{3A^_ISW#HKMG z7DujwCWHqtn4t2^BgC@jEaIYzXd`;mv5K#b_Kzf3a}E3R@-r7fxSmv+sLyM~_m8wu zK_K$3V${eR{BbgW1L4*C=EpnDovbtxuy0g)2g*zHe+-K^r5o8&T zm4yfN4V#T$h{BZ>u6(XZQU4;_KJGTV8}J2E#3Nam{XT79#tAu@Z|r0^&MGu16}<>Q z=g-JHX1vS9{O2a$Wd(PNm|gaUybhXo3%yhoedIXrk$Xd4RiLqylKcdf=rAm(*@iTr_|*hf zcQl%vEy0x(&b2Y8I30}51{2|A1@eA%!^w3Cczna+vV57Qy#W#9y6+Gec&hL%HBVy9+tZ$`FmqqLT+R8o6?6&zPLg zu_%j&kd&65A%v8wrTE;grQ=ujUrIb1XC0HC_soBl$(0sTJ$S4#pVsjb=Qm_)U;!57 zy{hNQgJZxZ2jgOfVdHHf2RK58;URb30eXx=r8$2K)2&^o`BHzVn})0}U0mq4L3=U+m9ZpzJR_8A76!QYb!m) zm-C`C5Lu3N*dA*_Z~Y3{#Y&LodM-N4KXASt>AmO- z+Ay+q$6LnZqC;`kPF)v7nHQZwW7gE%IccdmZRBP~ZVQem zB_kJ&mev7!M$RU34+9}fC*Spboc9QwT`h2{wZt@&B0)~?~B;}SP z{oId6svk$)B1#YFi7A$A;5Zs^bBA!C)9} z(rHz8h8wv*w7kchp>0!{YO-u2)T}$UbXJ;Lgf6nf73#lGF zRyjNCc>QvA)+TipgqC%e@+xRl^X*k+c8;mE{FVhwA1{}8%A0%y z8!qBaj>DYYcyoHD+kx7z3SVby>AQ?~8O2{JmttCCQzq{pNz@)Qq0$y)S}EG%F`24N z9$%YlD=s~gm-mt;07tS@dGL}om-j1_o$uzn|F#I;*qqmUNt46SIqJhMX@XXabl#G~ zfF6lFaZbA^Qk>4~x#tK6o%50=cr`}Jz62>v0ni|~V8Np&^s+B$g4V1Vy>rttdivna zl-{AhuC$b1G~UFNo=x%|mLgHL+5YV*oK7LK$)Ds~b5jTID`-QGuTqCBAF-A# zt&(0~?(sFObN@Im3KnDlvY?!v;PWdPsleyKB=+9RhEbT~YF+y-Y?#)yO2sfxUbKn5 z&y~w5l`?q%8V1IsCid{TvPdqX+=)F~BZd!iN$h=+MxQpLS+F04YkyoY;Niqx35mU5 zS(L>?NJ>k8E`*e-rTE;grSqTIvyMs6YUSUIckr5YQayOA5_{J1`X%{=3gv(T7(Vh`6{WheG_TFG)q?2Wt2!-g`@ zvWZZJQR@gT!JYCdXjJpxvDY@%)>>{a`*lY5 zUzba_(wX;>z&++er8CI7Qgp^+N>%ASzCzd5U3z-&3AVj*JqK74Dv~3?hv11d#rGAI zpKprqYZl=fDZZ`#!{>0?l3*tMeum>p*~1r&IWgg9(*qCNk$79}Z8%*X z4QTb%QNr)b#5orc8VSD#ql90AT~dEu9z!MkIPj@^?&1l*qt*gTDB*WBexigQeOgor zzw@WV*3NLpI54~Ibh_s0*;zl?a6eOjw;Is6>~d*lyP0v%bY| zgsvwG_jL3Jax=?t?G2#&8+-7agL?SJy&`+Urs#7}Pb3u2C!iEdDv~Tb!|ZPE4+oqq zl(N~Y5=VN*@ZvJ%cCRM46{HhVV)~(-+GBx^iJvf0US;xDrjSxZ>9X1Ha%kRdfn>=B zUQCS{$C_rEMJki>|C0EZ{W@dqSbtgj`}4rsBk+>;1b>ps(aawZBU9gE{Ciq|`M0Zl z{<%aZO3zag)d^m&whdWA(aWF`)kmk#QhQ&vWXXO@@IMZ6MDdb3FgAfQ>2nMgZUT}^ zPg}nZ`ABK&zk*L@+L}#$aqjxqbkdV{srJZ9BvwbTQ#orww4OhKz3y5JZi3G4WGpJ2l%%ytFjd=widAV=vM zt^(&JlZ_bAWVO}qD20>0sYz{Yl3KAoFM7Mh@<_S#!ee}p}i*#-=HJ3E3>B{WT82l_~!(qjBxED17^u!6n zZRok)sm|1A0T}=y=;UG;3iKU4fB|&JHb=h-Vc2wb@i5UNjzZozG!CajKp*XyaJ)KM z6~`Gjn(?9lMkN;I;!xJxx>cas;t>zkSgCIG$84 z7gQmOb+p8VOM()tp4qCc&q8y>>13-OTH!rc%>7;j2+;g6F;T_I0cvW==flD9;2vix z?Kb#Eyv7>bdgSD!bF?_bl~L2&56W*DOP^J)ekk|%bYf|Gpoq`y?(e*9UTk6H*?K9Y zF?-6=7>`k?lAtg6#DGB;K zlAgOH=nL)=C{z;k_t2jk;?2=Aw%7j~(3pEk5Mo+omjwNtl`MynpijEXBNK$8lAw=U zM`&3kE3bk^HQ!!E7XL7nmfx~@VQ78&>{G~_ti*{P0Cydh?1r8Ob$nSo_sbvlHrW#D=lxGrX5NdAef_h~vthYy?naQvfHpXF*HrwvNO*Zgz5qfm7%Z)Pn5EJ}j88p*@ zW6IS5s*E7}IT9Lnb6gRyuj~ias1*D02rpE56o-8^Fi$U!szllUW@~3K(H!rB=3zY> zLLQBvx4uXwd~?)D$#<=VQWv5meG8=?V^IU6Q0me$2;p)0QL#zmHN~p(!l;|N+%irV zmlfAdt&jVKx+%%#xOi$~R`Hblg?U^8G8Aw_y@F~ayMjtKYAvHWKdp=^g(9<->J}Vf zN-b41dRoEi=b_tF#lz6ZW6)gjL5wpf8@Wy-TpmR{bP=mjOZDTZmMX!BYuKNcd$~xW zAUp@BPkF^_scuJgr&_9K;wP%5qECyemTJp%)$KU+>>G-!eLW4`xS<%v?|Wv#G9aG& zI{Jo9!mmK#%2Y0&Vp7z#OzWW^%iK} zE#gu|Ba!302h#7t_r9q>V<{CV32ImS3uK8D{2)$3H*P2fRpd+Ph&QU>B!LhqM`H&3 zBcQPKf|D;I+o<5=>+s1eI3X7k7n&G16r(qeBNlZGdXFfC3cMIQkzNUcnfwJN2VYxl zsJoT8`_rB=NBAAqWiCgUxthn=V&S+q!P;*zI)Sx=DJA)DHjKjTR&e4kv0)18lvZIl zJTIjri8uDjmC^zNpzntM+?KU``NlG!AA-i*GoZN0Dmw%Eb}Ly98PGSo%Oi8mL>ZhnSx0CI?vz(S zqndB8B6FQgrRBFQF#ch=yi?xf->~5#-b7qL+`Ed_vW-bEFxq}wE^UOac&Y}QQJY|ZC7sK!sazG@3+}D=l!yIhC3E$Y0(u?^XEn<)su!7Tkjax2uDc|`UI5LztrjdvusW&53TkDJ_M}A^wtiqEE0+c+8e&6PESYRj4Wlr-)vE8y*f2#-N{=wc>}T3*q#f2L#s11hcX|xAMT(6x zUEDSk?R%W4?y63N4cq>~d}*-%ESGaC!SGXP7#Kw+vLazeH9l8n$VDc8b@DdYWSL1n zGdo+Oh6{5^i~WeG@vvNl3jaVbBzIbDcs7R)w3{u7A{d+M*@T}sbsv9Zx)3~wRnk8i z8n#IvpWCH>Qik-2awdFRn}vjb1QFxG4_){kqfjY<@B6Bt0%_2jd9B7&O5lq^i~GAN z>Sl{}c!)u{^T%PsF7ABaNeMKO^xP?d+uS8kC?zlr{kaACJeXxEfu}=b?kNEbIm=E7 zRIOw=qy$2DdE`q8j9Eu$2}zY#L8F>)uOh*Jrqc3THZS~Dxx7=}%am`%mf39^Ko@Ssj}HLl}~)q^j;j9fwjHBy+yyfgx2 zmYz$v4S7eogjx7x<`R?xh!YA&apxypT2fY_M>1l1+=AUn#{t1b{;a}r*9xY><)dO> zIUINg=eP>&vn}Hdn*TH2WxnhVHl$p>EOX6>tDObrp#=Y*$%qC14<-@uayE>@JXdSY zmtw=T)>Nv8F>F5*5l6&{2s*nXQqs@@IM3zFIlQ}ECMneU?a(mrBsJ%N&y|sK>4;w) zqLa!j%JzH1tGT2X-a-RUo8>Ghj6#_IQqZ0|y>K|C7kbHs<0~!sr0itES1sK2AWez& zK|xxoSn;`CtcRI&GQrwfC?wb~(9k`o*9Ge_3Y9webKg-Y*arQN*ZNGQ4qi-6^m#YI zp+~3df`=HC13nlVc5%S_PU_%vBt3WPV6(df3Z)Jk>fjO3n0x8~Bh0c> z2d7xca!4JV=q``UFp$9DF%sf6UmaSwXU;)CYKO)jo1%GH;xZf# z3oPgxHktkuc##~#f0*43xQdu~Bw=lBm%`jqz*}Pua#vTgKq>}U|6VMa zrZ_c$0kz*DQ{)g9LV-Rqg)dADP(6W=bWr{KKw;^i`r*d_+Xz%Y9zL0%Iw^aMrze|E zM3pMg?-7NN*S|A`g*h`nl)mP=W(V$gxlWV~4_{ZgPU#ZOU`a19<2)59bTiJ()e?c` z&mL%6ugByBlTTuF0+Y+Y%MZFS>~vcVI&@juF!7x|VGMs18%Qp1Xk)lqVqJg@(-KQ* z7)D^Ji21$)*xZ7o=LT%HyGx)DU~@C{R~le5293D`Ht4;|25fGylH~x{T!Vuv*#*%= zc%^lOxd0n9Dz89U!NBKH6Am!2gl3pZ%Ws)Cc~QB%Q{H3_8!qBaRtewO4q#G}piFca zzya|yUflIM3o$kQu%{KH(6Dxi)H3*rH~CkVCR1Who3~YGU0KJPxOlYv!gujVYW`}V z(apa^F^R&IP}-%axd$N%Q{r~R6A#lX`id5lE6EH$XB>+a5r&&N_sYR+QsuO3O zd1e||qz&D~iT(qJl!6mQ!%Z}Go6J2dMBzl|qVQ-Lw^D?)|42-8ky}KMI?m$E2q#Lg zz8d!D?cz6 zB&~dmC}>n$7e2Z0a%4jkO6K$azXXaKrjCIoQNEn8+_P zWgxMlH23%!7<9!J?tMsNYTKZBw;0O+=YMU ziSxj-V=QhYm3O&*L_D;<$#~iAFE4K^pO-Fyh*IX1YVHIVSbH?Ggo2epRdcURn4+>k z=LAZmBQaQZ3XoVj==@6L8-dPmgij{uEGE1db=J?75`jbu zeCl=0)^w#_eHxTvTw0xs@0hzKgc)7bbYBS@JoiWgBwNb+BW6}_WrO5P!Zf#T0d}^c z4<>ke;mprM8h^zIEeW3|odlawOjaxWE~ zehI(jVCp4u1)jU)_epU*H(bD8f$I-puQ41rAB@9_CfHr=Oi|qs2B2-IBC2$Psmd;K zJ0sK?O~Y+>c%vd-#R#X+z_p1G(ZFdmZMa3rdX0U)lJKvU%V$+P{AFku*h&_cbPNqX zS60sjEPi!iA#QQ_&DxuZ=mD#BL=V2=P5#tEfQLs=h@N$<5kFB6_;9ShGARTl(kX?P1$P%&ccB)D%Fx(s{^I2(Ma z+o;~w4XI7h(J;8<3b~=lYFG!ag1uK8^hSGQ09U{^8*(_2AELg6Gm<|a5=Q3VW}6JeErt}O?T_IL%2K?n6b;$4gl zj!)0*;nN^o7js26Ru`J-P6P(KK}gYLS!|}m@HJtk!>@g2I{clCf}Lz#o1^x{nGSNs?m47h>485!cbw^bb%axF?O69+D@LJH&1Wq$nD}Z7Ern(}>sU*i z>8$oC}DQ~88;*8%+_mRQzX+h0&HdYs!>7ES?p5K{n?wdV%0G#eFo((3% z3T}kfVH4Hquz{z{(MoT2Ml8wNLA4!Bw3;(BxJJ6U89X%%XSDalB5HQ15;VfyJqtNl zvvsE6=QA(>D772%p<0p$*xR-sEF5peJKX>VpB?;Ls0KhwNL~*sTlgDD$U3$xvK@^Zt z>Y&|e!6^jYmIUloesO}*;_ab{a0afez@{Mf#K?|*4^d+qZ@0kYf~tet8U&kq|He3= z(XH3FQfEDFHz6(AXm*C8fl|9F-o!%@WP~fi-{@Wmcp_hez&9Lkg_Sn6H8zV`2Z(@S zeDZ}M*b_bzwmMaKVHm+1XbPGg2`HXzV_9FE_;1fbc6FMvq^+>statHTw~YY?vlWPL zn?N_7^BjfXm{P?fpohAR@u^BCQH@$gFS>(VOw`>- zFxKr5(-Qa+kw=3^dC4C5%3-M5Na7wu@l_W9cE;zM-3|HxE#wh-1>8xb?`GUuhFtCipOf!?@a%)Z|H5RT+(MM* z$sG0~z8;!)i;L9ut;jjvBljY{ni@0qBCb!=bE&BM4$h3%X%0zwhiUqK{pH->%me3+ zx4VK=7UumO@iOaW#?&wNm#P0yK2u#n2&LO8TN4x9S?yKG66sJD#Bq4w;&@6eGSxr^ z8VQ6*w_@MSAyx#qVEV$`?z}S5P8%AMvt0dvE*f1ptm8RiBte+bX505tqy!(h|kk(LHug9Mk$l6?dOK$a@jm~ z4vpKx8dYJ?nS%7Zo5$wX(KRwRg^+rk$QEpNtT=9Atp{OBraJ^-sWQdqc9|ZcQ^|yC z`+Xsy-bw@apxs-j+wXuKffVp!>FD*1`fN~{nSm{Em9ctAiQs4|!GZvFQ(3gD4zT;? zOqBCg#h~zQJA@>2GpG#BG{v$Ia`uhQPYYY|U1uT%4d2m}1-s}d#jHBOw7~dOIQ~>j zAMb>WIrx%_Sb>T%0?c{CJJt43NL8hfY@ZFf?QpUyCctWIygR)sY;^F#1fXTQEy_?Q z>rL3E-`Kf%rdfrD)kbA}yxXdb&*Da$>B{(2wGnO}gC*@mRESEO`nL>GZ-Q7H8@vHL z!aiZYAshz)Deky_b+TEnH+N&%gQ#Ss2DSz}JHwT+_V9GI(QOYudCy2N`;?8*n!0C= ztnVOPL9&UxXXK{DcT6Q;U{PrgeNwjcybN2y=T=+Vek*9$!-~~E#o`GVt333??eU{F zt<=)o$J*ZIgLu6~DLk}M)il_sE97~fOKR>hHgC^6_k6xu&gXwcWl(!da0$35aI+EW z))Vjp9)~-ihbF3R^x?48Z5G`z`aE#D;JTEf1`j=1skcK*bhergk~<>(A@fKdEmsGW zNBSU%Dm`Mu=T?t2*UENBW%HTahjoa$k**viA!*jQg1+R<{*#4r57ky?XB{tvS$dYl z_KQM>`T>%@2Q|8(dW=F9#BcT;h04$3;>;`kq6*@Vq9z=US7t}Ev&AWU!tD5<6VuJf zLkwzldH^=;vO3*&3gS;i(sLKY54%gCP(l33(4QN~&e1zo5Pvo_=3Wqw7+cu|@qv{r zhl2QH-Q|(5ApR)p2rUSk@+xRl^X*k+={r+t`7QG%JIdvq@+P-p!$rKwRZ!3l$I(m% zdvJXRCFTlEh1@5Wc;drK16Ha6)1uel>k(1py}JqlnI2B*bNT+G*o!umFURlrOx`J% zO=>2eu{10~Dkzbi)JkNnKhjBDHo8ZnZ@)d9xVtQ4@R(5?iPP(Ut;Ah+El-WE*aV8P ziATZ9;44nxpOj1Br7#EqSX;+RaoCX3T0SQ0PfZ!l>N1?=&Ap{u5?y4tbfk!S=B?nq zZ*T;zO>i`v`%c2lOY!FhNAap&A6kIa{7a>O862_tQpqMvk3|Y)+vt3`X`s<9j*IfH zDxAPswUltegAi3jx)P&7nHJ>Euu%&j@F~v(FE(G{=EFcMY5!W*E;B-d-2-QYfzu5cJx~OM75*zX;IaV z{$4{KH@!pbs|_3Dp;I;Kd67?w>bc=W6}`MOsf&Krm!6hq0K>CAX|XqGC5r14*&?l- zj4$OKwj7;A)ktx|DaKQzymZX$Ztjl{Wf3R&dIa`uA!=*>6?~KrfQ)c_bX8 zww!o|$rxGRl_H0lL)qvaXx=RnQl)i~UsPqI-2#oJ)afPYMXiG@A(uX=D+Er?W2RY^ zdkLgT$r@AMQ-J2uEBD@jjHJrFx4wuaDq`3)ym;4U%ckf|C;E{Biomp^48GtNgFD97(PDVK}e=xOvpJc-*EC7Xn zejFPn{8Q;2hRyw~^*bf5^~1w6#Ni&Y2!^Wv=#4Ktkb$LWj>p8R z@*RAwq6MD%W#C;~%Ax1vi6o#WI|GvRD{D^VQz%{EV>KSIsD^Q@#`b;@7cW>M1)pg( z$HR6zz=JoE*kNQ+K5wDIMLXk6$_eoZHYD~R=T^?iIGQ7A>}IwFMF1hPo^3fl^Q?}f z=I!~HbJFrJnFN~|nQ!5+Q!+9UNn)v?o#12BI1d|^fJp7bIC&F%w@LsIe@l#Yk-w3V zxjo9rB=`sF&&zYEj10%8^m(LsM&^K%fhClYIS@ZlMut8us*KDTQ0}wCDFKsxT{*Pa z&wPt^`lfN>64`jt*&Is& z6pnew)6X>vykjID-Yd_mNZ>&2Oyr6j!XS3@8y5{DSNK{ea%5^de*z`xNr9t)#L|-j zS0LXgDR4b}GLr&A-{TxWiUCD*sSW)-(hyGn80<#c2+XVbA^){kHg@3=#IS9r5{xyQ z^{}FC=1+Wsh1ySG-RCmV%tab5FBXvD2|nM<2n9Y52Hmf-VHD=KTG&;wVOrQJ6~izs z72VfiBG>{}pQPJigeFCBJ?sFhlA6g?oi9p%M;hrbJ9-Ih0EPdqbAwYN<5J-5?a%{| zoC??Db7gCs`QlecUYtfevl?4NzA+&!P@hH=q|A*r!&3`XR0OXuPXVTrf{*6ts~3@n4(e5w^xzSC{t-n`&JHW=c@E0X7xp~QB6tJ#>^)7`Vd!$6qxgxPCJe0@80MobLvry}F^1W5 z9xo0$=V`+5s)H0L8ai2(SQ^2N1Nz9OoeQo z{8@;ejevn6u|ztH*ybX;h#plDJ{RGS31(Qs{=6K7!XNo!S$E6D@y9mmG~tgO{6zR8 zeOgrb#NIhT~yD0e!=!$`_&l-GZqi*yG)1cLP2an0Q3y zod7+u3afjybxltxwriF48%;Jy*e=bnI8IeS)u9Hh%$#fu7%s|^PK#n#GABYymeR;QEK-%u z{ti?Gh|ewF^;9iw&@1&sJM)pv-eS?9?Up**!d(x_lvuZ9h!vj~605C&LSj9=EU|iw zLRCcnhBU)N1PW+D|KqieQUL$=g?{!I;GeRnf(HYX0}ioa7YD4Tx)v|M{~RPeH^6_V zy95dW{C7ZqZsEBF;C~S`<__>ebLWPk(_WWG3bh?^q%KAEV@aA^)FR#BMuZ~c`5$8Mo1>Q8#eq_i$P~8o+|9qgvztAf~y<&A|F!9bx?m z)<^w$`2~gbb8JTU(8aO-GeAZH>pv4e5!O$i78TZiX0tUBww#KMPsylK0elde>?hv8 z%>X2khDv)}zZwuu)oe~w%qs&xUa6W?Hx9W_}kvFjAcx||eq zD>U!6$g$)gwo_xq1%rntt9>flvfd}orM<+Mx2M0%>y*ztmw8c1A|-*7V5YSvAWNi~ z3?hMJrZ><*^R;s{J*x`(1X83K7(Dwupt1B6&TEiyl)`xvd@@rwkz0=1=3SyQCFXIw2I$!;#I?-40#FBkhdrCixX+HSb^p$TgW{F6=3_ zvw)@u!Rog%N`cjbN$z}%4Wlr_6&mniY?#mhrDeFf=x1_glT7ZwMNzF*Wj4N_u?vcc zPy$WWczcvY5`5D=|6DHLR9@h#&@ixx3?}KM9DJ@!lnYG!YQwf{>Y35mnlv1oO9JT2 zL`zzzU_sMV0_cl^9k~-gFMuEk_g>)U`iXF|f;dvU*#a;LV{tr39$p9=6R_83MBGx= zo`$={Lb&scPE~@t#qc;Kxbmzieg{{TwL;h()DDM+C&Ku*8%28~;`TM?tA3WjAh>U& zZfb=^8%GJE~h zYTGXg+2<0{1P^Nb?eqO2AV(9uq}k}Sn)Nn$<|(+jw2m9_0Q7A%H{)70HppST5Mtw& z;NscXqDSy2a2;SP1lyc$?g}U9l0>+AYY28(;S~=f!F09V#`Yqs1~bM9fZE01&2&2f zY&YpV3J-vfu27^KC3@P%cZ4^HZPlDD_80WTF9;7Df646m;&K&A+4Dst#q=2ipWE$u zV{TD!)3dg$n_k|t@wZ!s>!GU3@T{XH!#mwU%L;KK-_0bo!Exd|F9RyTll+eP8H3}> z`ef(8%-p7Bg`D-HfNnRqBwESp&e~%Xs_f$Pz9F4Tb>Ygu3({6)7x#;(u)k#&?<`l* z)Y9l}*s#meXx}NjcmPSyU3T#qcL@|KyZ99J=VoFYI%4}OAB4u-%PtV$DZA|A<5sd9 z$}T?aE{{xfhAIW`w~o-VP*h$8jcUHViY%~TDlNZd^TM)?=~0+RSfjkj5^T7LH#rJd zbMhd%9`sIvBqFx7yvHbAS1zSnu{@i!e3YJVsl^2r(Ho@}7pOz!+y>7VTWe?3p>foXQE>4X%cxvT zFD|$^B<^v87kwX|nUivUC zV+%atD~rf=sibrQ9qCEw=K+DGC#BzyT%)A){qV_5N~5O78RVPMsS*ZPsX6C;2Uz(}Bt18<@+)@<6arR$4*j{U+_?K= zz{-A`e1H{nQe^`xKem$P0IdALT^^Yph?dOXw~jCuu!2VA6$mT1_KVa+Ek9f}LjwtzaQNuoq=aym9##G4$Az)GV#9kytHySTLp@|!nQHDty1BBS*&<xx)*>2xETssc_eac>OZ}B72AQV1s6F+$x4k!gbi3Xd9pV)-$VHjlL z5Pip{$Pb_><(iRC04d5| z1W);Ev%3LrM~V0(@eB=8sr|`EA)gYh6z&CA*Sp1JzZvNb^$jIGkA&lz;W*akO-4vS zB8BfRn?*hg&ASCCYKubTx9$OAh3k8uKw~NU9TN1Q_Gx5^l*1r!C4Ikx&<(z}inybo zr36x>B#kNPJwRjW(9*AvaRe>>4nCRCQe^irx}@)SAS#oNt?ChoP=xnkN77k10Zgke z+cVQ_gpE!$VW)%ska?(;r}uW6%R?oGP?6xaqFUn=zmWWnVDEB9X-SCF&<&MVWjgFY zNw#!WZ+=X%>c|sd!Tf2Ur~w?{VOZ%dtv3l&ea!Om#W_ zinB|6#TfO7av7ycRL_BifiEPcq)iR@T-hO)koeWwBy!o{ZEYBC%VihCnKbycIn08g zsKUF=g8tmQ7>=EZ_b@2bFZ$%aI)+qz+0_k zIV1u8(p?^zaUp@be{LP2Wdc)P1&wOHy^4hUnM%uVnK$|Oa(Sn`$@j3~BHrXYoY!P^ zrN{xm2GjrpwxCt1w!;bBrP_hFXx)Mvpk{jJcygmOIVLp1m*D?nVM5K^j)NmmH{eh| z%kewj=&})DfLtQ+(9FY6tL-?}(b8y+Oydt9p|v5M>}8`f8qEM~FjZPVID++!e>TcI z;tX0Tl1KP2GG`C*DUX1LQHn?KAVj5m_zIJ2r;+Z-SxHM~n4R%K#L}Ad*@lYboAkNF zqJ>7%r>BzEZSZ_W*jq_U?HJjgt1P2((WW^2qY6>Qxbs!g(z|932w4V;Oy^2kYR;Yp zx*#nLWDsCxf}VuKO34I8Lnd#h8^28hJZwh7M78xeO%N;@9bxtuVw{WoB6?IN=07(+Vf5IZ#)BVg0JzmcY^>#cwBeB1cV6xj7?^K(Okzk@a9X8tZv0fPq>uvq`GfQ3xjv(w| z8h41=GZrSi5*5WQE-I2|dWG5D-17%px6AoP4khXMvqzR7w0pHY)sWHyDKR}^mGlld z+TI6Dr0+3#EE6AT-qGRCm3Kh%ZtGu53hOP@m~r0O0kKh}vc-IZn4-RBEP0^6Ecx4c zV99~fJEZa?;T2*^&-aWg5A~NT|2z*|IXu}>rm`sOed1TzON@EH?l1FxSw8bzqAg{z zDT(3)M_zj~vP3%2K_rTgwavO&dl3>yl77?R-5&$3|DU~gfs^AX?#Jb~eSSY=23sRnyAj6{b1a8x*{jAD5c27CkYMN3& zRBmpp+MR+^BW-x64ap(M3^m&IU>2%Y;%_^v-9~k?6;yU(6Zo_j)H?8D^wpXQb`O;< zyYTxAv{P3pre41Th41hK8ts^-0Y_4q>jmA_P%*R7hPP+Kk_sJFHE*(7yL&aXBj~r; zKQiq$KQklxC*_Kz(d|DbS;$@x@VTtpyYGk?w8+!R6;~W+GO4xOvIqz4=FNRgpxZ-p zOcqZZC)t7S2*i{Ln>55ihUcRsY#!|MH$1P@!HmfAv;hkl-IQb=Vum?%u;mdyr|bsUD*+INYtiw!z?IFr?#^^)@)%tEh<~<8XhiTxl~gt^2THmzdW6 zgTs9jlAarf``hj_PzZxG!S~AL!6v{ysF>S#X!1SQMk7DS#!}?RV|g{GO`gu-d6WcdGssz_BMwIyjNXjD zEuuKbF4DGqTnWV)(tx;scocq|k*Q0dIB%SY!fwk$u~a}VXJWYjetOg@7W9adoj`Y< zD2&!c>LPUKDN)ZBJt4~T!U1JI;$uysJ(0DrQLxdTYX(;Qh&L;vJ}=KgeP$AtM1P)x z!^}W`h9sm$%O%P2&^nTa?NjK_t0U#^Le`)&vkgK5aI2LQ3iOh^C{WhLFwvkF z-lj4U*UU9qP`P?dI*pXi5HOxgQ$OQoGUFY#ve!{OGR%2~0u{l0P9(cqc=cX^`Q-C& zpi5S*k%dEOW;CN8vS6InV;jL~JtjLD{>G-|o+O_%{wQNwTuP7Zg67@!O9liMn#u>Y z57#TuSO%gjMNFDqWC>Y$gyfC_QFd+~%^id+OCe3qY+@CB8qi!ivg|F$NJ5tV9{iO= zmSvcY2w`@99xkLI&0-U%mg&22Alml8q~=GOt+-A3JW*_KyTWm7p>?8i1FaJ(C#*G< zbj{&ArjLKfhRWUhEPWJqzuI@%n~k5Er1vn&VUk9JQ~L}XM&SuCyYNq8!{kO9`9v># zm^igFqJk&-T2s6taBgN23c%>?dNTi*uj0u!%jJ~GV|*PN2F9p0tMaY;?yvBjAwD3@D3!lR}i3vz*2DcW6yrI zGG4=|Xs>QX|D{x{Gh<~hXaQ?d6tXvNZ_p>K#CWCUN z%s3m9*szPUvHv6x??cjaClH_KJ_Cgkh|h-p+&08Q0&xKvb59`RW~}T4;xk3E91@5- z-RC1;0bm7vdw6CaE)z^_?OSl*<28V2_?qR? z6Hy>b(L@hIOe&T~EUbN~eHG=Ll=)0%FWF8kcNUXS+g_K8r*yAGy`YrtRrnXBbm^~sDy6#~w6Q){ zb4%i0FgS@zjSe$ydr2bgq3CE#wISQEt=&PKxX@rdW7DFR=-aU~ZKc2q%Ad|%d2MHAcCH_uD^}dC zOwPlB<5s^h+nR5*r=t9r)<{w5QU++tay5^;Nw> zM;QB1JAs@;Ds3=>b`6RWRKc{Z8QU84`)J(y(-1)0-m1c1P)ecNfCGiE}6Aqb1d zBpE6FZ#7AoQi{)IDXlHSEb-u?I41kpM-_GNZT^C@{#niNybk;J6;#I)r%a0Y$TmfsSlKXIb;(ebpUD*=3O1LqtF zX$w$hI7LcrC6bZSj4}4-Wjjn#k;hbR8(%!BSlIw9p`_y3_!lJ=>92h%sd({@xhmXR+zNV5 zXG2#EN-OGShnZMx+{Vv?>Q2YOL`+sE8?8pa5hU*aSXJ3!XB$^lSR}`OESx4iLU+nd zWbAjgVsAoW(V>369%ZOgk%Z*NWOoZM9BD!_#xF7`n3=LulD7|W0w1!Doh}n)MNeuX zi<$2;GSdUPVDfQ$a>8`xD?>h9vY59(^KP3oA&YqvHI~Q=AD>XKOfCwq66aE$Gj278 z%dKD$xRo;;M+Q&v-CXrJCJ#lM}IH;mCU2Z*2yT7ep=?To{~$CO^$LW zH(-Z)frZ5-e=hxq+aqU)>rd==rYj#}UFBNK2S#)-7O}Uj(2B9|XVd~?N0STxJR3$~ zrkhaE=dfW41sR#b4dOnV3;%ApoHAL)Z$rbt7+PD>a^d*gs34!B+_`Y6k%Z}T$%TJ| zMxW(N3E@(c3i`TYK<-@lJLPc49SZuddcY6u|Xf9HR!#8I>+=y;z%KL`Bc&u4{@+p zYL8JEh|$-4y<3yG#f^|x^2I=mKBFAu;ntdXxLh$bJHZFBVV9lY{sS@k3X+~1V)Rw_ z87KrX`ZDzA7QN>2v4tbL!FDKz3U#CQG`|gvxkHRFid8nm=!+s*4iKZiaG#HX0V#rm z{FyjHVb5%=3M$oNTNMo^Vj``7W$VImmt?y$9!A|*lcTZW0@mctiw{_`M3;Zl#m+S5 zNbj{&gn;4-({PJl0GDsY4j)~Rl z^rv{8pt=vN(S~D3p+^i}ZZI?3pQnq$)QzAB&5!C^jBRhUT2Z04XfSaH8h-1-9l%-d+lyYitS z_4+dq52@c25s~vKvA&4NdjxS$AR@0eh)6v&CnC7P(icGhDpI$Xz(qb!7@>=`j&PAD z!m@!?Pb9>m-$TKBUgp^$P}GzVt-!N#NZ=&p4@g& zi{m37L^&sX(Z1b+$VTB9%c0+XQ)Mc|EJNOm`3@I;JX8ZugYL{+pUS#xEhIg1 z_>SpX1$m=~n#=4B47{OZv9}pBH8IN=wJL(_lx0TB*gP3?cGz`2^%TUVQ7Wh0%HPlz9 zWRc7WklINYKo>mNO+-M}iYUakP2TPX#e>{T2~C*S z2GQhjFQO)fTqfcVppz{5@R$Z;!{3b!yV&skCx`pzNP6xZ?q9giK%pG&=b%5geFOK5 zSq}Fr(3pD;7yZ|=bGV-t$#TfyegX$qvMWhB+>ePP6xKOoRZyuG+p6enEfZ<|D_a*1 zzO+={8EbL?HeAG-EX7qWTGKJhiKYMb!mj+FjCUA?OUtEjliq=!01dmTWw=E((t%7W zMLIkdPm|){n-jh(NL(kLGsU4NZeVsmzbU3TF2z~&O>tZ6oZsuyiwt52)>v%DuQ>J6>ph^&S z>%&ZVJU)@|uqac5>8`41Vpk!)x*zQBJJftQE;B;@Axfb`pr_^(|Sm1mGYb^)G>6&i@v&^&*1=)lK8a?5?boEsHK9Ug){2one z?i@CZ!n`+umcHMhA!#pG+SEzzMH-@E3oESEzjBeMw_28NJ| zq!nkt=UHl@zB-E0$#hEkIAPCRl5m&Os6EuuBwj97gy&AeeIxVtKbfV2HY_ap5lnLqV6D|qYS!6ggR%u3R+ReAMh51sZMu(?1FF{7f{ZSIu1t> z^aK&rel6R#=wI2CPYLqkF<(YdYihnS1r?vmg8D==4<$|;2jz>Su|qjpw^ zWI3RA&U2p+DH}k+CPM8j7e^?>tBh4arCMyOqVYLQr1h_CU6?MHcgC6o*l-bR@{?F3 zM7ia-*0+OQ5FgO>7u4n)ZYu2Kt!Fch9)<(RDWLia#_3;0KdO6RpswDS-VOBNR>K;g z0eaxI!xe{}Hf#mZo7FF1XaP{dSj@gMjy^6lH9rggggrsf>a7CzV|&o0n`V0Ry?!u* zbs)!}5JRUmhn~v{RT`nys&s&Wu4x$SE?_m3%3QlPji=n|+JjL}!v9GQFzK8xS2~Sm z?FjiYmaIG~t;aXwa!vt$xb(?)Uoh*1nl_C;=KN+A5;ZB}oID@#+v>&p? z{y$JGbh?@^Wf_W71e^8aWOoZM+Z(W1(exYig^kQwZjf1nC+H!tLPLXN9kt1M&Rov9 z9}dmC?R*W^CA6OpB6NUua|csn2{=|JLMYlj*>JUiAJ9^h`4*G;bBD{nO8NYASr*M? zWB`v+bg+34vV@jSyq#(kz@ufNaU29YN}(wmcJu=&CZh<$uK*k0Vs9YFmf&Q66a0Ksf7(w z%*hBQZesR1fYM9L<&eoiy$~7(hR_O?22jH1SxTY45&%ll$1cl8xN_5OidODlqfux0 zfRbpK9OQk9@Z12U?}sk13{aZxbQ{lvBMgw8Oq#6$P^GaDs#F;oRB0@NDpeK%s`NfV zay(|vi0pgS%w>u!K9@yyTQ*dwlnLbPia4HPpry|VqzYjWoSc+G@4;o^aJ5IxydV}za1w+d=-gN1(R@9KD?AI1#&0e}sK(GS03 z2?0Ww{JykY`8B%#B2rwB1=V;Ir~;+vzK3gM;1E2*#Y0O8IK-3_93tG{=LJKAuZvKK zcj0{cLLuHG2txu2@wfyO!kZi(fjuKaA{ZD%*m42{@d07LE}|EKARZNU9f2SslJ+#e zdlbZBSLK30gdZgV5XfH$mDvD@i*f=W!ggi&!zEephiuxC;D=A+Kr_G(ArZ8Nx4{pR z0C^}OSrb|Vr_p~p4Z#m5sJQb3#7dVrPJkcUA^0Ih!JF8hm+84ugCBU_!d}XYgCBl? zvQOZLf5E>9{6K&0Q{V@vR)YXYgA8+mKjf%Z!&@IF0OF!Vj*s^}-s{YDYl!u%cBg{A z0C<2y{QOgHAd`>Tl78r;K^)w&P(?rw2PV54`H^~?dt^B<_iMu*j^T3>@p(Lv(mzza z7`@Q6Gx+v%GLO-ZYZvzcK%SIh{1 zWX!l^xXf5rJ~LdFF~ivmutJLNG*3d7Xn`FCSRt9TxAcjJM?$GFcN?Tor6oMUzW;^A zt8}=+(~yS*SE#{XNw`ANf<}Oavj-XR6v#qs#*}mNOI(n(1qQQ|AF^=57Bc-%VnA=G zwVII{rMTaZ6ch2`KS@uN;#b_UFFE#3lPO_L#fl_EVi6yf>Gn~7=~)aJV2arV=X+vh1`0EG#78H2HuIxG3h7({*( zi@!!cvPt<9VNN|bYJ};J6-P6L37^Ztv=)WQg|j^8FLp4zngw4I=<;BwsaYV>Lu|gp zPl}j4NWBzN(vOlncyPd9N$*t-vw{o3A;rqASb79231Q@2y9ZhNc|Fz&fs35uni=yd z#`Mk8Mpei0ZW4Xd;eB0}>VHe+a|G`bvko4TRiNJjZ3gITI(4Si?ao1EhK${+ZEU6yj2}*TcCn$Oj%&NTE!a`gYru|hFC?_Dq>cMp& zNOe@x!$d(mHa&qB(xg482n7K}un866a9z*Qj7{8fTF=;mzXCpI zxEMrS2276G21Q&r?lVmfSw$gYHHV}9fDM{Rd4)`A>~}VUS0`Dj6U$lV&jC8|XlUMT zziSfw3FyRS)YuTA6L$`m8FwrKGfqy|eXY{AybOAugeU7ICP}lyWnQa%=DD~GMl3UM zCn>h6c`34l+=@{Z$v8t=ItJCqNFhnvh6L{_Kx^rslh+~x33T!%_$vuIvDT&tadM_a z^>_;0BsNhB{IDE5)(aar*7@Nkr-X15ZScbqlv)Kzr83`QI`zA37<{{!Wu1jsmUeje z##K`>{&yI~!1&RiPCmkhQJC>2miA$6m||&0=5XV-528*UDVIkk75UfDFtCL5Bn@?f z&y8~O$;p8_kv>nDH5b&$7iiobdTA2cpI4;kMx9)3tjy}wR1p{b(L~e~L!rvWr)a9$ zIbhyf*RoAs(iHO;BWF|eB!4N)iU&`OIQ);|Nv1g9b6FfVAa2B!G0YH4eH4}m_Lmmd!?epUA5dvMiA-MP@PWQ6d!EOpNqE_XSuK^%?^ zp*VUXHZ>M};>g$|-o=#y#U89S&D07k zo+2vEVeK`QYv!Sd{PyZxtFOw;E4DyE`e0_Z4|L)+HC2^?OleK^5rwHqUoA3H+ zSde!Npl*H8g?s1f%5;)FjIc=ICV;-9Yp3+fRQnF!rCRu7d{k??j-&VrhVIwpb6)fxbm6UEy>h=*@5@FJ7)RLXt91A^MT2X{}rOpwcVyzTaC_=<Yi6H}w|Giv6Ghxgh zW5X_C%>4&oeC*XgdTxO6@%Xk*B=A^ehA&nKV0<+6=cZx;!1#1%%pG8ishY9@#z%-` zIRK0gai5QT0OJG25ei8eV^vV87Tc<5C@~Xh{VUs7+*mH}j5WC)8!li??tB!um$-SW z>;1VoiiPoTy#)?o!}`AmT^k2C#3iqd6JfxsLRUov6QZMK);)I=zi83TbYlw7tl`X2 zpdcrpS>KfxeWzf_Dhh)E79C}!o$;?Y1<@tNc$h`J*DuZ~ChbotSK2A}N?_(E6}J?q zFr`=u4@b&?nR%|3uWbo1bC9=;8wNPHsVT|}`&Dm?Fy?!3Hhp2t_X?trfHB_~FXC2& z7!DXXeOBEC1=nQ2O?I(%6X@mV3!}|&IZ~In2)%qt)H76Yi}f2pmoFStz%BMo61R-3 zg*1zeTV6A`ep{?r8MJ(97HBz>uq0x64-PW}u^f^>@h=;(EJ==s?r8u=^Zn>#5wz%3 z1)P{CM!L*z0q{pn8K0lvI6m1o?3 zX1v3e{4b;2xNg?ogIAZm7yc2XT2TWW4E60T_&zxTUrctl@ahr6nN#LvkAX1Su;xns zIeW;$GDn$X1cdqI zbdlE*Y%^!j`^2oQml*R7-s~*$E>{CCf#yqQp3AanW+DT%o1%ivZ=*cX(mE>C?zwr) zPkHi62}{w2<+w(H<- z=122hu_auNY0Dn2#<6$;VlNaV!62ogAcR(5QpZ9qF`eDyp|e5&N;{Q%^Wvi>@=``Q zOyp?L!B1er;2Ynp6-Sr=69{`eHcWvqBg42o8YVjUq^Krc?2x_=8YN+&2jlBpvei#a zM4RPu$e=v7L&Lxj(x^0SFg`b`&ZkCwC0vaseVj0vF38{-joL#rOyX-o5uO_ve68}P zRjDfz7bS>OJ?PcCjY)ufBJLLoy`+pUaYP zc}(I}xHdOqn6OJd6%v~TBGH3O-ePm-o#3h}XA~tTT>KD382$*$-CQqF(dz9TgbL!r z&MeAHkI-$^oz(^eZ+gB(eJCfD>hXsD=Ppf>{h3OP0=4?06*Q)%5xEzBiI_vcJyv$Y20#F}D*6vlGyE_9TC3WwJ+sr>1W;-E18$UQ*9m>uYqV>Se2B&m zP0mzzZ^C~xX69yMt-xttKz7yu*NM6uJqJSOps-!HGm}QwOi+iWf_kIcj`d-+M30dp z&`>&iW*Tj1rqPy0G!{J{FrrQ!7&Qa`%p^@Uuxq*j@XzY(EKExeKIrwwI@|j}I~pPx zG>V_VJa!t0cU=kCQJh2kXV60s5lsFh9FdN7RT&SVp)26^9qTq#wl}))>W;Z;x8G<5 znOx$piQL+;VG~SIqg&Ul#`<417N14yHE9mIGrdZ;1BGu;;wwEIa8MbCf7Jnr+Njab zD?;XsK|^uz?#<1Ba4NkZ>CtKdPa=l0Zz@lUw}4&M5kU-d47xN~?FIF*jyedieXdRrfHIW;yxrfaL_A%gf2rhG;E0en=dP4gMON zh|HyhQaU{Poj3m10-+upHt11t)U=Erc-J@|i}=YSaD7Z1gZ$_s3kes!VofoD{fCm+ zNidDMZevgLA5l_OF5=6;0<|*|IYrDpRIQZ`47Mfdh>38yv;^s}@MqriPfH>^B-KTZ zZZF*v;G~Jnwz)Po5xEf-+YXO@=Zzn6O}3#Kvi?0P%hBN@bRz$-337id+7F>0d9$aF zj_{?Clg2zQK0GI?k5*JGpUS&7!e9ioh!RGB-piqH~7(! zvdfC87)Q@L^unogV%H%P5Vx`TbrAf-oBYD)7GY^$Q6h?*<692c$4289akoY zA1>pxitPKSbq4#Gi3t;Io3QveW*+e_eo`(wAJ%X`aqJY4u)&hj7lraDAHayoq{rsj z&ZBsY!kjz1%Xbv!gb3z`y-=9u+}Tak#E{ROoquhqF$|L+KL;CjNs#Y9=gu}G>ABCH zUF$vrh0dK_1^v0Hm~igw7HG`<+!=z5%072?g-DjexwA{%=OYzP8b(72vqK=#i^UNN zs1svVP^lK%s^}ADOr-U%EQJ2da(QR0$u4ZTh&B1EID(+0BWI8m43C_RshcM#j}HE7 zh|0jUHXdB6K!$C)3Rhdy^^vpaw3&ICzBQ-a!jn&7g`E)iF{YoJE6Nm9X8$9P$<@os zl`Er@FD8ZZ@HdQ3qG*<)lO8UMIpM|eb{3lIb5{OsF7FAi6pVR}lU^xbi6_3^jkD`} z;_JPFXe3U2-5Edel`>3k;&@W>9KglYf?iLZ088m7aT4r<0u?UO8Jz?>D;fcu1WV~Z zIuW)ZO2me*2fZ~$G%h+P_1omhFq{HF`q?MLHV!@+mNGQ?gxFhNwF0BK>c}H zE^|_h6x+-dsSjoBI^Al^>8RL7x1(ZFAHzH= zw*59`=B}A*w4fZ|nhYwV!(!TbvCoUGQfR(y=$19w_R|%SZ5?mE6(l;2BRM&}$LIs) z8fCr29E`)R1L@M|4*2q!p?^iL$2ch2-NOBQ(Rng0J?3LB9;NlqsZOkw+nT*W$74cGjm9g{I;j;5_<+IbptuYdwagr~^ z_%)XzOUU&Z)k(hdaxG?qj`F3@rtM9FiN64sru3tHedHt^<$D(Vl|0IqwH!ug`7X%C zhqS|du{l)k>k=G_UQ}U+kpD2>Wn1)NzR+3nI?3nX3{%+WGeUBC2LnTb7|hzM*L*dH z&t;^;9FFE3-|N{h3eSKEEWQ>Srof^RU);2C95yAsknk(ilIPDj0qgPebp{-_{^eb3-pQuoMLlOrsC=a=4sNYn%F1j}$UPM@I-PHY`!G4id5#_Pw zZfW#XwE}4C)=qf00~`}GY(@?MSVRq+(nl~2uyEjEuQptfkm5M;#1{!h>^hi~-lLsS z@^rcDr9+2apRLgzI$})8fzYtD^x$*Zl)QYe(h?rP5JztxU^#RGRm{Q@9gM&6M$Zsf z;xQNIz>hduGWK8G?+gHEt;hj;zD}7)wI0?4E=_%jce`eEGrGy&*l`-1Sa+gfU1TXO zwjHn87QMi`yLxmio5AI0(TqALdy%=kWfWX46#IlK4p>(pycH?(uX=DEpf(Lp0B;hWDW@-b^S#Ps0H1_~A>h9n$b?fSK=*RET=?vl#7 z^_$kNh5y5qR-L=my?DSLUOu2(sS*XzXKODrpHdX7`cw)xFk!b?2n=z!)SHngQfNUxL6%%SaPxOx$I(nb-xv7vaYW=UfB|Fv#s>|0Ku`$~rI%wijYZX7>Qr_Gf$|c&kuHra}=+gz0#0M$1Wz)QLBC!iEc2lRH-Lk^Vd(Z6S1 z0yU>WafFWr&9F}n?J~zhAVpe(IApsI)hi*!2mjAHTodV;pxDEc^gfC%RS;*0hHqD$Ql5Jm0FCx|Z3Izcp;=HwBg58}Wxju3@JQRv97pCAdI zhcc5@qSg7;=-CmDc9}9$Zy?sX$Ux!<(RaclL@9=%iT!z*uq$=-362uAos8l~h`x@x zK}U%G9{-{vMD*7_b%f}O2&3b5&(zx7hlj$G#=|@|^upURjtzxBoXu-)pOcT7$MI8?GL3rX>uH7_7CB1vlVo=bFW)xZnPMyF*9o1S(1cuk&f$m~lmGMPE%vCcB%a!hFqns*C1m_rU0UYo;u`c5s#}>P%QY}$jN7Tb)R9uN^Abih z%+6>|X1#?CBbU1?@!o`---Hd*rq&21MhS*_GV646GRqEC7e0ISaJh^!=&TPz!@w6( zptQ4B_&iHH)K@1aBlA|mS!%;&DG9wv3RqB5<^weNjD3+LC??_jM~eR3r>lNxT>jY2 zSp=ViQ!LSykOkogL2{$ogByYnu-Ok3WKh8p zcT>E|qo&~IEd>>mv~L( zIykM;zMx-GWyWaSX26xndAR&%dv&hWuZ*viV25~lQdql;+vWHJW_iCO$d<>X8lnEC zn$%38#^B)_t$fGqoHdA~MLvpdB=^*1{1Tu$DLXKLWo!CfeZc z#BtK}C(tj_CxwjB-;>aJkmGHP?z{o=qDGU^9z7YHC0S(6`*0DQHWg@9dX=YLf7{l_ zj@6)mzPhe&(?u8U+O=y|B^K ztqbdO%v4%t&2W-Sd*#M#>*66E#;lzI4NGe^K9|kf`C!vg zfa&MQ@|1$v;VjPk5o74nOK0da{1|%d3T{IkxMzC@c@eUml4uXr)%Xa5)%9!;AN1CZ zK~F3XY?`DN3%L-d;%pTwVDGq}`PD_h@tabkoBFcu$DUy$JXLflwE(IkE7HqgI=9`yycR6MGv`?DpO$BT54)))aFN9xjQUW)t!;lvH~Y zB65moO1%hJ{LGdlw~K(kP!i!Day0CVfStJJdJ*t9N5{9E7XdqwpZ_A@pNx+1JQo2w zQSEmT@F6#4uQ5Y5y$%-vJ2ArTBH&X-#{i#;fSovz?;_w8qvODkE&_ICQjUv&uNWPZ zhHw$ED}!=e1boZr7&N4dfSs6>_afkJqhr&eT?FjNxO^7@?-(89{4WA_;zXW{fPZat zTv&vQfL+-&@FL*XjFer&z6jWfUHL8oe#ht-R@Ozpj$Fxe5%7bfp-BPNTQM_G6VVaKWVUI?lH7)B>7iCpV++W_tgAy^?8 z0&3Uw;Q%aUp4!1KUCy|!U}R7#j+z8)Sid9S6Aq!bc=9p)jm4#YRPMZ+KmVF{Ih z&*ebs6C=o4xh!MkOQR?xYyU*#d+gS2*pJ63OwpV7`ht(lfpUb*dY#5JMQ`3fO$@o{ z%>|FkmM4#CFqq+Uv0)d?@cvWu<{BhDchQ^c+-IOr(VMHGKR0tO6ur3>8gnmtgGVUJ zE_(B5kt~OzHG0c&#S zON62~1pJ0Nynyxu|De+j;pXT@7!V88%j;LB0oIAw7G4U6O5{*Q8vZ+e4Yhpx4FI%{ zW3d_l#z3W-RTWc)CcLydsyl-xbPVu&1y#9>O5}u&&KTg+cVeShb2xH-%po3AHD|ih zZ9Ef*NqtTENqBjKRX=Aec0o4Q&#_D6M1v3O=0q5Ey3ZkmyaUKIXxFh|a#(LTtjP;F zd^i>!bgc`se>FAy7}kiVhUxP{x%zBu;Y-Mnc{mux!$Ol#iY@eT6-~(=e)Nl%7AeCkyc)r(q*#7vfo$yAV$# z3z}`G!!b%MioFc}eb=6aLmKsU>(^$L;E^ay7T@_(9BfAMosf{!n1v)x9%@PUg}j8{ zL=W>cAoS+*)e+5i5j$PxI;6+k-+kPXX{SAvSAzX{8KWz8@g07|*LHS_7vK3I>Hrnr z`B(glito^0`&99rwOy?E?{r=Fc>^o%V3Wfvvy-^UlW3TAsDpC|k*!sklqvj;E!cn%RO|=8N%*~18*=$b~QaL{HuATwA^oQ^&O;*ZtHgRVq zIjJigWLd4xgMF(?d(V%<3(97l4$Zr5`c0*Y&=5YT8#|>yV;N;DQUs}aGO~nh_^8TO zoOGL2wt|F-nkhR0S36DOZA)+| zC(5djHOhD6?+eQ1lgSx97a9h(D5s$Et^4k;@DpbE+^8v^AobM=oADwmPAyX^sfmP9 zbGg#@*)(}&3wtGr~=ngS7c(a{dVFEK~!@2Pe z#reX^w<@dGtG6kAhuuYYXib9mv5J#X++ z0&6_xZ1CWf5qKK$|7M#p0sjGuA{Htgc3>_4gQbCC4- z5_1gSOmHi4p8E_GN_C$N{kiRW`QC2f2uOd`J9w|ep5{f+n0u-lcVK0wx|fM$Ii$Kz zb)OF@+(26;DkXNZI6`5!WvmJ+)nZ!}oz!L`t$$@6@zcxYov|iQ!G?=ilN0X%r;%22 z$Yv`yRy&Ddk-4-t7|KZjEFhgG!MMkA>4D{`ltG+Em$zzbEEQ{Gt0b zINOJBi7CEU;_UgR_+BMUeImtoSuDlpGpEw)l(=eHb?IbdIuMPmcnG^c!<-s%f+*D zUqHF0tlVGWUzC-jzxJuD-1_cZd)r)nyHj57f`NHC)#xxYb5G*#>Y9iSpapirb8Wop zd==uYFeq*3>sD22fUg4Jx&1)6(BiPL2d(s^f%;dr2>%mGgbuIsB_=~>iX`*Clk9Hc z`J+wdg#uu*Kz2Is>haQM>LIX8@nFqC(6XK-JKe_~(iGA!Z2Fem;yisWH%a^)rps+} zBc$~HiyBKLKv6DH1v2@NctMLZea86lsNwSCBxruv{5U1U5@hmc;0MI7%(oc-)()3{ zs}_TQ83r?(e}g_y{L6Za@$bgr^6$Fx`RC$n8RgDMv8R~#=1bQ;5k&l$t_>-tCti1hRx;9=*zZhBp6#I}LO@45|9h7!q1bv4qZQaXngsg& zY#6!xJShxkLP@`l4OPC_}*YOhD9FA3ic;;3U%aEa6;?G}dzgpSo$XAdTxDV@}!%OVikNm4or#J+<_$=EDN zLS&LmZ&TdJonF5l{ANtBU$5?9=ym40wE%WXb=XM3Jq^`KIx`Yfp19@lbOQrOMt@oX zfj}xMy;`?1+ZTi*kL&#vVTL@IVMOCgiW!-rfzOSh=BlhjWF5-?%VbUV?QAk>Tw)oQ04R>NBEp5h`@Ch8)+g|Af1kk}- z3shC===POJwxVVt@J}7FIAcMzHf=cFtIWaDB}rJ=3iq%Mi+*L3uwqyeb{;e=ty=h8 zmayfU2Qt#i=Sof5^)K_5F271>)I$YL>GHu0*j!vj*j!6J7E-w7G}j*7@Hfx5hkI;N zxO$x~6v6A`@RFw99HT#`z9op3RywozFG3SJ`hSOoeOdYx{mOV;FIQZQ z#hxG@XM2J8T-K)>HkZREMz7RuA(^_XESd5cg~21e#dj$&`C;7kcx8PI9_i)O#E|hw zZx95?L$%Ge?{(O)%eHU-!6SVTNzaW(`mp;96v89DANq3(QS&eu!y|nX8gs`ZVX&%f zJklSCWI5oG-sL_Y(jL}qgMUvPp%A_@Rt1%6v8{?m9x;*Dzp{1VU(4m4u_iyjhKpE} zo(_hDmh6m~r#_&Q%0N+>JaQPVe7+5)jicUZ&FM!I| z`mK4W2UhJ<-3{CrVT2)U$Eq-~Fp?3l*;(=gV4@D-^0J_E`80 zo{Gm}IfoL36rPe3PoAPg*=<8nsCg%_ z)%u)Zt62NP#9dvLo(zrkK0eolkX^XtcK}$OkYtoL0Hlj)FR-=xSturMYjqLW)$U|> z3$NT8U{|rp*keEfHUjI+yc6|M0$6uC5t6~pn+71GF;L*qXlZ?|CfGmUOP%`0_ z(7fAb%|I|h8~Pw-^eGSbGHNV=uR0||zBBnU@B`vi=37k8e}B0Adq?^Fb6FbAWMtrB zQuMC*Qe+7&pQFOVoITJm?%^?kP}EHQi4?lDS|k|Q1AfOqvCb zP%`HXq(7}PMQq-bzRlqfv<(OEF+X7D{4EHWX;VRIwa`|kJ3Y8Eo03eZuy7nK=xP-u zjm!HHQ^0SsLGmq6mH`uD71|5jYnKl-H-FE_hPfFH>gGS$FbZ?u1WbN{4O76xh$U`d z_7Bv}@wde_t1#P4zU63W7`R00l!m&&=SHP@$9||Asl|k)bSY{vMx=PCuu0Dyrnr$C zb+ZcGBTCK1;WboUryI<4`V?w|YLv@z*-Z4xHJgJvTE8x_r&5`fQT z2{>Nz(p^niz7D_BRCq@{nBPCHw|9?BXTtKS|mTAnCc2v>$Sx zfkH{z_d$Pd`+mM5V@cXiKx6JnTHH33ouqxQNR~sA_V?ZABVUsCo#F_EjgPS^s8ow> zRdhO*iM0Ne`5Hegmv_dR{4+LO#F~7xGi$UCnT2Ja${QQrBCsQW1I9P2zvL9fk~f{uNd%tj;6AxvRsqc`NtM#tK| zQnN2DF})!xF)h=X%u#Q`0cYf>Lt<#hZRe;Z;qp*a9i43cD|$B+WIt8~1kWOty3BbZ zM}1qEqfRjb)Ss7mGC67H_7cC-E=JQPW@hRE~O6uiD*)2XcC~Y9E$p zrv&vygA&wM<3r3&-+2~X7G>ojtlr0KonZU+My&x}iJhEYRS8Ufj7$zYeokD@`3>XrzYUku zKU@S(ugLACWpdl23F5fJcZ};}Tb%tfm&NQ*Xnxp>*)q}L&E#~>&xpGN-enwJK3tBT zxdfn=pMNf~6XUC8fEZJDFwK{sY1I3Mvw3Zu=~qQ* z3LbQ73iuYvX!Wbzsi41S;Z)qy&b5MGxM4RJT*8%-P%gbu-?MP0ym=mkU`!!OyUYph zb%EN_5sVWkRfJ%ihQE>s#>6f*f-hEN%G0omvFTFbus&PbVC$D3yLisEotfFWKHN7Q z3&T{lcRMqct(&)08f|!})snO<*B4CVW<4}cNZxHij5KDh_RgKRnvxktGfc^7Ad4?x z!{G7$ti7bbdXqkU9yUzrLnDnCBPI}fLSW5>#0B4I=CTYnPaBKN0 zhW&QA{4+45--3pLU8GTI*hPGv71vTe@{eXtCO@Om-Vn)BSeP>s3}(dX1@>>e|)XHQ!X3 zq5|<1jK@N^WM1o)T~OQ%!n|RWwGvdj@ZS{dt*jgi+kgmo7erWUA$)~@Uzw`TWRGDi z&ln&r-wWD3$d0!FtBzTD7}Ing=nLBx$2LaPrHw7C-SM!j(hBGSYb|Z6v^(w9?M@f2 zNozb4&wHD!K(ziO%l;i1o66`dr5)@E6aUW%n&lz8Mx{TkWH(c#@wu$hPa2Nw@)WQ* z47&u=VG|_y6P&q+(2u;?|0huA!B$g*NgOXRdugg(^5KcC*i@e|VJo%8faC1vyt5yV zju#h8#v{x8@XbQtiq4HadI)+;|-qAr@vlU{i$N|C;W9=XV@eZ5B4du$8Fz|t->lrgUe^IXB7_;*^nuBb!gU>z9j`*pqYllq` z`z^gXgnr~I{B2=G9}pfCQj*uY!7l?vq7z~eI5Z@ke0F= zfaEGkA_8e+r$OX)97v#)i8VqLmR&3Y>Gra#4 zFl!;{xeJ)J-DjXs0kbCb=XQ!pC}6f58gnmThNmXVE?~A@BrBzW*=r750(fHhU-LXT zUT{}b%H;<5QK9-L-6tkrC9`efPz6N3F)yfHi)~(X%`zt2`d79&HzXnuAlBg<{ePw&m@N=J9&jr>S}ikikq}d z30<{8SfoDL41BQM88E>A_mSv%tPMtbaS}_BUXNAYR0QLvcKC6b#FbJFsqB_1on;m1 z7+5#UdS9#s_P02rzE@0rO%R8~6;qEdlOXP9F9RRGhG!|D3YbNFq6FACg)zIxUsM9@ z)Tr;}R?kuWuhnw>FYBvl#V}VhtP&3MY zg=Emy-7fnj$&rUP>f?RQXQNMW8mz=OpRbnRM~Im&^PDLAbx&CKD@D_(KQ9|}rM{Yq zpTx9RrQ&739`z((36=di75}2LU-Z{LRrc$$UUg@%ZKkCVqE1D>Ru3-v6>EBkCBGIf zfz39Wt!w5Qt$NU1!)eMm;Vx9cI+``WO{DdVt?KJh5Eicj)|zB@3ojjU1+4gtn{(_| z{i}sj#|KSHqK;8!MS;lQwd+9*{D3TI=38uHZ%T4nA8OCCfeyD-T@TH>ZTd`YfkYjs z%>^3EC{&OlXw9pUCA1=p>b9jbB&{D*rXYnRJ)?=0as|*@dYOU_GLXs??1I0NWeO}q z6BQ{)mS>2mTv~~O*hHzN`$FtkTPg5}@|P$$b}OtFfDF6k@#^RUH;sv>OoyJsy5$ai zmJSKKZS9-vjV4bq`dN%(VDxAT5A0#XD9m`X+kX`{OuKy}W9VTIv+%⁣Nwcw{)k{ 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 Z(roaC=Kn0pywJft=b&~ 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

    4G^uO17b1> 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%0D)sGQGW5HS|}AUGlWjZz;F<* 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

    v|EUkX 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 literal 0 HcmV?d00001 diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..7c549927879d621cf3be0cb350b9400928d85e2a GIT binary patch literal 8414 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 B-ERN@ literal 0 HcmV?d00001 diff --git a/.doctrees/installation.doctree b/.doctrees/installation.doctree new file mode 100644 index 0000000000000000000000000000000000000000..cdc267a33ec76cf6a8ce5c27e6849af119b1fae2 GIT binary patch literal 19971 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ப}+nC0a;}$$o;cdW+}>W`;O)8-bTg4DWhRsWI<8TbOZHuF419 zRhXYw_mc%YRh}z*13v&dwu!4D5G43@O{7vG5@0&m+39Dp_OF1OzTE#D^aZ~C1h}nfw?&d*mfH300d$Rcx{bnc^fD2L-JE1I)qLZ~y=R literal 0 HcmV?d00001 diff --git a/.doctrees/machine_learning.doctree b/.doctrees/machine_learning.doctree new file mode 100644 index 0000000000000000000000000000000000000000..896527cefff7613b322a318fadf00f32185a70d2 GIT binary patch literal 18521 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 b5BK2d*ET$en$m;Ew($ukewi`6W##_?&UOZk literal 0 HcmV?d00001 diff --git a/.doctrees/processes.doctree b/.doctrees/processes.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f40b72e7f6c0b0473cd5072c46eef8ebfdb0f8ab GIT binary patch literal 63037 zcmeHw3zQ^Rd7f7LZtbpK%K&;7Ba59`W_lk&560}`m5_{(c9A7v77L}jrn_dkdizCJ z_wI~kVS&Nc;<96h;UsdvC&3PO@QHnnodmFP2o820$Buns2RjZq1RRbX@Z$i%@ss5H z{`;s~)!o%Sy{naEqyw|v)phUv@BjbzzyIt0_o?mgKli+6YZb5XnBtppqKWq6}f3mesL(As!>Bi_f?dtoCg z>h?RMpwbK5E!(`dy|$ya^YM+j+U|IJFYGk}=cjn)E$!}^u(j%)3wt%M(`{FRC;}X8 zfd<xRqy z9!BB}w}#b-v)Nf`_%b{`Z*Tcc{ESb#s{Ky#W!bNs=>{wOr62F?`K$bCqjqKO`r4k_ z4YjSc8{<=lYVBrlsM~L~g6^SnnBk#zCujxj#m;)K)^06U8X4B~NWuRj>X6dhX{Z7rr;eWor<+1;J-?ZTQ-ob;q@xg;$7g_r^!wbjoYB zdjjLqlF)vxHWTkn&1*xG8hAdW@O-Lv6Q~Ka?1*~Zc5Bte$rTP76f@1lJ2hgQo?hej z zSEJ?8TovzLYc`gmj!(h5tAmvlbk7FDY=NHlZfD*_C5~&`<9~6&(gG_y3Y%fW?|Qv9 zSN}@CCGr=GzvWfh%_f#TumPdbY*NlP{MKsUUk###0vC28JQJJ?Bdp;jmUW2LY`P92 zS-Hyrds&9)ta@1Tm6|Ufd+pT#3%*+jTNt+$oI?lguDpvr)+mpZ%!!J2JzqB(Y==9} zxy*^hy(?&TYJL<(E}aX>JPplunVCC%z0>V$G$FXWzZaN3C(HZ%^9OT@$V*{mvNdCO zB+Tjx!#id#zREm^_n+{VLy`FqBVdtsqrJLrkUIRw1gsBCj$nfGjCx&`^nQS4S^D(n zwp@1E3E8`X#cHr3JeJvf`~Lwc7kw!5o`jA9`>)uAKB z!_G!s>opt4%cX@v)UVV$AFD?#zNU{6@h7bK4R5Yoj{41Vc>z0RHRLqZ=jiR-9zPX} z#d-9=tuV4Jnt|U^uQmNO^A@+|LfFJgHZXH_qyHwha`m>~=`_|$XM%1kXqaXNXJHoZ z)>y*64)g?T&<1+ID;9Lr?{wPT9@cbZa10~@u2$9W0`o1(59m+QaHSgrYy=6WX~+FO zq{e|M^IiPfPUOJlCp>43e#B*=+Fh0}U&^Vlk$Byz?`Po|$X413chj8Hjy~)rKZxi)9o}}}52j<@Ih8yv1Q><;-mp`L151q3I zRU$~NBp~sQ>12k&k5N6HnHWL1NZCZ=!CFVYQBa+?Q<5y;YBaW#Z`4?efZG4&miMK& zV40!1@xT_#RX2|jVh)+o?De2!dT5{`=nV0<;+xa#8I~RORKt`?cpI?skP%`7 zwusmrKFk?N;jY&SI|1E03yI?*{O+JCCQj6YVM3inR6n!xQbU8cqm7Om4g7rYU?1j} z5xGWs9ux(VZj?r&eJ&Dz1~i@JK0IJ(-Uyewes`S?lWx$D{AHL=@*8zAF;1g`_+01% zfhC3ig)Iz2Eh~Uc1N{?Lnzg*zw5YsJ0|sGKEIb0OY6${*sq8|Q>;h#EZX9KGg)Mq? zL@Q0ytoo%xp2NfM%J8tG(Ys-7| zz>2pN(c<84R|xn>c(euS#3ArT-d1p9D0a% z;z4h{1JB4-juu~mzpzjmVI}NsoR^=^`Q6sW)6!HcV2F<2I45fgQ~K4 zqxPZ|VH%;HxQHpc?(ab@j4JSTW1t#_rS%)OI{hBTh5H94w0x$=*ASx+)!KcCHwY`R z)ftRqoIS^)}kb$Wetz62j4fuqrZ%CAP55h)AJE5Uc@<9%k*zmubS2 zU29hzSJYdcB@#HR>Nm)45)aUR>cq6Y+B&BVrHlmJo1&o8+kegUHhO(gXNE;v=lB$T zr?19`7de3o4g6v`Az9s7LQS^14Y_BZ3&a}i_+wTu^wpjy>v@4)v z9Z0f%vK;r_?3*Jh8`jf1;4v}5w3&F4R}-}S#ilq8-o5(QZ3_YXsH@Gzzy2tee}i5v zKr7;A2&5DV%Htx=Jfo`>wE6_yNxP^dTDZj3zEpmPGLMV!pZAKDHezn#059H?eB`(# zE8xnR=oJ(?Sn{IIS#OsWP7?U@=FGZ8pm5#^Q9XR|XXPyV9hav?Nd1Grur;w?GxhwH zw6UgZ{VI;5w1unEsG6I1z_}&^PFe=d)qfVy#g}*1p(J$H7fGA}C4ts_eINQk6n13b z$7%@mUt*80YH$OZI;z1o8Dykxa2_hg`cku9?IY-X3L%#DCD|1=PSrofo)2%9bLazd z^@vwvHYAd$nBR7xY~`RjOZh~^7|)OK=}=^tC>g;qix42K7*;ubIc9tOxQ*Z;EEajk zyvH7>=Btw9XF{(5_(G{)qU67a~q^(j+I}8&PB$+_V_9XQHN}RHr-`)?p zArw(YE76t)LvMunx^>Xr_?mjduGChirQNj<)&><@O5F972X8BvHbO_f$k@ zI{$6CB#gz3g=e0(2ykS}8$j-qV*0yAPQ-uj65t7Fx^*III3Pci0Xb*y(D8r?hp7G0 z1;qmD#3dx{mn{Y_P7J_8pK<*!rr32O(JO5O;qS!z?`0cM3L>G!Mgr<(&H#)1OSQjb z1VGPdvi;`RC_&IZfvkkqsw5K(sCi~lBc}+9`Ye_;wYkFN+KjPijYd~ad|tOrF|fmD zy$qkF6|Qf+01&e(*E=|pQn{|l&L^dGJ(U3|&H9roUEf1GPp5Rf7fm;zbk!H}{;7IV z{)(P;biAIG#X(lnx*M!U>WHSbrIwXVXqPx^HFOO@zCEA z6Y8G>U{}(nX_xVzF@v!FVcSAXsQWP8WPAOElSwq*3!4nk`z_@24MxeWSLrN5y;ZLo zc3~62B?GHU8^8s)!;ObTc2%VrXRN8J-}5W|<)HX_e7FZ6%E$pK41M)1Mre2Cn?)}XV8C_88l63cag#dLG~w- zOoy9BpF~GfuF~H?Q)iWKSEG!!jRu$LjqWlXz)5yRz5(n?WXp=&M!s+ml23(K4W+_x z4$4yEi$t}eL?K}`XXroV3y$AyYFhk(OfKErU9&l6>Q~V8!f5ddmli`YlS_}3gv=6S zG6_lg8gT>~V?I$3_>HLT1}NT@1gR9jW=}3P5#xjkpn_Dsr@zwk!x!&;lhMEfM#$&@ z@4|o6X-gc$2q^}~_@i#2eZ2Qb@-%D#iM=Ta<4DQp3rMsFwh=uJZ(h4K&6{cAq@z6} z5Gf0x{u8j|jj~z4k=?1aFf+WBGxp7yvD1vLWz>W*p6k)qlwxWgO`WANCb*;gG@~Y$ z@y474#}dOLk$mxIJgbbCZ1h>WPPW1b@0DXP$tmu|JIH~4&{>d-W2JP1lc{`sSizEF zAgiZbUI`m;N0)lYq-`VX(aF!}i(VHV8JNzL_#QWK$G>^q=x!a>dVl~rBG<`^xpv6t zMtiz41DDg|Bbgr4%<4*E+Aee|5(Xjs%|^1&7cgXU&L~;9CnMWK4jnL}^|Hlx5_#~e zi4v5V+uZEY!$%J<9zMEw^zbY)&egX&77yPsJ8$qYb$jc{IRhkY#*_1KdMb&k`QPsj z=%>#_*R<}qAZZYEnfIeUTq-8$CaDzOO5ih!7Zq^!;{e=2ex=e!3I?2ZAjlH4)O=)` zdvNRZkwog93DyxLL^6d*%x7xs8H9FMBk(D5DpnB?L|Sb6zzIl;KqSbE$fDXZm;qc3 z#q-aM3<(e<9W5es?6)GgnjGeS$Hkc>4m(UWO@|TJLAMbL2}n|>BoI0VjtXtD+VXnIv73p`vVmmTx;A(L|mIPu^} z@$l_f(Ku(;tMTiR;?cwS4u_=r^$5QqDsF$ht?*=Fh^S!aa|aLdA1e|r;fPj<{0zvj z86k2yjV>!hPTvJxtTsv4MSYYsgV^N83~y@#Skq556a%|@f9p{ zrckwP_JZ{tnplNo@JqHiO<|qvkd+tEB8TimcB@di?+g*+H5@s_@c>94zuWcK3nEI6 zdN^f;Gjns)N0A4Q+<3x@ydCbF0kSih4R4OSF(E_t-n3e)6D5=wrE+UCzk;{-Lr6pn z>z(u0BS%R6;PVKB&dU0DX02ZMmj9_tkK<(+VGtR%e;6Gn0~X@dklTt^^}uQW+tY*g z#B<0*&J42TnoJNro?h9BApC<-D$bGDEFQjd@$eC);_%yD{5CK0u9(${9)lV*q6OlJ zL&s3GIW|R0S+pfC)??{mv4&HR1>(o82>zy+s}=rV2CHvI_*YUalCV{Ltrg>yU{NcM zPQb$b*_iwI`G5*fP^m{AjP=m!v^}~*b3C=zov5Dm;iXNKNt`(jd>$`1Ydi0i#GKo< zEv=5_iz51Mx7Zfqx2*%v%i=5HeWl8Y1Oyzi4yvx>Wad9fLwF*w*KY;hIUb>>5-{g5_`G3ZBog7sKV(cs|6q5fE97@; z`=o_Z0Om~Hf}FqWhAh1Rn<_Df7#qiU46H*x;Z6tCHI;$mdww6L6%QBM79NzPDiSwW z4+((6fyOA){5A8{S&3MQ?l5(e|sQ3i?F|29n3|^l;E(;Vl6;8EG_<@Wv*?KvT(e%$!2n?6`;!)9x^-68ne7 z41Jh}`O-jZlfqn-+~kruB~g6n+fNa)euq1A$;>D!b56tqG;;i74wIVS`D@s7)a3f5 zql2SXy)na2juw3N0J+Q_v^PaYr?-bQy`?2^mOJV6;`rdmnfU5t`Dqd)`Niq6Iz6PXvAX(ZIno(FJEOE8{q{lb1C#cOba0AN`Fb7AO!2Ooc9Imi#yKkI z`d){}Q^EP~&c%Zp_hUvRm(#%3DbCBYLdVhc&IvWW8%-U5`ZgJ4Gf}^J6**Apv$-hB zMx44X2ky3Oe_}e_JxHg`N{KAdK9CUYnyg4kQSQet66JnuddmIug;MSgO}R}XEtib9 zP9%48NSv4ed6}wY9iuZtfLY7(^uNKDdW%=S$4NfTY-vboLV5!amzW|2nSIfULhEE3 z+1VWHEffm3cqg#aq`IN=M^%dP1|+1FV6v6TcCL)ol$aRU(&kcf|JZEz^h0N08DsQE zu@S4bbh;bAmg@an2v<@ICwHLD;p_|pqR<0Vih+T230?8OC-lGkoT-G95$ULkqngO8 zrXQ(|48sPmDf|#f#Xw6XhCluFH-V_Pf6<)_%uY-X1oGtQ_DLM3GsElHqjRi zvn^T^J;`RYZzYS+c`M&X0MpwUZ??}o#6@*F28SPQGNN-3G8tFBjg_XWCfT>mn#5U} ztdAmfR)p^cGcIsJ1@X{`FpxxAgK5(U&Wu9Extn6JHeKX zOobQ3C|77#$FcE_bDEoGMlvgtEN5)x(=TE~rw_VWmtV6yv>8kK2ORFpUn)E9Mm~Q< z*MXdg&DVtOw{16`ok;)?ADwL>Z2!Y4w)esIk7|pP71f+VXk;Xs%Ca9X=ztVV+##pW z2GwWHS7q%WV%nwe4NZR=Xp3WNG-_p;00dR55n(fcVpN2X_Hp9wj0$tAssV%wf@w}T zTzp8~c7L@t7;uN%;NU?MW1g3jqM~%DnvVb%)!jT}G9{%R`P9IHWD|JNQEx$`%4nqa z1;L$KQOt`fZVuIsx_ONyq9S|R@+)qRC|T>_26nDYK65rbWi;HB89Z&UWzD_O2jH$l zKe;YW7AoQq`N0Elb7<ak`}movr86BB3J+}m#> z))iHT<=)=SpPl5R(L@=OdwX2wmu~KEpE*YOgJ|kd z*T0(+O6H|Qa?iNCXk0$QfY!R%K+UW~373t_RHU*SgKS>~UC&j{hchZhr?1HebG9+Z z-|LMV$zinjW*E(3)?Ef5gHrgfn9(|mwpZX_Nm-oUt(fGvybG7>9C)T>Nm zBLkYF4I<|u8vP#gWp!rRO1IsF-mPlcCUY&9xec(AD_@o17<6}4;?Kw$W#6*oJPtoO=p@2q2sMmAQ- z3U|`d7z4V{nrbgaw}6LE8#obmYXJSbkELOnO&R zlr~JgjbEL%U(d81zbkPx*_HOV+~aha4~}9o3r=Q}+_@u91s|r#S#ZAk&BwSCBVF;g zMLNGaZC^e;(u)S^B6vLb&~n#|GiW}SsHJ5A=2xfftELAS!9^_$oc^+~Bs)-^ZvGKR zl&6%VTZe75#5vR+&g2-^pxt68eA{lW_h9myQD}ZX4W?CSPOo97Ic1Zoxe;U?L}r^n z@>_@_%S;_w!o?mc@1utVBRaHfhO%^1s;-dVpJN-0blEELs5pG3%H^FeiVZj7x~d!3t3C`mGQKVkL=_I7>E z0P?ai5R>Ro5ED)#6neqFiazmH7)5e|giz4)%a$B%33G^gqw-cBeZ&2alne3-vu!ZT zXuY}IMqNS7OIOA=9=}eH^mTP9!=CCQSMkR}PDJW<=oN6ujFTw1xVLGeP7Lx-n=oDmX^CUuS%Y8_2eUMLx5 zGr1ryAL<;GslvQg$^9Yp%|3{73_l z+iV<^7F~|(sapY6%&^(iv9(hMn;b6}lxvjzt8k+3LE{Q#z>N@^M@EuO8BXp<`{)al zh>qOA5VMm{D=BY%))+6V z+Wa0-rBs_6@_5_<{r7XR>#98Y$*-RgoR6kWj>hx9(A3d*h9$o~Ex${t@biPwP;6Fsfo;{wZvi)rQ!C@`*tl`Y)%kdrx$+Q4!#Yy29@o~^!qr*>|L^h02`_== z4qytL{+BeNzibNb#52XBSEB2L31;MB9CLR_72^*~D*^-HMj@>yp@ zRof+D$@q4o{A$f}k?gi8x|>O3lq&$DMIZlj^j)JCn+~Y`Y(jO-raER7W@wZSlty)2 z^gH1qaKFf7JIKAX>%q~}&AX^l6An*=%#NK(vt-6%j;8KCWK$F+S|Ilod$R`n(X3G) zzGdi(v{E&RBiN~qApK78-RM-4VLJFDwuR{6pL2Ea`0OJri9o^Tmc!DK3v~btiZU)~ zSV5}$vOy#j6C?wKh$!)H2GOGNv)tR;^&&X3M3Fasw*duPbL-4=Hhdz6s}?(xsz3Rts%gY$FzCC!;ID8$l1P{?{VeN?Ex zK~=D^x>ZLx$|WrhxaaFQ&r3=KKHQm|a4l$4u`hjZ7!%<#%vxuVXkkoIJTB^-b0Zc8V#ezyyj zoCW%xOzY7~rBV1f9++q*u3tLhI{;^=o5<5VMdXWE0qY9zBvIf#rC2Z=tCb143U!cY za{0w72N$b5yJ>$A0FT?W>qqg@`TA}68*k%^*r?x*&*|OykL>Jou~k2ZmUy+tf1Lcl z`WhaX9sTs{;0G~mSS~9~sZ`}DYz7@tA_38KZS&)or05ld0K@yZ)C;$bAx?#oF_hTO zN=4Nezk&P7lW4r@e_s3}rdF~n>xIG;(jp7@D8a$N4({)PehH8W>Ac!~y}7l8_4!5I zrY+~+UD0BS#v$jEUKC#ZBU%5fj6=yZM7aFZ=RHDmMbJkx4C9EP{li$qNTaK=RB+b$ zCo_GH7fggg1k-yQ!Svj*pfi^&esWi#y_@3CuoQnm%_)&teUVvNybTjyo8eptxIC`4 zBJMdF-AcsY1v)N@MEsh?Z7wY)l8A9NS-nQySs!Og9;QT~eN{rRs<{uOxZPXwr3;0Jk&2G1$iLd_4NOTT>kSZ-96Ps!}2;jaD2iq}hW9tvz?};A~+zsQ3(d;5MmVfOrA+ zv}LJwsoyuZ45A0rOQ#)$x4R20Q;e(Z(7%3w{c|^dlb=cwNU1`0@xu|n*3S)-TcUvqv zy&TB&lFKA=FCE7f4u1m1^|MP1OjwbF;btvi6hWLB4B)}W`{M~Lj@N8z{;b(y=YP3- zowYo6)l^3SO|5l2FgcO>kUQIoDh z{-C}ASm!lBW`NIlg&ktRunYP;M+gC9LMr;?l)e>MRh@)$2R;P6t({KD7~nk*>J)Ng z-TG^uTObnL_BTZ{?X@|%m6yvTBE23#*c&TMdumdaS-h0QzO?Uu(jblAo9(7if0_^@ zxRna7*{8`$OCHU{M>aWV>Y(6{5pD7Ot{ur8$35_|o=wAHL*vTCv_B{8+Ck>;Oo-8}yot6_kFevv~BFpzobFpzyT6Q?e{VcLq= zIz|vU$pB{56bJo^o!l_j=;R#q$uaoM39kM+nqCkGrLI?;1Ou5^-pQS0p-+sNfy+YD z;A7((OvpmTiCKtVw*jvCV*oP9HRh?qHTDs&MngCN;k;3@PTYI$rJVnVgE;Q3v;sCc zqkLry)^Zr-8)$k#jB?8alg{$SF7n2ojse=`4QcSD@eL;Ajk`9*8;(m+snf~kbkpu( zTw+x;MWz6fmh^cWiCu-*I7^n%!~n7_?s=bvS| zE68;39s|G2bkg9d@eM{Y-Ds=1ek1q%EsFwU;RX87CV`B6%O|JL~T4B!5SyqdE9CPu-Givs0?k<#P|8vY^| z4M%g(Fyo>Drxt*0>D!><>*J>=sQBvm_bwO}bSdv~ap5q+b%iuPTj{Ryg?FeD&Q60@ zWE%Lj?J+LeQ13Bx!YjLOesW{3_6qD3I!n!PQ6FK0+Ks2cDje4hAdu~D%fWYw?K(Kr zUJWRpgza7`eWi_~!Ig+g^yA-4<9f7=#L#sSjn~)z(`X*rh2#NVH=~cS%*Dxrcsm2~ z4Rub;dG6-M)&B##mY~VW{TT_8lOi{4<;%uBPAI%(fV89NSU&*|U;RPi6Exs~lt*n_ zI&4n9bPK`&)((pA;RYeMxWoAg(a%GogGWqSzCN0&SR{xgmte?vO@A$H_M2)rQ?{1*!HK~%r!)~J4Et+5%VyG5j?MOx z+v;A}lTgG3fg;d$GeLNhLOht5bn=D_!4uwox0JyEA-iqn3xcz890{QUQxpSdph-NV z++?DgJS~0J4`uTx@Nk()7}6oFqIdra>uO4ELKSgW{i(Cv5yG1&cWLTb#?KF6lGXKn zQ?0IV8HMcAKaP~H`+Em~CtOzR+>;GW5=i2zLjn`gJsY9&iCk7Vs}h@}up)yuj(%yv zhEc8EZ}4(5b5AV;J)NKnGD^~=y%$7998I{<)FDZoaa$Uma%$8C+g2dO)!hLy`7oVA ztKVG4c|AspRdGi05t2>i0&m2RwJ1SA87UX#a`g5tZZX3l09Em2Xyn<+c+DR^mE5KP z0Z0xcmMb-s1}ex91CXjBGN06e{P6uf+@3g|QV8T)S}~RjDM2gxVZI8K>tI;i89FqFvw*kv9$ef-Sylj61EZuV~u zc2TKK@v{MC8^1bW{POf*?6zyf=`RPCsRQ!AIX#TH$<~zJNJ7QKCB>9Wb+WndM8zqt zXhVjr_~x|y{PZ()nL%@YwCt>}v9p@ke+SLcI>)Y&C&m`Y7U*&N&`hb^906yr1qbT6I%p$nGD7R__y(8AeYP*pd9 z)^TPXdsNsu!_5jOGh~lOclywntyj)QRyF&n31QVoln5=h!{-3rgm6WR{LR=#uO`15 zx~0s(BL)Rb(WB5??Kk|c!MZ^o$~cB%K!xV?9WpjH-!hrTYp0sVU72YlCf+d=MM};P z&8^KZNw&PMslDbM^p1M3@@^}*CZ1LMZHDp%_M)Z-OurGcyGTaPQfA7Dk@L1T%0tO@ zzDQl_;0zM0ZTjA9!*4EE{aMr|=RpYwoIVQuAvIVpB%Yr@i9smlC=}6JZ?^lWE}@Dw z7-~oJ*0L`T9|Q|R4a1zm3mYimiSL?sO&Iug_t+%%1SzfSIAN!uAYwhCE z_4OIB6T1HTqfoUOy1*&L;mL1OE}!*{BbB zr<-@;?;?mgP}ZvcA%F!T^c4Din^ho|eG!ho@^jWCQ~vXQm> z$@`?2SX#;$n24DYS&^moWGbT!>}-RHtmx*J6fjm8i%YGg_7L-nzCJk{Q?#xWBv zdoG5y673_P!bRGtPL7gjr(X^J;PN+T<&{gwobIL58R7%`5>zw#8K8(5`C;`psepu= zJW#l&(m;cy@)m~*`Eb&hT0mA@71J*qFJmq8^4ALLADJq-KB_e~;8gOob}61E zR6tY}7IEAFHwdaTyALn*VSxd`Cs#ZE3Obrn>irg)I#O@wtrCvh8*8u+2vM^^&~~xaYghcJhO^>{(s|uz03F%$H^9{;l7&0=Odtz) z@ui7!ug1v2ZRlu9S$GYaURqfgkj+R6k%cENoCy-qlqK+FqDcT6Dw>uY!&2M~j&)fy z8sXf0vC@w47j=2&){h-29=&ZosReZ*UD!ol1d%S%BCm~H=@n29J_=YN^WjP!yaCUn1ovhb zx$La=QfI#$WN20JES0cOkSliYGsU_l9*4_h?HHGgY|b2Z9<_Y*${9J($#9MPfu7ZZ zV=ypS3VjS!f!f_@VlW7RGv)btxDB~>hXSC3GB1*6D0awo&nRP^QapF&VP(g`ZziWK`dLNkIKRo78! zk7DAXnuBet_OEEZ&}g@Dkqxes>_g4sb+K4O@F4rF+y^5VWj(74-f|!QWLyWXGBgl~ zVVVc3b1}~YA3dfMqwXJ@m>N$&Wazl(Ht)byrhd=>dhyDYAga}`55B$hDmwR` zgsT?{4kGdqe^Gr!|Cl%*=PUXkU%D9f(K9mhG+kZYEaz~_Pob$pnoHm-O4Dk?Xgo+h z$q`q`_PQ{EB^^vEvT}IF$t$^{T(*+U?u`10)59<4QrRUF^PQQyWf}R(jKFky&GNDX z7cy-`t{RxO;+xa*H>ZbZrxDf3zMq9-GLuwzz$gG%vo>gW`YYPSj>vArYI)cuumjU; zj(>IjC1u^Hm|~&Y#V% z)0Sn8KojY@+6N>O1qoX+GDG;VlY6|GPx4!#3E7L9s>rQX=CD!f?ACvJ%Zt>nxp|F$ zm|3e+s|sIXN8?q6uVuzdZz*n3fLvAK&(O`3s>0u*sk0wld{yBeQB@#bMOFCB-_Zq? z2)#EORG@^ss>rrw#XjTZImK(y8RX{JqTA=hLC{8!h`+FnGmozQrcK5sK1Qc z+f4N(ZL`5H1k~6Af^HYH!>I~LaV5Xhw&PskcE@z{cQ)Xc?@g zW3`aCM{XU-__sZ1M)O7X69QFPYG`%2t z>>oDEd;+yE@!HHG_GH3N_{$M?iM#sq&_|9RKknV)y`_sn%p%^XQ5mV05oUaKcqBIE zSzbU`K;5hXW}h!S+;6c;?Y)#eOWwU}l>m7g)lBRc5{VvQR*)9wQn7FXN*DF2lP$m8TJ09KI|x)hjl+N^_{IH5VKtP*`?*`Uknb%lb$&b@0W zY+r%U>_;eTNkw+xWs%zQIj}G9d`uyV*nQ}nF1Y))4if-?utGW74oJFa>1kvNboNu3tZ9M>W;DFka9OBT& zI|k2&U|Y|OnmLwnbW8klRYbCclt>to$R?|nme)%>CXGvN>hA?|>Q^xLB7W)67jZ8Q zUL&CDHEhi}0ff{!4);Jmw$i)`0viCs-9ZyCM}3ZmcGONhSV-UlnRcW1PUCaoNG>G| z_6;HjPmlbl9Yf+5|1uT7h`-AmDv+cPdITVHscdMs{yVhrg5nx6BH7{xxL<(Jvb7{-IP%OtdVW5_yp2LUOCA`yyi)Cd4?n zuEy`NA_Q~rYj7oSVMlhffZIL=E%!XM@ePuKW!MZ(7^ zcK%?DxI}~c=h^*DCqKsbjR;YvKNDAcyicwfGpS5AT`BuG0s60}0{W9K5RhYu_4P_{ zkee)Iq()}1H1{Q{Ei-khK|NCUg3KZ@XIABRtQ~WI@bKR((q;6I{AyoFs;4aA;S;k2 zr^Fk&5M&R!vrFFW+U%3+er_E9U{jUnQxJ5TavpI%M#2!(sPKW(|qdb&8*>{}5I@%z#${ zh4nizUR3}4>Inx|Ph6LeJmeP@e7t z(9>@4F0K{!n;m?)LJf#J3R`FJwV=P^8drSV+iO=!JlM})G4OV1e_b3cxn`x^?lGCk z`SF1*@!kjlImGlzYtX@(8+fvh$M`!XUKzlI9dvoUdJ;5L3Qvi=QWBd5z+*(+fJc|) z!JckFZ%(O!WGSHU^0-j*8}{q=_-f?V_DakN>PP0K?eX?%u-soofBSgBGO&g>5b3Cn*0**>BPbJxQBi`Nbtt{TPh@vhV@eS!8OX9pQ)u2u`f-W#lP%FKS z_)3Lor1@jlgW0)uINL;8nI8)boU z)R>De4_X`XwJ6ksDgh;Ev{aB=735t34?Cb+tzeqKNLU50;wsp+joOZQpWpAbOUa}7 za$XU;w~8FCl4U_4RvwrglO0|uPlUNi{^XImU9z;+BuiZdYrh=@CAXz;Nu^gh8%CjG z(JN8(E20kq6VXuaG)n`^Y!4^;L9 z@iyK8xDoG(nm!iV+xuA85fF8)d{@AP5% zUQ)qZXG#Hd@J0!m7X__=eKmU~$(eeg#M=3IYtTBoflHs_T}qr_{el&7hpimNF7U$1?&{<&@V_F4X^UyeVk{PT^i`19BN^Sk`vclhTa zZi6TJ=f7>opU?2mPvbW9`ak2JH}Hph`A0TT*)wnDV6*)59rOgU3}XE{df8ZuMY-j~ z>2@Cbta28YT@UnZx(pjfO%d(JTKrqT_r={i9#wh(QCu`lqGU~CJ~CK&rHKMBTopSqAyO5ZAs(aEVW#=4mb zW2~d7+>~^@DvZe|!5H1Sf-$jz>YrmXmanaEVKY{6tsfBz2vYaD>sAdiFyxwjCI~zZa1tbkXQF-9@@8er+VCNMwLd_r25BBi|SU8n=i@srGJ5f zgUtgs4AJq3EX)cHt*8|V1!Ctt`uY3l-3>wT2ewA<*?1TN5k?P0D;5?bJZfOOm$;AT z;E386ts|t=G>@&)Q`K zDxl5t=PN_``ueZnyd)wZwxAa1LDJ}fFPr)mp)Cc7jcX zTE4yLS6iL$?2LbF=kZQD*xbmSYS!9~yx$4d;EjB-R4Fw4YUj~Ty0|7-U#b@T)Ase^ z`r?M-#z#9rD%WZ?N^|WNx@9+OONAzy1RL{}T(gOX_pWCNU!Mb$zpBMpKP?NRlhNLs@6C$S*!b1zm};lwTiWBCSNIG z2E88wSk1|HVLsbvwmQK&8R+N*!G?Mc@M(35YlF=*7NEto?YUw~0o6dMxDB8wUh-(C zxE=ppj{mN}e^=qZ=M%aw2-d#h@SS#1d-bA<-r08X`r_u|SaC=3hNBl2cNW(cZ)E?$ zHV)S+Rhn77p&MGc#)2Pi=fIJJ^?-b-&?#QWF>W?}>#;7t8g3bO4KFM1>($5F;A;PL z-OsmXFp>{Q<^96U+|rEf&EuWm%AUVsN{?ew#TPf-DFoMKv))YGL57S)hN%t_u|J4k z7F^N0VMopShNJ5utG@^1-^=~lS3Jatv@wzW!Nw+50^IAOfHZzw-zv3$u7;M1>w_Bw zaSv<6z0)ABm&QhqdsulTN0e4m-yf`d$Un`^8@k;aJ3_UX_#9E9ICi{v!}0c9t}ht4 z)>*v%sCr#6YLl#NGtfA<(8$$`&H|>t2;T89Sb*=5PVTtRYqsn4TBFtUa^9&@!S@=u z>H>b8_v#JbQfR$V%ljnzRIXa^a+ON$RMTtKyty`*iMLp5_+GxYSg-h}J$Fyghi>Q1 zH)@MstLQIIq?T%JuL-JcmB2l`st*o;xioUZ0=!xS{V&uSrB-nfV-#~O59FAt)>>YA z$#0E&xs$n4B{#H-kr2zyLWpfEWB!(&HK4l8-t}= z#YU~YP~?QYSumFwa0&0$VyjhePEAhQRb>^g$<`VRlRNZl2WMx@vd2?u`Xw%;=FOKX z6}6y+T-}>nQg8%E1n3Dhz5@(u0MK4K=VAL=*oSd|+}pj|!i1~LdG`xM~t-9dQMF0>d zV~Qf_h2RBAuQ_9Wi#ujA{eCm(w*{JA2zCsCkIoqJb#1mB*BjMt2*O0L?D@YGZhH42$K+8NbpyE!>$m(!vIU~01 z9E(qi3<**epoPxS3+y&Mu=*74KsdUqj~j6v99$U}Fnc=HkCi<2#19W(CC(&&dN?#7 z7(?{FAnWuHS*D*T;2K(e*nrA6V(P!!mE zv382wmg**iW~=By`ZrT;YPTXXv}jdK+Phs;P_I&&YhXC7)+_{HYts(d>2D9e_h#oV zcXn=nusL4?=%FYz96qHC52{@o^SOFVCktMDTdrBk6VQ;AIcO-cUE_X0a^`c`$a?9t zU-3@nDs9*uqC_q%zkRsuKOKJApVJ6?HJ1HZ(Z;q`N-gL(m6^FpEq}sU_H+pv*$(eE z(WG*+z}j3HN~uzrApDgH1XZU&{1SZAn5C>Bs9ps>o1%(xKr|V@mIa*BV`F0}QMCD zJeAtv9pWT~#)t{n^PCz4j9T`-FvBs;(6XeoR@V+-{o@)P&IA1!1-hak(88CR38qZ2 z`SfCCs#(v`Rk4Zu)^D7|pX=vq^j@3|HdSDov_bqG*yy4FcY&}iW3SQyg6Cd&#XntYwn)qoH6FBC@kJv9n*xeW*%mjmlg&< z`w6BKjWUX`u?6rt;R9pi+0@;&Q$A%LhljLl_^{2;Zvi7?3N5^ke+r$MT!XRw^z`|I)Jdkvh~0_VKAF z-eY(2sVClhelJ(JmsWU}FU58aFTai2vfEI)$ncG)a*Zk|!N3hAGKaGZxB z4^xunymg*fj~3hw>D=60!#`QdwUoaCSUfJs3r|I)k@YdKQRpq{YJUGX^aJg`5YhlW zi-vnDr^sAfRbV6q`WUFwHoV%Ysxe?ZaS*|+LpA}$if$Eg>X17LUugm(xLFG4-Kt%`5C2?E|4W{zW7z!6d)A0E*>~T=e zD8LbCspE1FNhA~Nf1uMsW(3Mu2(C#$?B%V%BG>NSy;opgaQgqo<*(q4=LD5GYw6nU zHNiy?X$27G%xMs#!-Rrs6RA_dZ-3DX{n+JK5K?rnFT}j)y}&x12-bA4PUaJ=ZMF&s zcHlF^`T4FMMYYK*?kqouu9Do@;(e zWE@LezL6;$vKH09GppZ4Ozdq1(lzbKH@dR~g8H1K?(?i4wTkYjB3%D1&Mh%@h8i5_ZS**1YtI6f_ zK4JyL4P#%|8n6&r&{}M-^fk2e423jz?}k=E7Z(@+sIm;c59a7qM21C+NT!O~I-xFb1H> z=pULs!(1&NJCKI2A@2-Yv$JZ|GggG)c{*2V)*vm7foWE0 z4VYOlZ^U=N@Hs+gb9y2tb92;gB!NT3qsS2P07FP3p`i$A7^WC+fCsiiwF&rxo|k62HMe7OAYe0yh^!wV~3N1Skai_fe46})Lx+sk`lkD1veal~@Ey%;*&&`NCA zB)2#S>U7#Q*9Y9WUZt!tgJ>Zt%Y4fZJMWfvaC*uPyR@r;Gvdy~Wu(h<=yWIp?0R%G zlmS+*u}jzfnncs#?XPm1?RzXLW^>)|BE?^R{ZM;oXT`B86iP{EB;jUQIS6WhaIvIQ zmgst$sUW`KP_r==_Xn59UYbEva?yEn`ag zpJQY}BC(;4zFW9wn4d(W2qF-nPGo^GL97OLSgRTJ9;`Q|w0dEZ9;~fa3GXZ07BfdM zlV5=~hpk;AwgQ+jc(gK0B)Tx)W-}91Dny)`h4~pBO`cKmDkYT4Q1m(kZC&^T+0lTb zJ9>v$zkYHV5vp4W42j=cDG!p`yC0F^g^TtIK7rUSI#%06_eb{YfqBx7fwx5WlZ zRssUPy|c{Oi4yR(bBiB1>xu)g+)Kp6MH%B90=KA$e?Ql(MSNESXT%>&gyaY!{s#oQ z{Wrq;Si431htPCn5#PP2n24XYTb@Yp)3JWb6=G563y8Hz22ulJUQ5NechA`6=yGI^1D3Sr3{vubEp>}K8>1gIE>ImGr) z!7Sp*2^uy!TZWdFIIE)8NGMOm$Hq`(6Czprw3I1R?P_=@I@4lr0+tfyLU$RxSZao} zXPBZLPEk^~8ka4WkfQvPXiVk&Sr6Vx+Df&g?6ZNP-P19Ov+QPEZkQ^?Im21OhB z7zl_WVbJIgW=OtDSFKuJzR0xrtX2%l4?Bnx+_rM8(TqJ*6Mi29Xr^(o$nJ0%4$JsM zzU6TF1e(|BxLut=b;t~%Iyl1{CF0W<98BCg-h(}(Qi~EYR-I6D%h;W8Qgyqg-JP;q z{!7lsQ8Co~lG%czVl04@d{UNFeggj(wh&hKPPBh)8axP$%awG zCc4cIC9YW;rNr`E9UKa-?#uKQ2`mIx_K^zC5SwB{^e1-8My+XaUevUv?+4nRmoTd< zVVuqB+W(06>arfP$n1OWwS&#ax>tm{~UxdMK#4_zT;?$ zE%2R#vZ`cFaSwRVDrt)6*@w*iB`)mLmrld)RVb_*7B9;Ozhg#@+ocmY56zUVC78J#}S{oS_9F; z!XO1hIn>-1{WX0!Vx5lRC{%7-Ih@6G5$0oOPT?37k~-&e%_2_-i}s%80j3&`AdP!W zhOFf32vRaNR6?0lj*;cqDng^p=MeA2zb1_tN+nAyC}-%tbo``U zk?o-90v7Z|ebuVABx3j+|N%sGTpK#?yCiVVfJ6*eU!pc7>y0)}imx!F-V zal&jC9jBW{db>^I53WO$v6;!?|4g970Taf_GA3oJ=@6L5HxpAWEx8dKk6>hTjzEu$ zlt^dfYdNAlRgrg zjtibhkUT_tx?_kpL&TX}Hwxm+0#XyUg(Q!@9@DlN7t@CzjvvyV8rCF`3K}>TEaw{N zW3i4aNV_@Kb3lZRhZjsa1F2)AiY8G4;@AqaGo{dz)R;05z?sB5P9yCTjpgTgdT<~_ z?eE5eQ_M+75@A)IT_6xG#3p#=Q8Gy&WJMGs2erO5wOA`m%`#^nRTO|p{BOoK!udV? z-mdr)DWt86>n^gc6IB+*I>qw@e7>89GM4H!9KYFZCkIiVf*xTHW<-w*t5cIq1O0`E zzLr7hi1`B+XH>>%G?ik<5I`4Z9!Ur--^EUql5ut4-Et;zBsPgC&(qlz7uJ`gv_J-% z+;x7CQ=@lHN?+LcE!DfYyK)23u6hv5>lG=-%<0`c>VcFm??ytfN#1_wtguxC3yS6bB;=0Jibt8OJA^tlZok-jYH_eUf(7psa|Mbv=6!N+F)I;u` zlwnD*8Ge_{o^LoNOabohzNk1mD?lM(Z`5x)AbC>^BoSN>t{vPjx=p}`5E5^T4HPAV zIPA5XgR^r*VlSXkIK07jF2dnE0JLF`{{4`h=OWw4)SY`DIUv% zA5<_J{-o|z&VNMfa4_iy;j9v}dSJb(9wBFWsINdto1$flnve+du&998#2l3}pVlu0 zJSqv9$(Yn(sYgJ0tYTBDf(eILf)SDI7d$Oc;u)&v2%JJ{|4B=b!;}$)VNm`sTihTi zx`vvUOT{REdyBHXnfS#+Iq7jPjh)rl-Ip%LI{}<0eaJZ*?XoX*>%%Q;f^|5zn|D%P zO)mTz6x+owA>}&n1ft5viecH}SE`5k@~@>x1X_pTCifNw0)E_(zF5 zm=3l;HN~MQRItGWf~}m7C<*dCast160qCa8^nOa!KVZK*%b&8{2XA|pxnbAF0t@^9@@d(lEV*hEMwFmB?AgCO|-;t(wVHJ_MSZ|mbr+CredgfO^hJ!aT9Uog0! z8ZCZBL`kv9&hiHQlce-Uv1^@bv_=}0*W(|PPKVllito!x%3J#WL_Nv88ZKZbJMO!H z@|E~GQohSs!S(oUnJeh8E{4kvu3l_cS|yyksroZ^1JywsmisRMX9B(im+4CG5Qy26 zCI1wy=T303`Ev&KsfxAkVu{v064%Hg#V^KY6vu7qD(F3w78F@S;SAL1F8@8I8BGx9 zQSrt z`TaXpl;y@m%Qg0;8Dw;#&Va9t4Hz{ITnibdDC+9NuM^!^LRec2i|8wf*rFH~Ic4}5 znmRVJ#)JM=a=CylRCwUyFKrxei!GCLQ-xm6NkIopy&f4E1#qJ0L?T0|Rfdf9z>2`^kl)YieKc1x ztb`x`FZMNv{5~2RFiJe5@#9}ZU(4jjpG4DVg8bHk2NK5Qfzum6A0cLaT_bX+{KheG zXf{O9I&26hXy;3QrO^MB_NI~j;W9isPl=~=L#J?qCwJQ=Rvj3HD z?=1fl|FL=-QN&JUu2xv;nkatWG6$^@m8WBdmr>aeKmPV0{~87aN~*T34^nc!wZmqNMASBzZe?85TA3)n z!09`5PH2qn;jCEV%toc?wyXnyj8ZfoyM09|`gt*m=9+ra>Lm`X@}*v6_zn)G$Z#Fs zad6^0W3z~o&S)yhf02bodvNzQf%x8wrYk2twYbnQ1iC1~dP|R)m0yX6J*mfTScH1w z`_+qjdc3o9ID8CgD&EInnrie|oeTFano8`lycOMn{8B^ox=FoCVLl+5SpJfd`+qO5 zmj4m|M2R|G{<8Bd*z$n7DnfXi#@)!X5MWPn5bsyctiTQwrmFLEQPk z8AS>9Tou9p!G#VI!Cy@T;b>go-_h4H4U^3qSAz?zNCf{&kJY z`yTzr-YaXWB8sjuRc%yMWfgk+J*1{vum>Yk(@ktNJT+aS&KZW~VO0=hA?W@goY-BX zOiW;X7%h@8k$h3ZnhO{S*2ygNZxypM7MgJ|BsZE>jg0>~geQV#(U$2z(wg8#SGTN2 zowmUSQ(n7{RRtU2u@^2{el5RBB+UI@t!31Ou_(1&MP3{4jy)S}GmlZ|7YT28a*_Vg ze7_WLXvccfzI1W5W}cb%*b~P?{bZhw#l5cp`)_L}Jt#tg()v=&GBsaYWdIcF*wBhcH7mt;(0f)?5JRE`EOhh>Hu>1j+Tbe{cv>RC++%r#+A!oCaC@` z8B{u!9D=I+e)cM{0N3jW)VR-9-=|kP3A2X3yMTpqrX8f4IhO2|8t3pN{q99 z1Wl9pXc#gjY3oSwhow<;5!Rv-^(nH3$WK^;{T{C1cb30`-&+0(qMX+i)#0+s-w4+2 zhJ<@>`)!Vbt1Ve`0y-XbSbntkhp^PBp~X$n(cW-gUD4jRpq+~LmLJ4C%Malr$_l3O zBq_jKel=bwZYV#(=A1_PHT>&8`4_*wsZ;(YcA*2g2BD*YTtg)g3~xmnax4^r$e~@F zxq5IYn`go85AoO);?t&vFK!`5%`Dt5jGQ=Tq(^TRW}ZE|WsQ79By=SxrG(gsaCyTf zjIVgbs&pS>@+S5?ti{6U)49lJFT@tD!$Oic15r<3dhtTMet}(g`FYaPv9La^Ra1$Z z;oKbd27x7J$Vi!JN_B*Z=8ZW{E2Del#LYu>A9wYdL z1gj=A6jkF{ib~^}>?V6hH0>k?XHX4;XFb6zqiNxeHKb7zwd9g(6^LX0BSvTKGG5ZQ zr1e_fC16q4W;)Wa-c*A+4)^kX@( zjI|0L@DF{f9Kwtwdqyl-@Piqv*e={=C2l}ZV>QD zJ)V;iJLWvDPA~>RO1d=m5E*(90V+a`W4RSS*GT#E^W^hr6k{e$x$~nb$vi-W;?%5( zbzrkwSsO4p4AyfySwXxYN_spz0q{NN?D8DN_9d}hjYfTLr6+ksfQX!NDBs4>l>FS@ z4LWC9hhx)B<1QLk|ZkPfAai8Kge*yz#6C+xo)%;x#Woe+l)eY_HO>-ZGoS~AqS+QA~ zXm5#)#*7Jswe|3}mbby*WfVH49;cIoKlfpa#N7ANxASDZM179wXA;p>IXLDgt4Np= z3h}@e7oLs=g+fzGLnV9=!sN{(!9)jo-yoaZ6&B)SS2v7$nQxATg>0bLfFj!siJoDj zNhfS%*j_>(y`oC*<4iSucaQ4O_kWEosXu)WPD6aJKrPyXi*yMD{$ptB5crU3h;a%Z z(-fWnEQhLX1nPTw%)7r|+2Ted0u@J%UJ{6vpsy4yom zt;4&I%d5#0{tSnApTd+}+Ut*IT!*IP&&oQw=$Mb)zM^!zs^Q&#<4}qa7>Gcio{$r1s^(QX7VG-hr?^iG4>haFbQNz3OJ_gg& zAN5$B3->OXO6<~vcV9O|uR1tF={-OlG2z{Ld39C8yGMaLE+O?tKmtOCckgDS0SbrX zeAwPYevzW0M0+j?-+3-@7~xw?1m9>Jpn$%Xsa-eF^jQd7;YjqXijyoW>2 zXRQ|#4qnYJLty;GD8P{Y{h(}GGUL&_l0X}2f0LQD4kR1v&IFQ^3d?Ll9hF7gLu-Tl z;e!wczdI5PW?^7{!nQD$>J<@ZUF%TQ+&v+l(45p}5yuQ%XpFU$l!unu=&m^&P;c%E z^TB}$@X4#|Yvpvj+?63m$>mjb*t}4JFNc@&>Kh%bclGorgFp4eyQNQ@4`2BNLXdvW z0%%14=T#1LB@cQl(mZiPZEI$(Qp=xkQlW!CJ9zLQYX~S8_>7^cwE1HSw?i9i_n0<> zZCG(i5+h+3AMEkgR4SXzdi&49Q8C8xhZC~T7_F%|?F@fmVMC506Rri5M z##l6<4R`(w-h7sC2h?z3nqE9+2#1kiqZ(0eko(g`dkZWqdq5ffO-ZH5dl zP2uAt|Ju&KPT9XsvFUPFE}0#F?hPy2oTdKfTE&FT#%X*V#u(HrZvn3f_Kh)H4Wy+B4lmhqv9gl%C%G zLnu6^>?(T+59G!UpK=lcto%~;+9T!U;utdYN;uh|-szEU;{F0QZN7$!xj%6+iK!;{ zqG^(a5#@Y3)#Pqzw3?|V#pSP{u>2MD=dR(hyHZVhZ}&5jYH}-<8g=@RA2t_jsL(*Do|#AdA78Ddu%bRfP=8=lP?vv{Ep9l< zgPY;vp5|EHFOD)xWA^_KHX1Xs1KfC3Vs(daw_O zzSi)wYV}#Q(4GOg8{L3h-=@9da9`xSl!~!I4dBGyz7(5ulqZbl{`)(DOSA``+NQDrbnUz@jdSq73lF!c0|+;5jNggf1Lob zR-99x?6FLDS16Np$nF2gtLIe6ZU2@iQT4|zu0s>(9yIDfpnTk)Kvy;7b}xrgG#3xK z9goc-x}wo2?jBiavjd7fmI0X+mxvAA(Y~8<|3Qkh?{nsQg())B`hoBBv)c?na)4Oz6E>zDr2` z5s-k;A-C^kqXBw@qs$pm#hIKdlJsY}gnp9rzb67^G`jw2^p#}hCeZb-q3O!$dNfJ; zlRc)}pV&W?2&fnti3t0#9{tDOGx0NG*(wu;jhE@Ix8Fm8_~Ix_G6eCrY&1MU>`&4e z7&K|Z4KG@8Tqy?MTwddFffrsh0>#UoeRcRfBOpfFvt(|nV`9dNGS+T#Bkh|uW`4LY z%koXX2;fq_=?VTNzG?aES@lip+Pw5FGkJM<&$N4Dx~FH_bh%=`^ySLaZTd@do=>kU z`i?}*9?2Db$aZzEoX0V6?CFTs=N`j%lw^xP4w=A1c6}>$LWiI#KgeEtIHA{Z@0ELb zy_2zw>dy9gT=lj2F)|#uze+F z9aSy3B<-*b=hfw~y%p_N(P7JJD2MHL^Dlli4qF`~F*qA_*BVTM3+*7<4CSspdKapW zH%fWQMzE*2BrTy(Y9M7CX9E{=)l$7(fxn5V2aX@+6@~f3Kt^0pDrW^%m;~6jcjQhT zkIZ}Z)Q#MV9>Tb+$MA|sB89bngqGM-) zI=ZSVIN>;b?D~kS=T^a2gQmiMftB1^@k?wp7!z`+__imiD|F76f1SIi>KA=4|5VY5 z?$aHEvn}0|92#rfN8uztt;aFA8AY79O0EsR-({mQ!{-5j9u8y2@Ov@&yO-8jD~@3O zw{ZaDm|jSd@cw4%m0VsGN{^k+NR$bGJdpUsDZpGyKGK2N}weMl$(U`#n=xdqG;9@jgIWxE> z3fKr-d-;I>L$))D#{Dfhea(=Iu(xgo9CPYltkwqgxuA8N{FZN(bx zC*-=zvSM4DQJI0$!TVwzL|Jy6B=u=ujw&qThM`sxGK%uzY;R2lL z&mB8I+3t5?SX(J1cr}WhFV+BJeGQk%wDfRS1d`lO@vbbCAwUh12I`SCYKz!k=ryHQ zDOW-8yNbG4eq~=+4$Z5SP9SFlB~3JuEIh44gmC#8yUJc3fY>fjNflsxw*w!*R)dAgXrIstql7tu?O!s{?L)*cig*g=H7jWkVwpjO1w7=}z5KOWYnWg6KCb#} z`HS^hBkb^zv3+~??aS=BDYHkClFhf9_KrQOT1Z+mGMI1MvyWNJx9zz}{j(nl%QjK@ zxxP$=AK2ty2YSR)lwG6iQ~NnKlJs!+f(`bqO#+1smL=%PZ^6Sn76rj8iP- zi|miF1m4$!i+FkUL$y#ce9N+F&z9EEX*bY$UpQbt9A^Hh7#oR7gDuX^8F{c#@1@hp zAICZwN+NJ%kq8&ZaKh<0KD*-MmSJ7i19i+4FODIV)8pTbGSwpQ(YEtEv|`M3=8>?n ztNJ0ZS>ENn@Z0J8f^AU=pST^-HU8Ffibx!o#Ni#q^C7gJ%SHjJsc~X)XNyawp%9PH zDp|QPLj1`nE8ZWhL!G6_4TxWYmQxq*l1ENnOX)N$tpvsd?Gl%Nvo;r4rd;fevOA@G ziD$LIK?}TD8?5I9Qu)Yi6r%(GP01yqD8`jB_jc33zvDhQfN;I3#=T=}K;Ku8{LiPkDQw8SL5X?eYHyglNSXI zr_^Lps5)dab*)?qzHVW_TaM43GYH_&;NBPsMQL!?kf>s~;Eo{>%NhKovB49WqM={T zSY*`gtAU^)-Nzv@9Nqso=sqJeN}l|SxYQete!yW9%J5FIJy}T2YvvoJddooAeH709 z)uRBiNQ3NQ+d^!R4@V5L9Ca0r&080h&I9h##D$A3JsmGiHHcRZf-^yJle&I<1nsE} zElbqIkWaCXVrijR!GAc&IBxB-XJDidN=3WoQOvWSa-an${jt$@bd9CrQ|3W%@$4)e z7X%vayq@jlYkrJVP`>6Z&btmxJU+@K4NWYeQIcbsexJ{2qv0c1&q;aTF*Scf6#39Q z%nE_r?dWYcsZ@A)mNo-T2DuMtD)wTpL$lGYro=*(t95AJqN6PAgc*5|9uI%aYJ=lI zD4XOR{ajwuM{e1PA(Q9KdKC6z%ifMH8_swPHuB2VYOUEhlVC>%n~D{=o3+__v~zTQ zu1Op*hGmE&Ar}nRmJ0jeN`up{d=c!+$lV{oR&&XdI&^)8y?w@^93UTV6N%jJ9_)Cq z#*{1^v@TU(r_I41q4b=P?O8@K)Vm?6|JW#0WIZvz>`WMOxIq=wf|CTaw|B~W7+g{j zOrJPZ;$22^H!9BHcsR?!Qt!|Lp*)IxYD`N)#5hFtVH~Sfm4A_o1yiAtvAugr4s-dX z7+9ilmQ}mA>NoX-FrWC%AK?~#EH;;@{2VQ?_8aIciT@=;**}G*BL~(J>o_~XcQ-RE z5e3}f+YaanzY0v`W{ILRNgH4k{0M;@-|&!}dwFV&F~iY+egH^8;O1P!&*9b3mk%0` z9FYkANl@}8p%P`Lz?Lw`?9pLgFg|q&NRp4w&Ki#kl1%*4N$t}QD_ks(&di~=Yzh=R z4t zMJc7KMa`1!+S6wDLF-!NH)7J-ADk}NU2L#)2<^`(R-A{>;0p)fqcc#~+#i6nv`XTt zG1;rQ9;Hh5XR^;vT=Zy6_6qd1OeT8+nvTq5%U=NS%d5dne+~T1?&NiF^QxPDdvbxH zH}V#;pwan-Xs8i%F5epNq)yiuoSJ7PeMV6k+{w35y1mM@P3;}z>269x z>KDB+I&nU()h2o@qdnrR4iuBQ&E>r~zu`QW#D#*> z?I#j9CoYZSTxgROE+JowPjonafM6*P*xjM^fuJhv`sOL`Hb0-E+^w}ydIiY|%&3s0 z0?9z2%N=a;KX6w>0nb{z^9JSS$Gp=v?xt5tWkY(C6fyHqK_*HT3_(B=6{)WID| zK&x-5e~dJZpE)=ITZ-0R+ocNB$I zd+(`3a@SlEb#6ROj@_LcW{`rlD>j!Xag3&5?Lc44^f~NB(`Qk^`Z$;acSV@bOmFtstjph(xFLO{sGa*ZJ$Fx$a>BHR@dlNtX5>CD<^B%L@HgC%7OZ zip^HuFRhYn>C!eaZ}^vO-h7Z^7*@yF!=!RPHIest_INy*nX&VP1oDd?t~E{|z44Uk zPZLnr^H3a}9%aKMoZq%BB%J>{m{Q1We;$^u>+hkJ~1=b%kho~5mUGh^ zemOYHz8bZYK6`7XBsoO%739`7kTshZm4&HfO=j8d$?m-=yT?R1Rj=OtlJM-^j*{od zf4jFd*T^-NvZ*8U-cqd{^I|ny?L3@YC8WC%Q;Ci81=>ojQeeWe8fhYxFZy_M3hBpF zv-n9))a2@=S;>u)oI6}@X!3%&bRw-OnU0h_>6XvX*gJIpk+@!c9-1qMCbcFcN+)8Z zBY@r=qll>1v)9pihr`_-4utn}2&M6)!cLqy{9tSjE75j-0DUb}+xZZh4$^kc$P1@( zjcVs?xxkXhaliak{pdRGC-{AE6+&OMoA;gLH1F(IGRAE0<_-!a9(E#l<^RPUS17T? zVIOZl~gfSdP`S=&0k*$ow{XSjzeJfc)s!P)t>hk)_9QTgBLTHirXX5V1IF)ADC( zr9vK=cj*3JXl>ov%4dfoa}B5hlHn;Pf`u#)Cp|Vc zmU@olQKqmK!G-&C&8CD|jXwwXITz_x(&0m5o<0woP3Z$z1z<=t5nR7~09F-xHLqoj z@}C})tPOR*SouM-)%=(_A$Xn$_Gh1=Gnwa!z)2=PM~Fbl6$pp*mkyf(T>gF}FC=CE zmj5eWK*s3NZAULYddbmCk8VGD+0o07KJVxiN3T43)zPbAg*)lMp=1hWG}D1^8aW-< zSfV}Bfu}zJ6$FO7c!u}hED;aw!CsCTs$JK@k6{cN2Ht8|6OpzY<$Z*yi}5kC;b2^3 zel?$~!+`;L+Jv{hQNmeRWc9*_VQgXMVBjRT-)zFBCG!*~3LP-BvyFC@Rw3v%uah_9B$=(mRnpMgceA7tV|}x;x;Z+{H5S^m%2OCM47D;B z<92vs^jWa+KDK@IwS%+S&bxMeX^s4knh_1RtNLx8qZwZZ6m~V^r@>-NbBH91ZFg)A zQT2K>|MZRMYnc|?el&Fy^q%)AucF2FpI{(_zF2HfTcjkLQddSLk7ss2@8xzS?dNg6 zFv!}vu)fp@24B*9k3cAj5w59e(;hgX9EC2eaY;D8h8mQ@+MXrq4ObW%;+ z7Z<9u*L1wrqUb%V#{``@b@8A0!YsSA3)4@WPM%oN!nQ^jvD0nW+#*R*hgQt8l`F$t zaJj>kDB8Lt%HdHuGPGyED{;Xt#~hd=^GUac5VA zbzYEl02AM`P(4a=VX!}=2!S2%57xFyb?2VS>2DKFsM+#iha-s-mp@9F1>Wz5Xe{bj zW|cXWQN2bA-#`nXYNH((2-viC!IeLc8Zgi@7HT!v_5~l;FV#?$gP|9Bn~IQhs}v@b z^T6RwIvH>S5bAU|iJbbRI+`ycw2!k}oCH1d4cLS}E*NdV#qSqNEnFdl{~tMgM>h2; z`0c5&$U$}<7d5p*jZ-}pVz=HPOeo8_%y0sIl#<9h2t6n!KY|4O)xvE=`1)YC zL#MwIV_;6rlHJ1-fe{He4o5Z4`2RaLet!jnW)~}*aK@slxjEEN59vAcjKe9ao*!Nf zBJClCK1=8*DRg-+>USpie-i;Yk|g?!K)C--B&d3Sg{CW(L}NWAQG~u?g6P=B3tY_D zWcZx}pZEq2C6H9VzbNnsUC+VzXq*y+JwglX)Y!0nXs5#9j#@Af zsVqtd=?Ce&y^0$VIg#Y~bt*?lN| z#dA!WjZ)y(8YtUUMe&7br6t`l3O1O+T=r1)b98l~;`#z0SAWwmW`dZMiDQ?#7$FMU z`qCm|LXL_S+zJ zwgA!ErJKQ6}Yka}s1Tsr=c-(Vam=yH$e&XE9qx(H@-*x$SYd zO)fzROXkP6mBwRdaQ1954 zk;13J#U|OOJ0Z&cWU`nBWkn$cDI~vi@X{Ral0+HJXhG5p^*@yM6wiOFhCrxP(9B5D zwTz;oPWcU}4`z#vrh_RYD@7}E3bbwB2iX?1Q{7jz8mAORjTTZx=(~#dJl-iE z0rbjCm`1aBFTQd@>MO7#A@yqv+#I^MB6?GIPKsUF`{9jFaRXizRVMM}5VK!C5@xgF z%W>O6w*G2ty~F74P+1o&mxpxWN&hqsl;QG7==T+G9?`}&{FcZ@U(BHbREyO(k-ybM zK9R6JcrlAC&}S2}R;jmexifb1Bji3Edp-%-tlM4g^xewW+++a?;jR-{IJQ8n6saeO zpet(Gm^>g@7C8`Bj^yU7JI5_PCuVZd~y4 zT&1m&ttzzzq_>d}SpNcUl&VRoQ?+zbX>LZfi9_(?*80nOvR{?bVyUG{64q*Q~_OH^vTcsY@V zLT;R-fXraG~3A?hzK3-w>n5A}n;d8kH|I0+{}Z!`qIVggo}42OE0P%m&$ z1*cSiqzL}nd_n%=*zWEzRaJ>ZD>=r8zOZ)k53^djn0>^`m!Ch`?1&_MeU|hPKrAK>R~Cpk>hB8olxOS z_`WlpH^-(EHF8F>lHP!>mg%p12bvDBlFrKSNf~Kw1(igMirY%plK{9c;QMenglO`# zVp~YIag+#^p}4+BlV4X}IVQ7qBvwMM(%pBcdX7pYQFe*ykSp+%4vvng;?GvmKq!## zL*?4i{L+m6H7rv`5}6#aM+f76B8G9%BVSi1kBy<9*K=;p06!ZWAd1p4P2L0(I4f5T z?FD&V7VX$h;>!mWzSt7n(_h$V)34Mq#UT@X#EjDhK9-g(_;c+AvP~9M)8=BND?`WT zo!f1J?_*l^Na@xn%3NP!e79P6>#>;*U^K#CZ27`ecSm7ywn8c2!VNM9apVl=CZz7M z84XTUmJmM;3$qS)X|z)w`cLmVy=!6@f8M3awJjyQx)gmC8m65fI)6-t;&3Qrei|jn z9~)yCEc`L1@sw4=bEiv9K03`W91CA$dXxLIELbk00s(k`rpc)+;^+N0?Yl+SF4w&; z;b~&;OHS{yqEUKh`Sh@NQ!ah%aao`G)afPN08hI>L6Q_J?aiY|_R>tdj;kwCzWAU*I@f)p;d_L?R*nFg~fsg9VnnojO7o%V4< zf!3HK-Wc%;2%vcaW=2d~C`PaIXHM%?skP>7wML=&2*~QuM>2aK^)j;J9>48-v}bPy zM$r~a3BAd0=uLGu?~KRgSuEKv@UVc+%8$)ruI@jw=TV~3UWH;LG5eOgG`uE5XbAfS zRpt?|^h0pljSMycjMhsQKU+H15r`iyj}}B7vT7E5BreKS2v31AC;>@DU?q7!Ej5Y{ zuzweqfEO0{*~L;dJfn`?Sr;-8oJ z!|N00B|eGgyu?2*@gwTTd5Q0c{qqt(k3uEpCaZHu;wxtj%>IwV>`$t#9c)lJ;+^1| zCW{CeOwvp5HzpY_n^abQMx_{K@^Wao_d}hLr6PpA9Uenn0Tpavjywu{^Fp-F(F@#M zebx}1V7+K^_TEuOS*e`NA`cvoKElHSHW)gy;LxCdU=QuSnw5d{fW*sIu-6Ioe` zRUh{N%+(r2CZoY|fut>#yOTTMnr&P?HCOR%ka{({4Bc~oF^WIQy61Msyy~H&=vD-j zxTTUqcfh+J_phXP_1xoKG^TNdTMO5+;k+H?Cro@8RY;rDR&FS3gWcUdNkr2x95A0GW=`;7hNn^b}N?{&H{s4It4bcOS$e;ZB*e>YX3^t*V z(3DoTB@Byid-uHrs&^YkEPtw>-sQMfV(sAX@pkoZC&NL5N11>|C09T2$fH*MJ`YD1 z{>y-)WorLCfT<0|YUrERmjWD{h$6qkT_kU^nW6tVV+)jJh}jwAmQ+lKe%gR<4~mM% zvkTlCJC8}|Iw9iHhx6056Y9Sr5!=BN_bxJaixs1=0#Ek3Pqw|Y6jnIEvt&O`D8UJ}g@SohF< zhwn4V3hGNZ*k0Rol<52v@yUz|TnTIP>~(LK%GBmF+`x?4zznL635V3#BcV(a^olfQ zaHMPZrLln!FFNU45EEI>XG=910wb?ds(CD5R2%~6p znJsv3xIH&^GNVQ?YfS548i6d(dZW?~{q~d>gRz0kK;)6NCLmAR;sVap_$-gJEbMth3`|k% zLB+-Hz6~v36937;pSQ%i9SVOqmn8g&&vh{VJYlCH_;Xtne?IaMQUgvPqtdTP(IH80 zQOc*%L|Mx~@&{1;fJzs6LN`FDfJy)r2P$=zgUY`_9*=S$;^?I}eMrIphry53Uo$#! zXGUcx81mFzF$^p9tDxH(m5F97DxK(N)Tx0`cZr@ z=&v3%ZPcD(T8zG{1TTaLA_8Dm+}9JWiKU6txNg^ANfQA!WD9HmG>fju+co9{>n3av zBFoLo8r{K`Uyto$`N#3V-c7MJGEajSTb#)|UHw+9tD#VW;|ogMI2;t5@sg*$#etWZ z_+~Y6fY9mYPgXST$my^6jE2LlyP~)iHVTZmK^iP2LB`@qZ|QV{l}>RMKD2leR+=E5 zc01xpi9pwMA3?pj@bV-r`3j@nM0+>;xV?L5XG2r5u9NXlA2a2Al7v)zzTqzQQ*yp) z@k)f$(TI?mz6C7cUbVzM3XQAKf{XjQv>jfnuKy+cRfEGhW7 zHBCfT1LcBoqRz{u#La`l2I``A2tMS3u&AS{k;l~O)99LJf7UyK-`aKNq_88jm;6yF zOQ7V|k}=WYy{REK*<>2949VAJ3aKJeQJQUgT`k-?EW78V53;FR8FEW=CNT+%%-4#j zWQ>#rB))Q3NV6Syl(6p}ZU$g_^8i>==2P zp@4|I{E;J()2QnFit+_AW$hGG$&J_)15Y*{uBOxYPv!16;dM~Xf;$$C_^1tjSM0bFhR1rRcvJ&0OCbISJnK8N1Md^hvNjOB`XDDk<4r5 z86Kk-mM;M-Lb5{*bwcqoNSr<+yBE*?L_#1RTo#ZYiUB$F7iS<46x%a_5#iNM`KB*H za;0H<5s6@hd8DO`;IQ4hZ+Q;eu6A7x+o2rB%X1gUTdA?FgZMn)9RGa8Kim&+3W>p> z?*$Ggg}Fxd2v0}RJ5-W_omw~5eij##dn>ayT4lC}ilm)r1HCPxbS0>>FSF|GgNwBq zjyaGu!5BkoBoED)VR+C%T~t{J)5g;fR|W}#m3I_!mW7cx3q7?3+d@>$d_>g@{#hh0 zv`Gz7Ii)J0LQk@i$!ce3{gWkOHPGQjpF0IDPL-mv?h+(xosq&@HvH-mw~(ycQEE>Q`BkndtU%-x#Md_F(R0sr9-OOWs|zN^WV)Q~lsN zGv$qetT>7Lff*8{tY(u3^QHTjOqJ-0E)Oln0=@S;hFHI2KC~?`mH#B_I=je)l(9!P z8Q?kHJRa+2C@X|xixu**XL%Ezdg49NZFuU5_bz)QLe!4KHe?XJtSIAr@yS&Tjz^Tq zcOts%8X*k5qvRflM!Vv}`9fr(7HW}{ z*}tqk59-1Hc_vPuu@GETJy6G~@n{nJuuRwh;-3Q8Jpd+5?JU zF^Z69nwq|67D(UG6DOB;HFHSnhhvkDQsxT=4gg+oRlhkn!+a<<%utlexw(ObUifTI zmMjvCPfCNZy2A9Su&}R6iBZQvn)yb6V~I8?90b~o%IBV1ea3X!Muk2*rtjGdLnLRus_2p5Q1-s^0w z0-RTEK}L{_VHx10pHQHv#nRUFWaPA!JhlgKS8Eqf#z-4ApqaJg{tk6UK*j>BE3i!t zz)<0V3D_upqYnHM5(tp$QLlEuoalv5GyaeedjK znFYZu6FAV7H5DCof>3N8P?P1KHal89QmN8vym4KAVBtIpo=3rF4F#=H@+)ABNk&PS zdzV|a+`GO~VJHiz{8?ny#Io)j9v><>K}xZLFhQYw5zPLaq$%j%hRnG$>QIlIyXm)T z-?C1mvv(;Qe;3&;v>D`Dq0)?;K!ge(y;#l^jaU9SUP%be2|823Z{b*=cxQMbk3FI{ zts(Kub}5fyw+*W%904gXpp*Z8RdQ%q& z$((alxU1yIIOU1WH>~Cmwxb)$MtQ~OZWrwpQD+C=bT*?_72$tj5e%d^YF9Yo&JCYs ze4vG@A{b6=_Z<&G!91t7#nF5IIHvbR&#doet*?9qf_Q4yoa*nhfnpX#l(X`mvu|}y zeUsT}XXw9-4INdv-1F&!E4F?feJ%5V`j^nuIiTLN0`K4x>eu$H<7HRP;yd9r8pj$` z1_^qx`))9GTaD7v3;7+uJ)L{D<#~yFwv|7xQkC7!=xdpKb|soVyL{s50Gt|~JhTt%+Fz`4;@7%he;?R*|h^3YkCRa`&$PVT9 zN97ok>R=7!r>pxAAU7pqYOGX%HFi(Oj9u%h58kTO1sFFJ*02dQ!BZ023Z>~?{geur z307H$;|T4I`)Fn{*F51Dw71`aDjgY5RC|??ePFC*@5DIQW@YucLx6sgJ~xz#<)$4! z7TuT-y@LbVJCm^h%Y=rfbu+`v%xDzO7|&3sk%=z$GTqUXYsU`j7Y0s@Cufj~gEqk} zebZs5yr5fc3EGN(+RwM8`Y*gu)Z}zcLF0>DR@;zPUNaJ{(E0o-+d`br-xhH`Pu~Px z^g*1Ek$s>NNjF;IBos~@%;seX(5P@a0gQxe(ULuRQQ$^iG+$0F5X0~6hKj0VK1PB)* zE=Iy8%2^7z*+;?LpAk@#=4TbJXVHn+3ex&~3&%l(Ssd(1jwz&AAT&L$6wjviNop@5 zo!3u(4FJ#4N6Ho%wDUYtvV0G9$Wg%DLz8TA1f@yt8fvd1h09OI=GR}*WZ`m7wd)=> zQ%k0Su9m5@Jb|W;&azI%>3bJjpR4(H4z>Dt6{K$`^W-jxx|taXkCXPS(%rtnK{-#O*j?)E-+fWUkB0r>gYD&#YdzGZZxYw@Ze(QErlVnNtUH3eA-|=0{ zb4Iy7oh@NARLeg_AS#M!t^Pcodg9$`CMZ_Px!^lz!*6CjA-F#>%6?i+> zdW|E%c3$tiv-}}D3MCTi_eMA4E&^dxPGm$Aea=z>zxxXNJ6ES);dx~J>)4+|b04?M zdb)V)r#Zs1dF$`T<`>;7*N7j;TYnE-Et9uCg{IFEZ#_#qI<2jlls2(&QLF#vi96X?o(&QsVmTB zUw=W2lr8PQg)ntSw^rEn4rrF5UZJjC5kY?w_Tov~ej%|gMJ|;>8kJ$gIBaV#(9F_` z#pzj71}%*XGToQMs|t5f1D#P3rfMGNTov0pU>G!t&RBCq+l%TjuzK1Z4&4iHv%34SMTi1R?z-8^$tAMY=*{!Z|`qmh}S}`1)WzF{~ zNO4*~l?4=MZxt7D?6r=v%Dnom-bO%?j&`vqa;1W&%^*ot)fNv6Fl(oKQ`0fHGrFD_Hagx<0g2$92O%V6$E(-iZ;d%j{JP zDSgO}Wwi--$ptXy=WH^Vs=tjSKBWEtWJ`Qis{fi~9w7td16ln4-)2FA^IzLb3b*~3 z-9)7(M%A!>a`rtWAG7}v_irF68d8rLdkV(rJa@e`HzUe_s^*gDuKet4bbGve5*Bx`rpfFu?b7r3SW27oUe0>~*-hoc3kT zBukzwHCk;@pI^mawJLc`m;G4fij-CGbdDN=u)Zu1zMmkhplOof;ONFBJ4#P0@xM@w z6-;zFlVlKTFx${MXhB`#VxYR1E2A;u>nxi>0wA&U0JX?^{Dg9@WNY#o4}A*H#CEZn zrj)K-d1JUM=iF4ot$ecu@+i#cNp9sER&6WatZ4;$QteceDWQ_eu!M*|MGq(hVJdPX z<&zOXG!7Xw*T99nkVbG(b0?apD~n?-G&fM%0X2oQ{FA{Nw8d3%RZjn_;Bu(R8kN*sPoqrs3hefn$u6ug6y{+M!PQVw z5&SZ$WyVo0Lyea&g@Prbe?!p9STV~QtAee$kIYv@>@_-{c0*#sMT5T3yxi~8oKt8$A0MkBXPce z?oM&xoSa&SE`Mq_e-u&lL6YyE3_-px1Rmi6tsm$6E}pr%^z_k4G!$YUdaXJCvJ0v; zsbd#0prr0~)$ve+V_ENEIp8W6xFT3kTZF<^0NOx8sT;6#9}KkC=I2=z5E_f%6w(W! zWPsjrNSL|?r63gL@sg6%(W0Xs&717uadN2S_f*c7-tP!ET(t zXyKN#QXXUiRY>rG1ZumKEuik#Zr~fR){p^m zKEbygdac2!*l2@tL2Bp??3+qoGxUisu6(!{9@iLXj9%V>$1Dh@)cPOCJNn&yYRYQ)=lzFt1v`}c#%PXcT*0c?OPV2 z{X!HtgWVqAfXZcs!c1mwwodud#A#Is3JpU6j09-4Y|-MT(7;uBjS0nEEd0xNaLN*^ zk0dW#+BJmXN?RjCJBz<(l*OAgg}cxQw6zfI9$^U~M`Uw1oE9qiaWjG831f}?PXhdQ z89CX~(E-Gl*-?5rNxp@UXBN2d&u|;4D=5mA>K*){gga(%#T=bY03&Xk&madv6bS83 z$=7gEJP%aiNO7rElufnDfs?=W;QfalIO@IP2ok+wI~qLxtWL+E$+J9*5Jf6>^G0F* zzeE%%t^h^)V`5)}RnRgNIAIUL`nKo=p>b*-L<1}lof~?%$om9+5zy>{|!r;ZdEfFLAr}aUn3TeKn^hCWRkLSxjRRzw-)O zK5*aU%(AIF8?{9SppuUoj)QFxY{2!uB3q8KRqwzBon% z&fvc}@@98+h7BL*h7U!4{kMH$6e5moe%G8r1nBXT78oHC{6Rk?xT+tka3C1pzEEZ* z>0iH2WHYQkVp;8pZ5FkpnOlz>f9Q?}?s)K_BggNWdEoHjnIne}YRy+W1{Z?S8(NFz zivYmr7R_(Q)?hX2;OHSZH4&$Eq!oNzBB$osC{_SFRjKVZ@m`Mjt1Nj+FuouzqR@1{ zXZ8AYcJHf0#M4|YGdUbUS4{H^G!LPQR(J*kwWj8&3QYCTkvLTWQF_R*#+112z0PCc%yiSm=6 ztZmd)K@6&$BeCu_*8AjDCcQDAc1Afm1EH zHgPTvR`0h<>e3kU&%l(;_N*gxoN3(}n^yn5F`9+y0TSj_M#8K*h^<5-&?1V+Yo5-H zjY%-I(2$VK_byp=FK6i}EPB=p!G%DSkPPA&5E65eRQeP-fT4#7EUtw=k4dYDWG^hh zT$1YMNOomTRZF{>j4l=*q4=`kDux?%Q+57MHx=mL3_I-)+@YCq?8a4tjhZBIoNoK0 z9p)~%kCH7w5_Guy;95mzJ~9CD7hRGWH~1J1U|xi$O}_|tFACG>C}o_NMXrWmL@~+B zz5QMVMkVp&%$p&aUO$EV`fWp#kYR7Hw=IOdeJ0A@J`cN3l3Vh~8buBiqd^S$m|zt4 z%(aKreDP9)xhdVn@Fr4_3d)?5v%)ok4&ENr@KpC)hf;%QMBr5C0KDcMIE5s@SLtAs z(H45t8UQA#OS4gXN3d@;r4h?26YQ5q25~qLI!8&zhsZ&{|J+`#L%?sh+oo7}vsgO4NF42!H# zW4(+{`G?WeIl8gT@(Wiv=i&tW48oA-xRn<^OV&epgJu_ku_4eYgjjr=LPld4l}XYd zJsR(;jA#fGqlTLEd+r2TXl7?3wxFSCy+wvh;qQU>gN`f2ZXdYoHl!CIZkCpV5D(sQ z9EQRj_wJjyci$miSj_k>^l#8@$`JMmAJ@0%g#6H(6obO;7Pz_@DS&zCHc(Bp0~Wft zFsM)!|Gsm0k`4*|N+LG*OMrcf*x>Aq)$OOh1$er{yB&A5No{SO%d5@N$)vbqsVbf% z@X;vMRJqnT2oL7mJX^Xw3c%FGzlkTdQa#MKF<4ScF9MglQ8Cf~- zh^ikZD1!^z^bOkw#t0R|j}<-vy%v#K$8u@<0&dk**MUCZ?aA)hvuCfjTfL(TqDh%E zT>*`0_9;Nl*huGhLP@@7b0-uF1gU%iR5rTr;PWvm3pwDMj?9Y|!nmDdsvLtD$Ha+Ac!&6y=le4!m+J6uJK(pp-3b9sP>vIaF zX;lzb7^zZesWRNLD)VvJ(r06ADJt3fmRIVYc@Oda7wlV!_jO#IGwff*hFytl{{s42 zrfmO5G+nuDkCayGf=pb%f04*Wu#14dvfqw}Qa!#!!%1}+CX^iI7vT)0^=jV?14?1m zlqW8qQhrjtt4m)s%bXF`D10+puP*4oWTyt91G)u3GJ zLc8(M5qkQ(=RZX)h1cHCQyx;{pF}5#?g+V8ODLa#yE;&4m&%BwYC(;F_d{+_=%!tD zH3Mj^USV;x`&A|w?G8zDSU^S%s{`fD`GbYvSr|D)g=+z%;r&TQ!TaaF?Cl>ODz@dU ziPpIw9hI28>GZyvZ{dG1hj8!-_965y00;?302$JgLXD3v)cpn>a3~VwJ<_!^W^)!% za0M0pP^J$%rOVCXFW*gWRiy=x-OfBzo%w`wiRvVw$3l6sk+ZWD`$)6E@j+BzRi_Vo zaM^D24E8#cE5J&B=4*8A4i|k<3>_lYRj|oG$r$tN2sEepO|j-tCLB{qO@au=6wb9Z z0(__2u31H@tt{JEyo?kc_`KE0mqKvc?!dgLOmvCmvkyay8K32a-rfMJ@&d-0V6s;|KG zgb2Vbv!*Z;3=ME2WX4OLfMkc@3ZPtdLGded=xR@P?@ie~iUmc9bz8J6L$WDtnW2AY zZ-Yc+??bp}1gpXL(nHTP6g+I~3Z7(aVj$y6DZmak1Rd*;%z$cQEf;5yCJn}$UFR3N~6I0ibIP1+xCI_-Knn?1Xgy75h_Tn6} z+aZW-pz<7;NeJd2v_KmrH|l~59e58>_-FcBoyP+LMFIQ}#nR(IVtq>+s+%*`RIils zfF!aH)n)CD%r!SE5#DWP{~&jHc6Lnd+1MVgy@<>iCKSdj6~i;4IWqp#=~G?LD2849GVWwpN0DH0euHABNjnosHXjnlufdvJrC>Bd ztXLd>CK!4sW8+AftjZW0S^)Zy0sBvWqf^v>(xM&JpLn&mX%E+`7)}}If4v!$G3G4P z)S1os(gNHr^mX87QVKdrSVu8@acFyKKf92Xm@3nl7E}q7+1ba&s9(?EI1ExI;msVI z^2Sb&Jw7`-9uB@xs};Nx)!HeX=s=AgxCYog300i|6@^O2qWvaHWt4P!{IbNoK3qo; zTt&UXW|PH-a@8fNm4XPWj@(L(|1MCVyigToCGtoTRt_D`wCgQFGaj(Q@jrMJ@D7~1 zj1aQ`3=)#{t+I%yG@&(4q^Lkbv#BEdOJ#`ZzgEpaF?}2#6qg8&zO-=|3#AlPWrb|& z5RWP2te#48*70Q96pmqdQzV|nlQwpm7)z87=&rJNT}sG#oXJL2#Pc}Q8)y3IVFzOT zIwDDfk@c`UV%-hJ{yB#s^|0jW4)kt4yrSvdz6yNSk+;cfxh8=l8@27qK0MnQq_m4`%>=?&9zb< zchyz=lxVsQxujMF;B-;Lev3{Ix735PDX7ssI)Rqk&ikW)F5ZG&i_WgAe&l+tPkDc< zya^1!S~;z2B7?lWK+2ZDM8TD*zPC`rVPBvkj0zl&Ktd=oJE|pyFLAFUGBq2uCQG4; zfq)3JffILziJ&>pK)n~BacK(fFFQrkBBjm|%Q<KR4l`15fh+>dnl(tPAl+eW`#1sN*HQ^#pA;8;X6IYJ@%yF2L8Y-$BrizbX4~(6J zz;P<|pqwf-`G(vd+^$I-zg?e7p@xHGv1R5^%=E<6ls=J@(ic!7286Q6$m~7fnX5EC zkHwLhD&}FFo_CB+IIpmoetU;^ufLE(iPPEG(q{pDPijp? zZR}y+%~EmH)T9`j*@@FTHdLCcIbfDG!6Tu(tmJ@k-o@|R3Fm&?2R>j&=Y5=9hv8ZW zjwAnAkw^|xH+;gd2`j(Md@yP>PtZ(5UBl=hjM9TE>h3t_{*!x!xqWU*fs$?obvR4b zKdH!nk_9_7;c2jjL#Ca9A`^+~NXB=WT2{(07~Vl0D2NqqlS zll80pjwZLg;%V9M9zN>7rrxAXl;`);5h4+eze!ZIT$6=&7LZW--UsuS1C*nLT!w!^ zQ^#UiC*wr#gBfhFWO_#U`avP?#@v|o( zI?cCU6K$TXUFsN%<(|*h5N6;llS%MKKvj(Oc^%JL)y(?M* z@1s)bUfR#wSD$r;>;iqn1#ze!4;aj@L|`3MtBqh+`3|m9(fcJ)Opj3cU5UULiOO$B zSIhKEyc|teOyxUteUPlXJ=xuwr$F{}A$KV}|x9GWXC%!$B5GG9-Q$09T}j^lUrt=OD^v#`8vO-I=*}NQQ%9=yJTy93c^*35 z<1*^WcKgPMb{QpYUW5Y=RG2@P2=_j`*UtFD30L+HqyU?XXjRSb1gtNuXhK~Y{J=R` z51XBne&WD*{R@_1RahW-mMZ%&MQ5b0=|)KL8MAz^=7LADe6LA_kW0P;E#E8A)iQPB zooMP%@3Ud~Mk)G+VLYe_+drH_B4frClHdhNep!R;$uEUro*^ec&3yo$4;H1yeX%UWd#UOrCH0Nm3!9HbWo3m0G z1ZXl6Xv*j#M5u3;(b`02PiF5;nLVBI5)w?ELs7a9-Vl$FPe~k*gN`8uJfUUIb0wdX z`l>o7^;&F1xrUL|IVsLTeT^>Y2A1Q&DGXE%_X~1gxl~w{1@cG)xfn<;>f%kfiqHt;@s8F7#7>)?$2;j@eXEB0w4I}Cf|Pj& zt30}*p_c2AjcAWC|H#DJI8~I%oCRC!1qlk;E!sAI4B=nidr-%OIvAXk*JIE zC)GkH*zn3+rR_I6-`P>;xPuMI`K`BGo#VyX zW-72X0lo`^ zR54evU)Kkh`lm~(Fk!oCURoclmnu5wZ<|iA#kq5&?k?iVW`IBMb5Wf$!8W-AcZPLj zcxJ2UFP-4p*e|gz z%0CKx3%03#!#SANFNppSYaCp{H2~L|MS!S+HFbim6&xyTBM2?w?oM!_U+n~!@nVoh zVa8seg!{n&hYdLWhWv0sq*MT|f*wzIiW`D$JR~&}J_;@@0ll`eSpSSgK>$`BpeUr@ zs3MC2-CQhB1i88W;iG!fZx?Darx%G*mw?1k;0N{C!j^(1`4(;=YnEDqq8CFiYBCcA z3(>ROXh;KOb`chXD0@}t44rP(ug&n}R$Dn(jfYIil2;&`+RAhaB5JzhUcTk|1 zgCNeOm=sW}C1t;XX7gmGER~w5KVn zK3M!fd3+td-N=vY`EeaT+BiW{Zt&wv{P=r*%&f)7YxwbZ{P=(Tcn5|rzl|Sf`SB)x ztWV+NLVg@Uu??AM`ELGo2R|CTa=pfnm+|WXer&l6ADj5`XZ-p(ejMi4L;QH0AFt!b zSNQQ|e&jC4$2algmADzc{2)L6fL}k&kC)=+p7JgH_!vJv%8zg6sp}aU-U9eD0{64U51tW_pA~SQ6;PiMFrN_+pAqn$5zw9$u$~o=o)vJO5m25LFrF0< zo)z$&70{g#u$>i|qYASgEq<#?uzu_Y+AW+;Ojv%A;%CEM(rB$@nmvH|) zcsNz2n~P(?>nDpitUU?$9xe!*WWrVN8n#-4Ry;bRt|-@UPC|R+e>1#xJjatd+o$;PmW}v$J3oY$KCu~pjghK$ z@#EHu@NtMAWCZ07KZL&IFQKo8x8a%4SDWM}^mW|Q*9ZBR(APFgUw2vhdV+rmeSMXG z34IkTeLcy)guY%y!V~)9)r*S0coUqWFWzpU=!@mQ6@C4zrLRBaUqW9j!>Z`(82?iA z#lM8USTI7Enw6$}>5W2^rc*K3-x!9)FhA;{c~N;wTmMo$SoZw!*qKb_e##?)6H0|4ldqzc8S zU@G+j&39azY-p1#8+gyddx^f)^;(&~AXrBh3psz}_?`DrqgKWbG(1XvAFxHA)`Pv04jVH|j$B zqUXNkl{JQ3S#7mecH5{cdvT8~L9>XoJBH3mbj@$71?@tvct@nG*Yn#w&a z!~%zvR6|Z)>JJaO)F)SIsVM6`>RR`9uhpq)l)SuO8ghBRuv*LeinBaF*kT2Wm_l1h a)qJI0fE`?0p!tkA348|HyjH4B_WuWefta=c literal 0 HcmV?d00001 diff --git a/.doctrees/udp.doctree b/.doctrees/udp.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d686e67aff8a84bc7dd7a093029195b69411ef86 GIT binary patch literal 67182 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 literal 0 HcmV?d00001 diff --git a/_images/batchjobs-jupyter-created.png b/_images/batchjobs-jupyter-created.png new file mode 100644 index 0000000000000000000000000000000000000000..8dd25f34c04ba92c79540389a4291640ae846cc0 GIT binary patch literal 56503 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 Wz52be*Am1(Sgo-AL;CVh5B~$w`zC?_ literal 0 HcmV?d00001 diff --git a/_images/batchjobs-jupyter-listing.png b/_images/batchjobs-jupyter-listing.png new file mode 100644 index 0000000000000000000000000000000000000000..6e94d16b17d2ab58919e7b8ff894dc5d0f4183b5 GIT binary patch literal 46962 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%0Aj%N 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 Uu~j}f@Ev68D%#4G&t8A}FVHY)fdBvi literal 0 HcmV?d00001 diff --git a/_images/batchjobs-webeditor-listing.png b/_images/batchjobs-webeditor-listing.png new file mode 100644 index 0000000000000000000000000000000000000000..4462f6d4206415cb09418e560ddc38f3ea2f45fd GIT binary patch literal 63115 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 literal 0 HcmV?d00001 diff --git a/_images/evi-composite.png b/_images/evi-composite.png new file mode 100644 index 0000000000000000000000000000000000000000..5680bf03e55509af77051f8fd0fa483ca5337578 GIT binary patch literal 31940 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

    !G}{+Y9*fOR|| z`af^|(S*c*9TDGWlM(JYGPkydDSn&|7a~Bzg1*RrAiMdLRQkWTjlc2s+8u6b`mkjA5jtQBqS227!q$fdT^bT7Xaff*UH#>I|k1 z1dKY+X;}eDR}k-n1OnLS1&%uKk%2Or+33nYoF42CEa~sBHtgjbNU1kA`E+)ssj znA7D1{`Z|KJcT(XCMLr3S@I7}nGHNlL6$P3NS5cq;eOGkI~fwlt`rHY6}tAqabL(h zl=H&WtaA390}>7Y+2zo_F`u5CFaupC03O%uqM`o*L$Got7_wo81h5$b3W^X|iC-S? zonyMG?ALmpGo!IFIwM%>bAwe5x*@O_FF;zJS!0<8Bx1mSOW^n91_;4sZ;BVP0EnrKq{-Mpu;JA;Jkll&TDCa{VV_`)>Z@` zdw={}1JL`WiP|1~x7Y#eiGV;ca5gRn;Oj7(%Yd{wVuxJZLB$U}TWQX1yzUo_fW86R zZF+#U2M!p(D5AB>NBB(sYhBzSVYe{ZHG zZ?A;S%Dt7$JUuX+Q;Qzoj}X-@^667dQ_f!o8Zp3}b6E*_9gc@Nn*jQ209r(dg-!9L zkwqpHYc~Xf$9;K3f?P~g)L$q}1C1jagnk}g?NtmfZEuHwC4C3p7^}I=%pa0C|8R`V zrtf>8*BS_J;vFC^(nN?b;u(NbAM8-gA65x+OG+?>0g(X#AvZ6t6%ZC}k5|Niy=5X} zHjK4BU+?I$9;a$^b7lt624Xyu_LCqH&naZeuFOka0?yM@y3a7;+`qh~U3c?F{U_cy zujQ6tPQ8HS4Yjhes&tv^045@V((z2th2O46$Hzh-ms8)sAY$e?XwdNl06PF!7~i~E z2Em8`1p#E6$ew+6=1{0s_5^YSx}%u|1*kxQE*|!QxcagAxv)5Av^ zRIq@A$7GYQ?;K=+_i;DCF;Tz=CsQEa00#%$XAoNmP>zDKazJn}^4i7*QI!f^(rzWl za0A&=5D3Umv<0SrzzX08I}PAAUCWTIudi?I?68_0yCr6R`#K_YNTbda9|kDR`ha5( zqQYRYr@&tHsHXWI9YDk2hzK!&Pypi{-bWDf`t@tD{s><>HR`*8pu&-bg~;{(c=)dm z&xZyFIm~3*BV=U&glYjML{Tj*f@*4NOUcd)EatnAqy(q^nSjj{cZ|cvOEQAMRuC>5 zaf4tvk*`ckODhPj1C}w_MQoi`Q-cpFwOtiY%(Q!&{t`iyTxmP#D-wzF&9(%Jy+ei+ zY&+>;&iD_E^9pS?u>(woh|U90kqJK-RylcHEh7QYrVrjc>@xK9((**u7{=>@2;k?T z*sQ*#MIU64S$F}I3a3!2`HnS~PNObNCiq{+fmWSeXD)8018|yVW>o&675)YB9&OT* z*}2`3w5?6Yq$;_(E|KovU!<7?l-l5dTSkk(rO%)cn-nttrHy3%joR=j^pizAmOhC? z(1#x6jJ&^0lpR+9uCcatbaVjN*fkDC3wh6plk`LzDKFZIH1~@8AGF5T{(nO`7A~vx z+yA!JS?mu9d^BsoxV=0KDkxwO77=+)L=-A7a6kT3k!bS&sR8q}-$qN8x}F-t3N?TK zv|qmr6J8lc0YKQ1X1IPENiGmsUd{>}hmb+Mu+%I-w0^^znSgf>qrXZ?g@$Bska14J zK~##hV2%>8-@oevxd%<~crBp82L1lc8?hTjE`X7)fDFc1z)t{7IL!z$$I!tM9V}Ev zw-_H2;|Hp$ClHw1Zfa^2QV|bA97}BCzoi$LX!rIC>Fd8F2ow?(eF_3F6;xHy=GX;(BT$q8ukSYST*#7Ew-$j+Vz7~!T3Y%8x8entRrIrqizg7y&vU{5 zanjp%Br0b8TNZ#7_y1V|5UGGdKwJ+B^;ufdyS@b{g@dy*Y+tf&zOVLh1az6f|)B0j_ROJSo3N0`>;-zdxN;QSphN#Q~H3KXRFR%=fqPaY8D)U5M z{`*sC70LxFP;e|BfoSZUoSeLNN=DckzEoN#I|kQ$;6o0nAo;$n-km4+xh+1v)1?ZS~u05s_v?L z?!Ei$I(t{RysQ{J3=Rwk2nf7{xbQC!kZ+T~h5`i%{Erh3%RX=e?kFgs1ONMB7#rI-n%O#Cf_3o%52F1#NXWrh-^tw8hCs>O z+89L1%$b0Zi9piXhJcZtk&%F&g_DVmlZBZ;UWPzOL{W*mt{xTygaAZBSU|}w8Ged`tmXk>JKawgK1$+&?0LbC4LA2L*>Ii ztc1dNU^ugx!l-zmKO5o6cqt{z#HphSe~Tz@;9R&3c06jFJ`QPkW_z|YmD2xORDO8n zek}2vS~1OTcr2;gddJ;-q$+PnMj@3<{Hc)FuNc6+3JZKA9F9WjlPr&73fuzsTpQ+) zO#bhf-64L73^}Grj>8|kH*qm<{jV(-t*6aby|CFK=t)1X$NQ#U9f`&-;^P4a#ke15z~;_>bMW{W8TV_} zj2YwI>%L6)--N9X6Q-`$b^H?dRX13_{rLR6lEf%!H0S8$j@$!J`^!mL_H0zooHLk$ z0R!--p|8qKc_O=>)4M1>e6D)Fn>VeA*^BV;E>`Kv)vajV-M$_2WlPbv1j+f_B-CqE zh^+aZ8RGAuSGhst=jV%=50FYyi$3$btqk_$?U;gQ#r3<-h+x_e;ku&vZuz{POI;xF z-KI|24Pu+pv$GEmMghM19&y;ZL5r#5Mrdeg2#1L1_^@Ki#KFyVe@V#mvlM~pSzx2wMPt6(}KJv~3iDIV96%qPWx+w4y-GBUEK zesW#~?xKc+Nv=z+2ZX1QVMSs5_am{DW_x1bYu#at#%m9-wOv0aYv|^d($slhG4R0m zG86OEp!>=)I5>!fkADbn>juWe#58c5&Srb?e(B3cp6$g5{Px@AD2Ee8{*Ud}6-lO`~Zh~d$ith7mOBy z_rnStJiI-yx3@`EUdA)mUE2_Jdcc1CY2PPp|3_m>u}R*=y6&=O{ljsb;cd0*9S7uV zXhv2WEU|HLb|L88zHPlJYSb44-_u)0qHJUcC_6s_nbzjSChl)MIDwk6X5;rlu7Q zi=Dv1sP}#T<73fa2sA1`Pv2HFVCU$Phdy8Gx(CE75-Gqya+u-?l z(XgoT+J4A0rDH#U-ne$YO6Pqn)i`6e%+|gGKZe)G^SEwEPDX~{@%z$q>-8*B_icCg za?1O{(Z$PaolL@@qTylHvWn-Z6W`}aA9k6o<5;F~?s$31_v4l|+VFK$wR2WhR(3U$ z%XL+`Ol8IMvSUfZ@;n-s>ukey%erl&a-+?)>U}}?UD@;b-yb^8t>O%a2=B9+p)-H5 z?`L%Hvvez#l`RL=*^1%WwuxJP#Sc7R^TurLyz%{^smnV5XYE>(t?tcgu>+pN4|cn5 z1VqF&u8ZcrB6Ew&_FGvlZf>i`%Prj>pKDtmE^DXvXI*b&UCaLd{=42cEZR;pB8@9n zt1fNUz>YMo+0;2YI(|iAjIL`v%je~I;8ojUgw(~#YJAi8^Zl!5m>owVF1H604-ad$ zP3p;CS2vjDILYyyCzJ|(YB&t_#kEcMsTY&|xF8`VB}MJ-jpHz*ucSCDA~AkWmMdzh z+AGZOR?S7wk*&lO+OI?;rv>~CP znD6`MxskN3VPB(qw%&s32MkT%QrE|Qkp5HR)KuH%JuPJt%-7zMrPKBc=PJYdlLcvM z>8rA?m$Cuv-RmLzsg}bmsUJh-8VwOtRqeIxavYm4i%qrmd!nLZVl4-0mKcSHlH7F) zz*QJ!S=Etj(J*>koIUx~z!15sjnexvLxZ2jO?ms0X*8RU@*<%E{Jw&a;kFy@b)uL} z8U4v~>5iy?c1_iFLzUtC@htUVzu~;3P_saa;%o2ZuDou%zvZi^zQiQdd_u z@KEKkP{w{c&QzjA*?yv2mG`T}?s@<-KXEqzmi8(2H+%L>KQLgfH>$q(s$)g67j2ik zI(K=PH5Ln$At52n|B^K$>L)}nwfo0(9vF3ASC?vi-aR(2qg`W*%&%9!(8R>RAYiHe zfMviihWF*C@1v`4(-G{$KRVx3;FPTc##dBS^zYK?z(YE#HRt}zQkCx1`1p8U_S^l? z4@WpUw;tH9p_8p!*~kC9#`i71L+Varv5eR%TR4gDN}nJDNk~X&2jZ$R@H{;|0<`T{ zy`;w#Q2;ht&Pwezmv=QwitF3R8&5a0a_zRprw)}e^sTmF_H}o)FyL+)jv|?K*6V&$ zx$3V=5fdv}uo!TJ?P?q20fKI6S>^l$P`LeO@E8|99hdd+4gJ)BTw$Ad`Bd>4KK)hV$>3nA?}7F1!ks?T@;zH5A#YSD_MFR@oZie7eZM!_)CMZo6g(?=?L7 zGG2;y#}NM&D;t;*+!pJy22xG4o>9*)^_qbR5LxhQI}nkPjcsU%@8f!x`=8s}^-$y% zzULVOFzxvYFaFv!Mf~@8MLv`}8Hi*s(|Ed6bvPr2uYI>{7{fEz-w%GeSYc>kVWAMX z*n4Rc9sJsUJIU2@TG{r*_j&k9&&8$bB*gcOb9EbHN^KANh39WupRc}{8~O(++1aK} zPKlC*y}z#glkFkLeyLX1~nKIazgG1G;*? zE*Q9LjP#Gz4eI%+Jn;O*GiLP6%)l|^R$$hn?hoaA(|5U8ADN#=V_UZa!_>0tLDrND z&*lN*UN&4PC!*zI`A%*q9%UmB5Za!45PiBcT{k6?jo&Um-@8_T$Wi4sKozmq1 z@j+ES_hq3xAJ5P3yX+=bR=-`^CKgn6y@jLg3wN+(GJwS3hiRtsV(rxXO7=VUrO#s< zHWt?Q*IMkl*X&Z}ZUW{oo!hjfFSZ~-p4ksfS%S2!M|mPuF?nHMBt%+P*5SDD4Vw5sc)nj-US;?Bg-oNbpaoxTm) zzCm)iUhD(2d|%fi8ZO3?jwj95+X35Gf?e``UqZxTX}>F^`v)BBf56$imwD-R`2P>c zA6*{~-_J+iso`NLThFyMEC66{F8hNS|7AM#>pd9$6G-;QT`@L3{&y{p*D~FAN+8c^ zzs+{gj`fe(R6o zCP2o|u-qL0kqaUCYE504X8A7H3H#Zk{9*rXN@of4(C0B+qTFsx{WuE~M>h4yw(fmK zLi!AE>d|{N>*Sj&>^~I+x7?dNts(>o7uO zD%_zA1fBRATWmtBY*p&Nw>u;d&pOh zN^KYt-VACr{&j0+>wv?zI_ZExk0^2+90P*~(QcNjX=XEnh!X}>ik&9B7~;{_?)t?s z*H^BN|(a8MDZ3Hx2`{G;EldZ(t0FdT{3B!#fX$fjOHZDqt)zg3) z2#JHB(lU%xm~xOLKWT8z#&-Z2G*%bS1w$$fUYqf$oD;22R*n1ZfpM2AFn(&k14r^5 z%2N(<#%SBhuM*0ot&GN^G*|5JcVVAhKMLds$hGUNM|c~znp5;-Kk3%QPk9Z{{LqKJ zkyX@ZLr9OFU>(0Zfg^SpQrLsj2&goL3F}$lWYW0oR{QgtMJB}}SSXp==ik(QngJ9* zHjM9`a&`N)c#W%kX{bX{Q$ORx%qS zn%!PjTAI4ndbP#z5QX@Vyss4ExGiwolTFKBEnXbpqYFA4G9aAnreT0aAW%fR``d(O zZL2HAPqxJZzo1RAiI5T?k_O*72`i{dnKRnGT}#E5JZnCAAAAS>Wx|3>vr zajP?`+WHtCHu|+&rB*-cL_(tuecvkVjUjA%o@!&FzeLqa$ii*=lZ)9u%VB}l3B5Lr z{fLzj-ARL?w^%#4o|e6ywst&xG~~j)jGEJ>Dj~dk{!OCx$%*BCzAQ%G_@Hr0v0BA1 zoTSwRDHZ%1StE(ihlv;m3YlCC;E@AXh@zSjco&U4giJnJH^rNd%jI%))rZIgg!j)E z-A~In>&2Tg#^L>K%-bIwaYB5y=teA3i}c{u5^nq`6GDt6^jT0wkiY0|HK1ATsxWcR z%p{wch%BjTOOGRnx1Rh8PU%*6GK9%;%0RUnQl<-O{|H(3=6D2@+fGgM1+e!fP^4s#fK`*p4S7T>(?$WD);AK8lJ`@BLUlX8=t%5vOA)^C5m)c8ST z{ZYq9mXUP!bO}o&q`%^@r=lcw_5Rp;F6aHq+PZhqOAEFWF6`IEe!8q3R&j@E{;gxD zkc5U2>JWrPeIPGbiga{;1R%%>a<83iCQBQBBkOU<8o=tbsL{AyorJqY9c^{52BSz= zOGS?^<^iji{A2f{hjRJmqhdJA4p|kxI@(Ekd$#)g9tWV&iybWeBeyUR1AvWnduT#1 z&FxZ!N$~E&)m7VGXJseCG;%oFfX~mcYn7ZDO&6wBxmXk}ym3 z>zjCabxyfd0|u^YZ=p>T*Op))k{-$5X#N*S3M8dZnuC6^PY_fMBP#`Me~ZYxK??8E zMQ6mMuWCzNpIqT!>Qt9!DZ8_>Z{p-No2>}eUnlgP3@ITPSb;GV_%Sbd31>FDt+_Ude=`<1l^gypASbZ=n|A?dB*6Z*=q!OMQqNP=DMjCe z(Q7W^UED29@7vyeRz`mZHZos=oK%Bw?3J1G&myMue0T*?PYEx#EwSRH)o_^DC*AcB zCw36I`J{QMzN`Ao@hNHvwpfO3NTu}IpbR$?E0u7?iKUB z#I<@kn)quYY&~n>Ds1KZxsz@q+u;CEM@O30wx&;qgOXxLN1BjqP4bh$fA;%h#!nB( z@$i0z<5i~k#oafNMh!OwW4F0_jvFoDvb#A+CAaFmm-h=D|S@ zDXv=k)(J7PpwM)UaGjJ(3$+v61`A|Oso0NVClgAaZ?qGDajLC5B6@ViVJeIwzo=U9 z@G`D6+ZSi6PDPJ$L9C3dfITg1KVdy9TLZ+8PQ6=lIi9oMHV*hcPC6VPacR$8E5~*F>EaZCvUf?N}OKdLXB@){G{}91r))_g*BnP4uozN7Nj@X_Jq4e|vK3%6y{Wd%Qaufc|K5SiHqGhVTu;RT1 zN`Pw1n#%h&_V`lBIhaZJZ>!yk=!1O6{~}PYCxSvg8y{^H#>{{J!~Gvcd-)0NE_sI| zz`QRW!E*N+AqkaPn?cyPi=aZtR_1_cUPpY{sjUHJwzaFd34!kEw31Q8_3xQD>*or- zVyY6-9Vzy4tf*}0^0GkyFT+|la_BPtL%KRR6n=22aI=|*0702y#C+j&w|;%OyVK9# zWyBihk!clIFQRkM8A>Egt+%3}>O|V83R3z>A}+6K<6heCIBF+8iR2d8F2Y6!^++YOBq?T1xS!FoM-D3WRfGHzVVV;`~ zJh{?d;<&iclnCvy-=%Yh4b>q^r&J4{Pf{00>A_kZtw|A?Q#zBlAqE> zg?u~B9=W!Cf2CoQY_9j+Kb9m`J8}W9zxyK}rLBn;OmZy=Cs*(NBjl}Rs`c#zrrB|GTZZ&8 zHPi`F8*Sc9O2s9H(>#-GmTB)1Xg_J~Lp#|50YFgA`)@xv{m7l5g31>*EDeHRuGCms z)(cQu#^9VB>l>n9p!a5^7T2GOSuH(~rx~&WOzm!z`R$BGsE+kz@* z(}*`N#dv;x&CPIFBCE(`^BR2>)276Jx0JPnk!jEScV(d8=%6>RMC^$SUw_@Sp!Ge5 zNlxr=rT`r@l@mKEI*92AGcQ*EU>2o>T9D)T_pfAT=;;cO_7c!kJ7j0Fb$FrU0C^yF zCjN~sk+CR7#L8&oJbeqZa395zWoL8(C3X+m>yGKo5_3HxD~IH?Zs`Pf4lU#yL!Bm@ z$D!J_?lmN%MiZ6|HPaUxRS3QShid7e{#$KfZyvr)T{V*wE#z{dQomH$&}WGL`uCNJ z7cIKE_v2st9#w^@IrL&CH0+m93!pg!8k7{Eh~<=2{?(d=&$1+v0SAgqL;`#l3D|;ZJ`11(uB*OyN+wrCd{t za`_RR7bvGhBis;F@2@cH6F~^URp%N`B5q~8k3OxStrj`hf(Kp!;Y{Ta$k@K21_ICl z>_V2|=lzKyUlj9)dAay5S_#2AW=@%GZ>+9cV6;@zuFOcVy@I@oBk{ls1@9lqigSD1 z#`2Sy2<>_`?Tw=6W+qw0G75#n84CnXa@_0_0G3UH$}d^9h8R=Ca|3?o)QQp`e9bW< zcCp_@0Y^U_h#S2~LPof_adRnXV0a3lX=b^wBYgw0tjiZ{Ns_;OGX zyoN@SUTjmxtDhP{F`K&0=@r;WkmjgeM|Oj%!+kl-&0<-RZWSIGH$`Vv!X%LN3UciVOW$)~aX$*hb z9M?!Q@8_QrsKXAp2?I++v)e%)clna^MhY09p9jz_(-Q z&(NKqudK6HZ=`%0H3{*nZO9S6Sb1_ntYN(%?rr@bT3BE#E_H6WwTMjn{&=sSldBEN z=)hOiM&{FH!(e5SLe-jTc2NcTx0V-Ej*zKr&UfloeFDbm1n|1iLhE;Uew%PJqDUE% zB>H@7DyIX=zmlS*=#uOe2YTxel;E@S3fN?43V^d;vSJipcNV}jA$!WD=P09#yx`8L zF$wZb%Uezrd_t%HL^R<-&95P#Io{!I*@u-4A&34i;h5gKv2WX?RheWwB-A(mN86;{ zSnLtE<$~PS@nZBWGeicQrnuf(*G~TjQ`)refL16qXVO(Mt4x-V%`iLM`VRwICR={J za?7A=%Ah6o zkno}cIj;v`v|VdexsaKKhdO4-?ASd4!z+ICpoV%A42p27oM#!>WU06$X&6QtfHR}KJiW5;kNq}E^EkRSvMa2o^0>xDFRSOTlreK30Tx`Fw34aX-e4v{ zaAD~$P<`Zo4()pVN~>l$68`5ey6a{ew2YsGx%hRj>{3S=%gxz|Vcetg{&5 z(`H%j=iypykW`*m^CCYSh7%25LZx0G!i&sCIiLb6t4NDz&(qmn|Mo8hCeh$T*0w5u z*jD_X7hoVrr`Eu00=am%S`w{*oaeeF(4Im)w?gWf_DPorm3?nQbEd}fV1^-uF!H3? zPQi@e&RmVIYXlz72!v^ZvM&i?kiG6<-G<)MjY39|lQ<|kXCtCS3AIU&W?B>l@`4Gz zpopxzYeWIO7fCWuzR*$ri)B-*P}{G9aH6Jd{_R(y&ObGksP&^(bUNHKXd8DmG-1J9 zDaXk?Ea>4;QkGO4a&i*?3CEI35Zt3SB0sJF^C+i6kN)J!yCuXBvN%m+xbCeD#~j-h~OrstI1W`{24el&xeZu(!_#f$Q1FAY!ID00Cl z23amj)Ft7<)&Oespj#Ae`&ZTy64)feXQgV}LwX|Cvoi7^eNh7VvJ;x1YVb`9xn!LN zAl$I`0*Q$F5ehu*?0kR{)rmbQ1IdOT4V#VgeVhLJ07v6wrL0;(wUg7Z(1blo1y)u4 z-|sw>WX}8K%+{#-P^`!aR*R1sL+EQrZ8#na-rPW<-=|fi z&+ZEIun7Rr1)wv^O60gDMGdjiu(iq*9n5+;CpcZJ5@9rL7E)h1s)kXMqCDN@*G9$P z3m7O%) zZfT6UrU9O89C6!P`>?3ojC_8-XL9mcR2tMW@zcSIOY?KVuB_mhsJf<<6v$42{{YC< zl4Tfk+uScv5~QK_E21o*2Db~Vt~>U&9f50;7b7?F`4=<`Abr%l&CyR|`@&3$h9?A~ zWi|GuQ;AEl{)J5l%OQo*?6e;aSWy&kDR9KQQLtzJKJ!~Q|5C{X5-Jk7@CqvL^5yYyxGMJvOLkz1odYO)Kb@#{jRHli z!z@o)%|@%8b;l`V4-Xs=OPVi@hW+DdkK??4?&*N7Oa1H+D5IN>CDT}~)CRBFcD|2%!B8Oy<(-cRI7#q(?yQxkhi64uRYNWhi$FUeauC~Mh zq@yu3s{}2xs7;Ja5E%aY~G@46&j!6<$b-U)SW-d*nFH0u6&4 zupVX1tWG8%7COk25@H3L+#4b-$esAo+OI`*-gYq^ z7nD`)=VaLaYqt|@w{o9%a%ammfxtSh-In*`^=sGX>pIZ+AuS_g|9-#Z`1$@w9JD>o zG`0VBJ7sEQv~Py51B^Y?SM25dN5^TCjG)wfFPROu#$v}33P{ID%&CYhgYOtc2$*x{;RbLQ2kNX!W$d+# z=|FyA8KnNgKWoJ){2Xa0Xd&!4;b4S2q|u+l7)r9_GCp}%ckW^s0$;@D0I!^LS#dPH zftmqOGcyKo{A-nn(sK(X%)$toqqRVVbefpm)SE_MIx{5FRJ;Ah+vE;@Hak`csrehr z6UAwO1r35m%2s?DfC}yi!-cAk&ddfS7n|&49T80f+*(?E7)(d*BL`fxm_2h3)LEJxrA~vp)fLqX-yGx2tU@sEtckHn6n6)R5|ddV|1>hk%5W_Bxn?XD`E* zxk!*nLr5NdPKp##BN;hz0dhY*f@N}Gu{~r#pXdl`CSwC^${$}jQ5epbA3RtHW#YCvVuSlSG zIik=|1p)@pg*w-D>|gF7l?si4OQ5w2=$1pYJ4iLXA@{u@2Wrf9&F`?)nFIJWmA`BSj0y>z6ruwl{2WsVg;imS0bcH zSQY?5Wzj9s{-8GHeFJjCMR?NIG8xHADSi(5cY zdyTl-pVjg+=gTKQoLIgRYbJ`{6VvxVtU9t-y3jeJ%K6%C{4H@n9t6r$8 zI$0KJCOZlp9V##2umE)=LYg%KWD4e#$t^Ui z6XR&jP-K2a{dQ-ejVMk)A;jsPl?tSVA3wDjwhD>h{iw41;8%j;oO6E`Ov6UNq{Y~{ zTasj~!P@A89?VN*RsXw5BblSa?%4?B(*_SxpN_$Zw^nM=Gi zodRY}xol)ex8DrvLz8+yX-em!aPpTqn0_+^>Xw}PS#$! zuNeQa2exl^i|VGhsbEwJyVxN~?w%KP58D!C=<}|<(};;o*i|%o7&DK;=&7!a*9w~Y zwo8t2|CW$%L(45g|fsN#1FWU9NnFPEYX)Wi;fzcJ|1w`79G3b?b z?Af}hix4wb7aONux)nj2DY3#sd2WJ*&IwwqBQ}MkgtxpN79t zL^xF~{43RpvaP4#`}|8FE$Br)La|x1+CvE@Bd+b#7vM`}Pkp)|Zx~E=+DWYd7HwLO zG_SipnARu6E?W#4Z+b{|-hLyYgK@7!d;!MB2Is2{R_o1izOPNbVB0{0A<>u1^Dx`j zX9nBz^}Oj8=pjV$yPe|8271@PENOIsW-Tln9D|Kk=k_yWx;>z^%f!PY?fBUIqVv_} zOS$|1;A_OZ1V$~Tku#?GWJXweg}L_OzvM?-5woz~^})$P4C50LH1|XjMko}dRBBQ0 zRCxkMsjEIpM@z6?VWdgu+E!s^^xHbZ>%=_X^rg2SHNs5ZdjUXJzSU%NZ23d?W&P3a z(fd-zfx88d(RF7;q8s{?!s^yRvyEHZQ+_|>oAagU{sfZKz$`AN2<38I7O}+&YC#|* zK!bCSHW+uJb)F^)?jY|YjFE4lfQ@7XCt5gAWi#&7`o8_Jq8cME03iczFo1YTjfr`_ z=no_o@iNyE!D)!>VVZwbg=aRB&sC+*%R8_}rB5VaDvd6qn)F`F_e^H15wT7^Z#Ow& zzbkQ{IC~%l@O>%v9R+M&LB^Bpe7R}z@!x+AV)>jl`9!YSv_*Y6$(n%i2gz{VboY9w z%l`MY7gMZKc0Cj0gXT9gqp*2j>H1}s1-rU%?Mk1SnaOvNCY9u#0~T`T?zF9fzM%r3 z;5)8C6l=nikj7zy?DtDivhyYa;b-Iw58{faX`{>&%YrYOSCKcb*{nrKCk4pOBuig~ zeaXo5sGHq9xl z>lyR5aHJ4dx$kWCS+n(B?szOwwV{eO-sg&cHWdLcgU`$=@XU!22WK69hrZR{Om?!n zmKZ;DB?G%)SKi%}J4C_W<3&7dCV>epBx30ZP;3C1a-Vc;{``3T!~HQp=VL!&C7oYU4*o8T*~Anwn}w7wX_9i?TQ9eTsLH#k zoi<4AKJ}K*2NgDJb6bs3dj5-7x_rwq(LO-lN!#|uwAsFZ*yIw$`TTp->r=4JsU$cL zfkJwVU_&zO;7`$yruAm@8$;NPdSPC3hq|Q76*60xQQ}`^)KMBS{N|9Nn&aePBw#Sw zY~oZf=VZwuCRgr;@|@en)mZ)`?R7H&O)ix}pa4xLl3|Oq)Mv^?@qiw1!wfG`Jb9mG z_8@Bk+X6oAfgoA$csVzUab%1mgWySH?#bN0*&=o`_dTLD|7pl`!Nnbe?o&LESLe3A zZOvt!$3^LG*O9v8K!fntw!I+IjsxoDSS3}Edqda6xGSet4rTK7FLf2FNlWJxvQ!qN zQyupo(NGSfS$usARtUxh@C{ybbG|TjGb}f+Yh`uSF+Mf&;rq`wY#0lvxoOfOT7V6gN%&;USOeu}(kQZTs>Qijwg;Sp4 z<(8e0eQZ3csNQc$J!28KCiw!_|6qCH@Ze{35b$UNc?*gd3ecYA3ADDNFchZlEECaDUf?;Plk*SxaIEH^jm5W?gSRD0E3R>qEDZ5N&{+ zj-#pB1p2DV_w3<|>XBB^bWW*7uY=UK+8NHwwvWwAusNV~-_6wpPizLP7Da0(%#F#t zT!!fcz@xqTy3-th!=MI_CYB*X;*L3P)}k-mhCG&KD8|mq#uL?_cEg*JwgL=GW!G>T zGrMRZ1Bxh#-tv;MT1839u1v1-QXJxy+lk}tkXxdAerrf?-zT#Kf+$I$$VfPeD6Cxm z-l(8i_8l#hfw1qpMRpD8tAs1bL9ZVeAj^1pz|eG{ECSjd6vp9 zn&8#!pH4JFa9fYL^k$$F8iDe{hcS6BePAxxNIs`5tBdm|%p3&~LL)ol}OIbS2${8Rdl<{qiDhwL$GB7c{g z2i|+{!6wGnqd6Oa_v4^KmJx;DRv7JGY_H+Z;-#k2>yRnYl0TK=w?&kCbQSjmaQIqs zhMK~TNo<+@{HgLgMr>bRM?{^y^mL_AqS7hF-Cp)Q1XJ|!pGtB$zc7_qT>wtXd6uQk z=EI@dupK!9lz+~jXwB_P)U~f=B(+^>9RYoB@77s2w8a031p3?+{m)-67!JTzPC#dLBRFS zcpj_(cMl>(kgHd@&+oVW7`OrVd?3}-mb917L0LLaMK!vxF#+F|0tlbj6j)_0|07p;?$r-dBrb7nMNq^uR-fVC-hK zst%fY))>=h$~N8qK1$sN`JzL4b}8im+5W$Brv!J!pRcZis8s1pl@r<2*P zFVYHHZ!)on#X1DJ^4=xVn;j8;p_`pv!j|vFNn=hymwxY?ua$m)b;shjChK5Dg+;qo zNo`=I;tW8pRwaR+V;HW4W1ZQkXd%YmD^}OKn;G!?c6tF_6HC%)HkEGp8gH*p=HU{* zdr~DL-H)3oc0mN$9B^#obhDRKvbC5{ku-@b&QBOK5_NF?o-z6rCJkhG)a?Lu;#9nDPU4Xs=v5>|ooa3WU z1fQr3#^{Xh!GDfALzqG@+LR^!ahFRPLeoiFQWFi-_+f zpNeCrV=W>KJz0)H^Z3wzm*o!)+Zbb6OQq_9J+hsO^Nf+seuJ_MWhSW(^FQhDlegGpR%}q=Fi|8l$B>WP$dW6x51shP~>1f1Ct180F;BK{$uZ%#4YUXGAtqD!+DmvSVD@_?0Pe@cfJfE zLpG-C1RJAbID@VrT&EJA2do-6a4Oh=+ayIM?`Onl1@f97Aa4rN9QIrVx@z~><1b52 zJI|C$ZU-NF`=#y)&O&y&99yJg@ZZC4Rn&(Gvu7{m;Q!O0Lh|pyfe@mQ7Ng~a*J7p( z8Zd*7(+7f4!#zj$1og&Nd45GsYX9Vt%AIK}r*-iw&z1AUB4l5Y?sDJl5dOg$6X0oP z(|)#GmYY}}SLh;JsyfGf)Nk+^^sqLyonn-7spChz_eqmgIn9?raWF#0Mx>6H##D`D z!m=W1VEeE=I+=x<%&8y430zZxc+_+Tr3GVxS<&K)XD~_Vz zWH$~89w9KyoC=eN3$4RUk>08a7-}@w>MT>xhOb8^mFEqaA_W@y<^0f6Y_J&}I`edS z2lw-WL}kTY@$hvw^MixT#=t=cpH zRq3CeyMg+bs%4$53sJ_^XV7EoYUZ6`ALV!IOqO1WUpFh!H6r6}f8~qV1;>Fls?8`d z{$w#%3{>dOTRsd+9yy>DmpkqS%2D`Gjd(j; zA7p6P72jK^?f2~`L@OF1<=l<|9jnM1D;4!T>|^p__E{GS8(R$BhQFnvP}QP2rPzy5 zR%SW*IR?o7q7WfJr=^ulQqJHR7s~X@fBNipqvs!T)g*Lm&(-!W(Lfk=)&Lp)!#JW| zxt@a$$lP6l?W=;X&RD~@i$QY%Lq*1IUb&V0X=j65=>VGlB|iId>D|O>07m~@ayey0 zqRFO6YqbvQco3A;&SGxrrC3Cw|8^Nop;GTOB%nC?V{_P>H$4FWISOC9RJ#-?dWk zWvGf=;d7TH8EF*2DAa|JWnekWgyS|FU|RP=a?XE^x$kEzP+J}8xv0#b2TDVbp%2L0 zOQHsSSpf8bYM$^D^Lc$b?uyPHl*kZmUT;M2h3vtx+;RAK)h)2Y!?d;55#byZ-8nc1 zL%%{>Z}z6#Vt{}qnhA6%)zgP3;>QQwbJC-}&Pq(Bl zV*T)VW?){AsJf9zK3Bx3e9Q##95*MApsg?ZP7{lufqzyo!L*Sm!$ujyTB$(=KZVe0 z#PU)pF~qpc5>hT{*;>F^uR5I^N2O3<{H!%%ep-BsHrS+BZY45$U{b_p7?XF*Bh{>c z(0wyU+UrTsD_8-B_-Tl@E2>CJ0MLp%p$(Ou>;&{kX8E^ zJpNnNLS&CHBq~fmawN0#gljcUb*fa^D2Z)j&EMz(hi-F%%oV@;e)qe4)YNadLyOeP4mt{)WQ3DSc)V5Ze8UBAVn=;!L75rP~#l=Xy@n#}FOrVIN4z&WK zC&AT?swKLfRwapA<(Ol!?s`jRI(Wo(sD8ilv8 zI)%fFq0_5g#%FW{!_h;~r7~1Jc#4pPnUc%N=tsH0oP+DKV6{zX%Ub*=O1~GS6;tBI zfgJVAoW-UNU=;1}>1f=E=h6rH!bAyt-t{5UzP$Fk+V)vV==p-@+LQP3AADEi%6D3# z|F=obmQX9E^U5+8Vw-L>pDIi+VTmZ`=k@3!h@Yriv4)=R9{k#$AplJGh zZ{o2PlI9HkY(CQ=q%xaIgW0(Q8xreHU!!5*NyYf*BrsV&J@-Z^cdT@$CKa>L#}TBt z#3?R2u~eC1>{941q0qLDo;0Rh5i(bfKxi5MzC4+avomaRV0c#$_f3B)+!crWw|2n%9E8U9DnQWKO!KvX;-tggbMk-_r@MGkjC3dQ2k9=bVA3YZ?2 zgq$^a81k|o3a>XUWfooiE6=2Mj$!${NTYgVyQJek+3w$l0UlSxx-Jk+8s@^!TrnMp z{YwKJDFkOmdhxku7^X(I@5>dh$sJ$F&W9IFhqzG3=DZlE^*kl>g_SC=@ z;Mlwp%nRF#TGAR7Demk{Qo4*+5T!;!fA_#5vG_?Ct;ku2ETEZJRGNY;RL_~e1TRrr z`02f$k3PFBIKap|Pm&n&{IgJ1#*EFtM}Lo`t^>x?B__upDvFx3{%>?b-n1fIRd!(> zBVINhB(c1|fM$Nm4#dqsbmY5ls8i! z*yW4j!YW7>pv0cAqQ{xjHinL3RkDMWnIf@6`ATcEFK z7$Lzjye=QCk-;c~%Y)y_X>~LhKfzYU4O#!VpggrufO{X^UsH zq`dX&1AJ7Q(-HBPRK=o|dq2`GeT)1h`V?J1VbUnmpVlD8_1+@s-F`Zy0BrAXsOf}w zg&|r{6kF^qWFufGC)yce;yHr59_S|qpx{smG=@@()A1g>ds&MbmoW`f<_+^Sn*F`F z>|3R@`*WttuNen#54JB}ahVOpUfBv+10gnkL;bvzs8Bmdo~4LfP&ACmVLIQmkdk$F znaIc7^kvbE3ufbE1d&XvN}bh?5+yKB=m98=8}*eDxULVnRj=JIhiEO`q>4>@&`6~} zD5$Lk@ibR=UHINJYJUCElG5NOqS0X?wuRiM$u9bTG@WB~UR~F=lQdRiH@59GMq}Hy zZKpwFHf(I$wr!`e8|&SL57Vsr;Mtvjb;Y@8Z%^Opz z5!Pe2c->U-vJ|nl{-F32TnA%2&!*R@Xj*)u<|@#XWaQr6}$Fdl%00EmbQ;j6H zqFFcN0z!kE=t#EZ4i-IVf>h1+dw}2-gLqS2%Z#a+N!&qsKe5S)f;1c?J*k8m2J4iY zqv5w2s1a(CQ?uEF%XIPzE$4x5i$!A%9TLZYrMNFuicKW2Vk-d-^-C^RysEGw7wSIe zu0hGQ&~%(>JemnxwB{nZf;bVXk{hQZc0A;a-6N(5E7if&ZoKQt#BC_&KUy6i?8>l> zt5QBd;jDI`QP9j zmH=;N)5D5zh)x29Af(l*MLLq29z~Z~E8-Nmh=2YZ^ld=8Y4U)CLSa&zHa zhd6(iah(~zuf`5chB_W9`vcKt0V6EE@rwrA6KPCWXncn?zg9tA8GLI8Q4e5q%aOAL zUCCxLat>*FHGZ%Z!{aYyR^&7`R_lZm?>pDVMqIuwkxR*-CF@?aMRCn8YZEJmC;fIL zGoU?FR9vy=G%x-W+Pb|O8-Qw{pfh6B)$}{p={R$)xc_eDwej@)__rYa%Q)>KOg@lQ zGi(x3gPP}k7+4!8{o$Fpn0d(uLK;DwrKL06h_*M)vCTIq z)zsF;m>U{hqjf^ZfCwEQ)qSvXm_V^SmOKFhd*lO6dkU-kEcg_;qk+ zC;kbALX&ORwR`s(^22@CP}5^rx=MB;^6of+K>OZGutHZG|`$utjxH!@pdBQ*cE_N|q zrI3v%vQk3WeY0R*IBv9+4qh@xjP-33C~(5xF;BE2Qe5{>klA{DPtW8rdY%{O(l{;@Lx`t$CQeE-siI&qo^B5GCjX8E&Tj3$jO zMBiZKVRgcY!#oh09NO9XV@Wf@%H<+4wB9{Y1n#0K^5v zz;k(F1ecu#qAx{NtiD`2E?Ra%NHK8957fI8q71UII59Mb#)`Axz87G_BE6Lxb z*UU;%jM&w9&MN7vxy+fcY3o?Dw@+${O5BfE8L9*BfC@<`fD!~||A`7}newrd3oVC<9c8s)dbSs=Ul}*I}>W<+zC*sb=Rx}fY?nVo!6+j)G@41tkns_l?0U>wv zk%?>0#EFBmCTPytkdKqzI4u_0cFWqKqY65KnSF{irOI7Hq*75NO|DI;N%Y*;WS%QW zEujl$28y-*jHia5E+cI2zZUsDQxp~!a=M(LeNqonbX-?Tx8R77c3XJDpzz)Ofd=Bg zva)h`<`IT-Vx|F{nj{UVmW*bVKvi4cgoF30HM<@a2Ys-!=`W4_E4fyu6{~{dA;}QZ zRQ@>&h(l$ZEi7wVC|)aadkCyZZRDTak}B1@kL6w=>1c5~nkX0xibgg5}h znXohq&TJ#Ra3Ldhi)K;W>xMH4+K2}#?dOtK(_GR)oEMPnPST^adLh(q*uH-eA;gfR zAbXGRRinqsI$21yQbn2-I?B1CoF(jh5JMylZI|dR6kRR_r=Bz(SO?L!< zJaD8&`5gTTa|e)Q2;IQnLlpc^Kgt_E5oG`mi;;_KqYT z@ptW+OThXow-7eX(AbT`cQhUGSSS$U5)IvJWBw!AuU{ljhC~b3+2mIs=P}a(bz~C% zERs%vpDp4-s-P6FMhhv}7n7EP?np8+Hl>%m3-O!Rp6s~6`RS#Q$!Jj!mYJhJj|Kx9 zPWi+$o)~q!{-mA<*_F$GI$jALy@Xhp)-!<{B#E&aKjGU>?T-Uyz9!vW_~MYk4l%?* zC)1T65IcwiY)sk&CZ1)~hBN^+gqbLD4Dq93l$al8PK7$L_sM8bTepoWhflpta%};5 zzAc>g0T`fJtXMP_1w=|lV~OO<%oXZKNoi_qoXFcv5ELnv#)qd9_o(wD2^4^uRriZP z)*%4FvfEApkXjx9vT5{G_kkPV`%2LDe04zY{Xh@w>JwSyy#uGGzt!oJIA-$xPwoTF zzov%Cw(HGR7wAZ^tM`Yl?3$XI!^8YgU?Ix`3prvu>CM^rn%i-E{7=yC7>65b&KrYK z)m#-<<&pTMCvMf_i`z{jpWbf8(B=`CbexULt-sCzglPhGp5W9u!8^FifLGxUG1}b1 zVPUB6v1U~jV3P@G_HB^^KGGz8!LT*?@?7q8BfY2>k+;*A?LJq_9WP%&L^0I-5xQ5( z!r>Vw=jy7YzB_k&Brmeo_}lj+>AtbM^DX(YzLnSI*9dX%|MB;x4j9m9e03sk-_3nN zBrHGGt8@vE6(5k4Hb6i0%tKt|Un++u&!HHTVGptK{-aTv>_NQVkL(w9rY^F1cf3Ev z;`fNR+UCZv^?u(p)#?LK*%_V8gSYnxJ|2Hhx%_{rD&OG{C$P`+)v+6Iiv-fQ zjL)8;+dD=Kylsx^N1lWy(VG6Un85t?t&i|JnM`i|FLQ>}Wkz9|$h>k?|L%{D%Dh37 zCb`?buiqc$8jpW|1J9-$9d@a=9i)IG{NQFhc0QQ2{cR7qgT7G6ciiK`Bp zpOcgy2jf@&(-G^RD;o%>6qp`=hBJ~ zs^9?=z2gZbCVP3@?Qhe}C{W}V1!cpYvN}J=^BOi02EBhfPJj=*ukVS=CiY?a=0Eby zo8%_@J_HVU+tUO&+qQG|PodU-4M=XQ>?ep5_#|rCwuAuBe;OUp(i^M6cM&S^UxORf z_0YO+4Alpn_{Kna?pS@?3}`T8#vSd)B!h=bll$cC4F725b|?>;#_QjobuMonzd=K^ z;Wx+hadbH?TeQ0E){0%w5jeZl2RnQ3d#Q;teW17yzXzwrFh&TvZxw z=%8f`W@eZy<9yKnvF+kr8#+`|0PQa&E~{{BWU1S0Trpr=y>C7K--MyhndGtW+(ob2 zp8g|TX6yC169%<+&9UiDvZU>V@BrwFTlW**Yad#vc}XgonB|G<45vl2R9$FQiJx2l zeVOCEe^1hPxe1pEPO)UHzRdb^Q3KY_mA%;uou#XB>3&TIB_Rf}@#D*=;TXnBLU0jU z%G>5Y5O96(NJ_9!D%`NNxxjK%;)o5!KM;-9Esqah30WLeyQ;o2bwk${K%1zu(1e1i z`qQKY@;vxfsomxCWaYY9d5?9rea(s3P+Mahc9g~UDmGzrN7!o{(I|jO>2kv<%W2{W zffkV?T7^x68E?eWnH!$(3x;oQuuc7m9+ot>-$2HyCb_rmS)m$$vIvT{e-erJ4J|wG z@XF^xs235dl^n!o!&5rj!27kI67HONL6Nzef|}Mb=nD|%wJi4g@Raq;IF$OXL1UlQ zSzN)BnTvVYDe{7v&g}FOtt+?Pr22LKs9VNe*Y$-}7v6VFF$PU8y~6fujrvqI#1aM# zq~5bC47XC{!(Y#zA!A})-jrvA^4+ka;`b5yomfZ{RPjDcLeQZ9BS&}mpZ=t3t_CYe-E;;}_- z@y2`Ad*W6Uq{(M^AWohJDgO%x+<8uh1^H^#Ubb~5r1A~VHg@mz0XyQfUd{HMJ=GWafPQg2EXI4=RV>0OD zMZIS}6`GBjR4~VAyJ4D;0yW|d%&tqYnme89N#39&TO_f8H>0GoCDBP`P~My)P)&_Q zBe>j{yA9az@t#MpDy@IMd>m0EQN(d%Iah7;yXGM+!rxKC^JQM!KrElp6td1M1SjULo(@FG1j4Q+HH z7)1f!lC(eQqgtnsWQ#GoursY<{a?h#Qx*i;=LP_;4pU5N76}e@xodkmO#=&nKFpRRxgZ#$c?N$Ijffc)XC z9Pju_4Y9z7U=Fe$NA`^^NJlD3;K|~vp8`T?Sg;EyAA^>-F83|YP~9Z4wBY9LFwgh- z+CTy2*bvPDu9S_IpSj*;BvPxKJkCCcc}=bG9o3|D10g@h*EOT4iY1C3Dr<6D9bxr2YrPNBrS9T^TdY4PV`PTXF_5 zzSmQihDAJVFWeDb^Hlr!4 z(Dl0DI@kqNQX@#Msb!vyY<&e3`ktnb?j)N&QHj%>vJ3a9L;p*1%D^X!oTu+dx~A}w ze;c!i0F_XP`)n+(C=CLY2X^P|a`ce5>dIC5DiHBK+3Nb-rvaJLApj0Gu(gdoUu$v# zA|Z}zHcgqBPy1=4XRsKPo;f~|5jtBkE9l~g>e$N2t;0f8(>B;Sw8wuluJXgEEnKB( ztEZ{vGL&N_qKb;~P@O|aaUD!#)6jB2Pr>SLDBEdYH0ZIwOA7#65-S;T7^mX&{Z*tt zZpIB{PZ`5$+k4)Z5-m#R<|5f3jB-x`_~4|(i92@j=on(!oBVj@5|Y`ul=`e5Qs0D@)U5f zy}L9imJA#;k7E&48S9bQkdvR?1$Ns0)njB%o89U->UyPV(_FPAAdv1 zLZ|Wa4@{!c0RI{7*rVp3_O)2LAS&90>*R2pLA6FkRP`K6Ga#biR0Ct`@=p6w-i3@k zImjTtbL=OZXqCOZX}vm8YWXjw5KQ81?xiZ;9>h)IRsC*i$!wa(HAzv7yszk#SxXP!joYIM zPbsArbSjLEe$OJuTqW*aKUDavgLr*C6W=$K$AE%tD-8N!(MNq0A`M}oW^jUHqn)Pu zL%8KpzbfhX3StXnjw=Uqlv!-V6*t@?Ue#jj4HqMq%!=DJW6XDgb$5P3cw>pU{q@rzNiPB zC`<=L9B+UjZC%d69#kSrH^&Fu{}9z!xDyNs(O>KfPPS&HsKQb%hsLBEOd(x#N*D!G zR(%Z3I<1?4NZJGYCa6l~IVw76kpw{psV#+a3m z6YYDo@!unlE{+1iJgr%YEq%uTHhhnPJ2Dxjfzx$K@Rj00 ztFa!>sN<9@IjYEKLn}8_g7#FYXQS->4PoRnlVMsw*!AoYh>goUw$<7!YAne0SKNkpXL+fKLDMnv4gJf$#+N8HEU0 z4292lJ6`q$K9}?)OqEMyQMh0@i9cQrR&#@YN2}k2iX}P)GMYJ61Qj=Vc)G^x|Hu`N z?D3E(RY#hH>-6e+VeZ=Ho5Pxtslkyech|6-R*~_k4T0c3hn~BKk)!Gj$!#}>t2^42 z+Il1uMRw+c%j%g&@TJO2c^Y>WahEJ2LgrgK zyep&f*qupdbx+uE!f!jNxC^K<{-@e(r0n3pr1X#HRt6gY6VTprerJi$zVE3+vWPN^ zD{VGkZvIR8*&lM@z=bb(ZZvb?>Sq#$#en~&k&pYXj@iR3eVY$XOIu%|WK?{pX6iJw zCl-zRa)R*slu@=q>x1WxN&@+9b((OQMQ< z=!1l0cjedxaE}$ArYSGZMryr5sE zxw`5@N}K28V>7tSq?5u8vA3Z(O%U@&Hb9o)mFt-5H(+TK7SCgwkPuQAcz@ivm3z^8 zeXk{8vb^ripjE_sZCIP~INR#7V#C`JzqHTZfwN67tWz=?g=`>ID}{7DppfBnu0*2y zT17T&RXJ5&23bc%Ql4LIKV13^xGvF`v;Upd5?r4VwW!bT8JRZ`@^PHhJUJg-uJgz$ zS!Hg+g*&U5a8PiGmN*FZmF2F4Nyakf8u^=X(U^1?F*Fb%=t@nLygUFhlR!upH+p>V zeGoR6FlZ!rB?Y>5O}h}+u6AEVO1BpQKg2)4To#EQ#v0Hff%vpXal2f+|1BU${eIfG zLD1&6@uIa8>iS%`VA*rnwzV>F<~?EJ_-Bl^Pg2sOT&vn(vI&vluuLbA?~jPcmLD7hq^w?Xj} z6GBy3KT2taDMg^C*s8r(n8pN(%>@xTZOX=XnWucwOXn3sR?OM8bqbUgi%n~#UTf_G z<+6yHK*`ivkMbXzN3r`6wiJPB(|0gmBDXNGAbOqNRyXmR$}QwV66J>3n7qoi!q_IS z@#1!%2s#&bE)@li{>Y71h4NlyS$SBhrt< z0JjR*-4t(ooT}6BYj?UI*K2m)*46%keZy{I&xfc@oGW%a`X>~-%>nTgOuB@^1E2A^ z8$f*Sj{fQKXw$8{dm$-!JF}}l5Z#72DLLxut6iV$r}}y09C2@3RD$5!yYe8cpMY!a=v^rjTHzW^yS9D8%+!1$Jm#M!bZ5~# zPg~e!E6G*^nA)U=DqfP|(y2%1&vBFgFtr))*0{2$sHde>eUx>HsHyHVo;NlV-TN`I zDfjkWuJfHQDD3r8&lf77ye>n;ShKcXyQkh;g#L+oXU~)#(*VzJks}gKF zU30^}{b=)xJMbPNX=86nCEu{i*kMwJq;w%|MbYZ%K*ecQ*CZ`f7(161htw&(D% zgrLvo*)6oye>F7#HDbUEiGtXdu<_=mLry`d=2R=0t%!X=b>nULjFLQMS)FJNc7;Q% z@y#F)3_b_K;Y{fcRk!_(@+0Gd*gZG6(!%wv$xFc|q|&Mwu3WKSOS^Dxiv|sXe99B! zJm8-oI=f}-zUS}7rg<8sKiP9qKBEQ^Xvv(n!%89O7!_ox4S9JgIb)%G1RGOIU2VUO zypEFHs!wAs`t(!}`G%by|GL$_7(LXveSoGgeeqb}sxwxBbCD3w;uG8sBWOb?gg6tzXHVLH^o>sVl|nIC+iSya%?1 zd<356*vC!23y-Sz@ed!}%MoBQv&}zQ_CZdz8#Bc@SfPs(cj|5RqAy@KKFVN-ghb*v zO**&GjZi2`fVGLw-+tHtqq~1w1?N3sA z^*C8Epg7w=3~o2AXB9@%>aKanX>Q59;7k#nv{!z~8Y+=1L=Q+o_25!eZ~Xx>=DQ=i zOSCk?IfnzWy;*xm^5St)VFr#2vyvR8$pnsLPE8*t=Gfj3K@V%^W}XgxMX8y2<7RCF!X{bky|vw{`iVwLG9| zUpBsqR9`4xcm}ut^8x2X$jS(EvbSG7x*%0L*JxnZJ1Gbi_0{fI5N#yN?GFgreIu^B z8G4P%pDqIx_Q9dmzvUUoq!%@Vi&(jT7P=V}!-ojeMlI4Sx(~Z)jQJS7o`R)AL{naenL}EDo<%oMCls zzf~&GBmADED`5BomuGjpY1Pzpx@p80zbDEyvOM^D`}v9TZEP^;N(;tFq+zl+5yY;Y z-_xQfDlSfpMtoc%uz@m(i~E8rJ-_N)rZXs|!yaZstt+HLW=nw>OHbzhAxd8?%&lv{KT-u4CIOt zMLfeRBh^aZDclV2aM2R)Vchtc>M>)kypw`NW61@n;V5Dz{1$~^W^vd)YfUl^ zSUJnY>hVH0urwA0o7=~GWNNt*P=z5ot=DL>3T{pTW>sUc0fET7jnQxkh{dMiED?7M z#UGWtt0m%iFW>=#^x(@8N$5S)AaJ6uk*k* zLy6$_=55?t;sfi`X4$3o1K0DFyUx;2_10}Zh7p=%3R|x=eFmq8A-J2kYH$*m63kdE zg8VhFyOe^{F4*uBSlNax0GpDM(tjunzy)O&Am*F-`euFl z?7V*Z4hSN}lEQr29c(=ga(tTpuw*~Mx4B(HZdbNl?Djwrh)@j>y!H@Wm8x}|Jn@wP zBY-_S2%iDwtRHTajcLO_xaS%;Spr+SH``u(P|U*&l>k#}AlVmlT`-9Hdz`v;HSJpv zOBVe|VnO+MiSDo36ckX&gMalgje!CdVy?6`#W?eRM{y~cNoj}>8UrRt9TONjbH&My zg%f!g^>uJ{odF_*PCwjd`=~=yVt;w=7vQByI2$8rZo7f&o?S1$EFnS;I=yxJxDj+q zHXj|5g%w^iP9AJDt0Sgh2-EfM>e?|NgZCh`)-vO_vE5LIpTh8x! z&KofQ*?YX+d);MtCywEN=afW%c>sdX*=HIp4&Z;sg02$GuKzPjbS#cmWF>AT-Ms?z)7~$!LwZCat^{ zCCzT3v(H)Kvsq3%TK5*N*+mEao1R9shLpFY_;q;blrszwokvd+9qtt(@#wl0w!SWOIjTU0c}dnkg0i^{ zgGE)q)iY0I&4D0iUe=6OL85Op(vq5aJy|mWJD@D^xH;QAI)*hvFQ`&|^5egTg_>bV zXNwEe^}4$iFT#7Ter7Eui!rx$>EJBG2wj&EZGOD;lez`;2!Oif72(r92GPGE`O~mz zyP?X54&*ayll`)O2;vT8aayhiaY5bBt@OrHx?WAn8+ZX9Ep5Lyz>{YLG>i&ED? zEtj?4UpRx2@+*rtmWwQDc99;qAa|hIKuD@9g0nG*!H%U$mONc-nTF*gutOh`dceG9 z^tMXnc-cCti6e%a3GvuFFzJHQSJP}eSCQc5^FsJ(#4o6ZhA$>ugTi<^ThOk&iqa13MuAgjIDs%9#S2m7XG z-BHT4>Ykqa*a)Rl<5>@{J@0k$-uCRvJ7I2{qXS)j{+r~7n3xP=WxjsoU)=c4pN4&n z$vItL_v>0eZVNsQ!qx$>M!hB-$lt?5Y;5eF+w~80fLAgJh=xEoUC*$1T+cwdZ+UTk zLEhfp;_wVyVx&~ScVMtkmiFkUJ6E`N+oMg4p z-zl3+2(yBn1+0Lq*A^qzJSOj!WPc3wHh0vq;0MW1L9+VVp9S?Iglr}ZE*i!260|KU z<|K@Y@+vTQgr-~(N794)8z{PJv1;0kECcgJ!wz3~b*f9!eH%jLid7a@bbdriLog#F zX5|Pr0&@9r@O!+U{AIL{p|*eP>f)KxmD9A!6+Bldw1au61IubzOPQP|kQ@WhFywF~ zeFtM!)4BfsvTxt;mqwzOC{G-opYdH((yh^U{s0XWRa4~q7Unkd1_jBkKb8NC8h;@5 zFQ@3ZflODt8>e%F8S`JEqa>=1XGQGT$I!ReZ8kUFvZZ4w^(OLqCM!zW?2p$&0A8|9 z#^3=H!+SF9=acMVDR^?n z41{ESSPLy694-vXa}>^J;2d{#1t{QFR2}*9pPGd%(G*gNLde)6;)f-!%@090cnKH3 zhu^1aRL&iqqTz^Fhwp)Fg&sE-4Q^;v-b3|u>nBaM_3BT0Fsrb@jfo=p1djvZBq>$*1k*QX zz#)-J0LlJ1Gn!z{PcH!|7t;ZZhLi@IwBI+6Rrp3(To&vI2=OsfCn~coN^w?HB*Kse zt*Ve$VE+oCyx?_SuRJB_-t?f4v7rZ*!baVg+9I+nZm#IWQ143cJ9y;gc&kQXBQqgoIsK%u-@yU)GrMkd7NTfxa+uc2 za`r$8^XepvOWw)n*BxkJ+d$G}2Vi0x zGQ96H{Ad36{bgm!5df5Zig2$_)Y|x;0Y9hcFnrISz;=1?AD#r$cLx(m$R2PByAI`O z4`}K*x54B0%?N_}dUMPFaXWQb@}_M5VB>e|P0%aw@`;@l;4jY+JS{)xIl- zuNl=tEVswBYn`qyC5&(6S4|U=y6Xte{<{WBto!!^`ryU5$QbgH#PD=1^-c4L&AE)s zgIv<8(Nd@3N7KawR*@zHL|SXzb?IZhNg(}l#TVtZZ+a|dWpHTd3XJfD+TcL*1d=v9 zO0w*8d?6IM<_)$E_N7ZaLy<6Q23z!Q{(LE0ZutzypsM#PfA`;y#JlQ_90;Xfs4V(4 zyZTJ>JplG`?T-Tte?J{7LF@qYumAjpI(=ULXQu@6>1O7>ajH9nuBIJu=;8gkM?fGu z|G6c63YsJ>h~n@($1JC03gC6=dJ@Tu?hx+?4OmZhVS*Ug(iHZ^h!cslqK+Vc*GiU@ zq*lTl9r*+F$5u``(1>h8an#p56Uic44~=+m(4=d6k^_7){yd#?$CH|gU?&vt ze1zeXM*U@2=Wt>tC(6$D6LVhq{@z`Rtnt`yqO5KA9PKAC^Z=?(RY=!qu4yMSd0H%2 z3PHIYEc0^AQ#6NKgVFZne)|=T8Qqqmjs)`I@(ZkpfwoQLUTxL@wUjC<@6&yfK*LMd z#SnGCbf70$A#1!tFUuL8o@tF1aoRUfn&ARbEVH+Tt(7w?;DDz6q^6nG?&1>Tyu}Bl zPqAMU2G81t-|D5(!oF7LIm*70wmks}ZE#IPWwE5E!rl2?^1ms8M{=~+r%sBttXYP%>wd{sG z$x?p7L{_n`l~%$mLwhRgrQYmc%LKR-rI7pm9dj8r~TAd;HE%V zN~8)Qfh#exidm3E82L%Il}!BQ7oTG8Mnv(Vp(ldUSy1cYm?efED>*81PyFGPcP|26 zz^TUX2`&%%tCW5Jy)^>$+EHTE@H;w7T0x0ERF19AXLm)=*^M9Lv`TSt43fs@vG7Dl?s;^th)k zR(Tb%JXg)gZS70d`qTw;HyGo3DhiyP1s3E|f2%vP=EjRAIgy{r;P^`S#e^$Qx&uqF zQNy!MJFil&apBLGcDv1*;l(kz9h+m~{2q*~L~{Ey-D>L+{C~(bj#3|1nO^c4MGzfm zNc6C;MZ~-PVG}STD?aaCgoIPk>;JTk5C4Ihj#)dcr3PUAaAxMog|cHrc`incrFtIL&ArC0*we-F>rV zV54_0TqRk=&tf${#drXWIieB`fpQ%05*XNKA)2q)zgl0b7&wR3+9Qi!8S&2S$@7wB z4iLS{ZjFuNjW&=w`MXf}TJVeRz&k3y;sjaq7Vm!5zsdDO2YQ4o1-Rqk9Hg>799d&f zPU$nl&}ECzke}E@C!K&-|Hp%v&Hq|Af)d4cHQxKiw_OC+4%H zBN2?Ty+E~kn41&^OH05V(5@01kVEb@3>cR%JfEA`*gP~}7KIIJL@9$9ISJ1qzLUlUBO)aOjU%G6nX5t`Vi_iluU;R|mKbx)?2N%u^ljs%vB`9b zt%??^S}(jVK*8!BWUOWKGIxZ0A-a%y=^efUgFq2%7a5m>Ii8Sk2~D*q5|rAYsJg_w zzM-mksJ>MSDJ2oJ+9KcKd#F7PC2?|a9ya@^1w+ae*sr^#=vO##al+Z^qM$4){=Gxb zM~=;glP-qV4-j9e9M9>MJmg3isYAF}UVdhM6kdS?H{ z%35Zf7WZD4hrSPfN|Ax%rRDwQ*3{9_QH%`dOeSK=CYQ`Xs@ApnIXHVuPHZ$**a(=YcJDjy*NEl-(0>hX;ynJ(f-QOUzZdPN>!?z zOrYTS;}otAjWj@7&RBh)dDGapb}VN*;2Pow3-<4TP4WB7*$QO$2EjsE1q}|$m86DoW2vV$$~9Dd%y8tJGGXICdzdNtC0XWvCP4-$Eyv{&9*fm-m+d?}^Xh zQ5x_x!~17JHm_(fL{6KUe963EbIR&CMKpJRjYGA054awr6iiwwiY)&O_X6E|Uer~l zC93`z$CfPopNN7!HY=gK#bhkGr^|1T!#79|FcOA%tbw6WleOJBwe#Zn%+|CEBxnRo zkPg-8pQN+zD(qSLA;G+V2{ zaHPE$TV<4EBMl(J#{RMltVs>(a(!v}`Uqb#Ut_(bG#%`msaSCW!$@xqDFemL2nsHR z?=cZCjvrk3auI3Ah_9-qKMk|^#OrRw>QIa{@^ z|1(e0U>UP6u_{HjUmJ7x@o|5_*Is%f{rK^q5#}?>6(B&G3IYnA=-C~Yc04uKcg5_& z?NF!~a$oc)EY-lxy{w5{A!||LFF6||yXK4~%0t4j%LsLOL-up}*hm20UbN=7O8 zlL={<>!p6t)7P(@lytwIV;}nAu$9%Ts^NZfN_XXq=ag%`X^@iYp zyu0R1>d#nvI+U5N@cVjC-?HsNrB4@8e&g(aqsgP&X=J z5~|Y(FEpGvJC;;@A1Ayh-<~{uJxs`s%^B`F?cGk))Pq(Ya`d?J%X|xGbH0TjW=NoH zE$~I2XsShIPj~-IfaAo*_YBq3jLL~LcwupL8SnpYnWvrZ9w3#$i1k}QHbbO;YNE){ zhaaCV9Ldr#Lxeea#bA09Nl@drxk1ELuKZSf3)Hz zq)Gg7VixN^#T8Vg+8Mb>JSSQ5({3IU79- z)E(=&+}B$L83VV6txP*#7-0*%DblfMm!*}c*7rx#Wl5A8lzqtDew|3S7`cO^&L61` zA&soEh2&}H2Ci7!lqW_S(vhrp8Z^*XI~^rS(sj3)C%W4bA029kNmi zf(tPHLQz+Tx2dcov&(9@HLC&3k6{T%+PGu6_ZiqRdl(%071yX{D+6r$Cs!W3Mwy}-w!oC* z9K4STPrJRC6h(hh952#wQ+dV&Pa8J z!q=_QYS%oW*=d&~&S1!ch9beo?M^nR2z{B$A;TT3?A!O|3nIul_s+pF$KmLH3z&!O zZ^crjCIhW8{8Vgv?({U|!JI5nW8EuczMKgUh-QXpgOnbYBx2JhrZdj4Lg&UB4)6zY zSK}A+9tKHQZO`ijN~JBv;?a(?UjW~J?coC!CY zT(hicM`-p=c*^trQ7*bZe@TBJ9m!%`8b6~;wBGKl`XV)Gc`2J58#hqZW9P6Tky|-t zxGq&;0K3JmC#2~it;tuv+Ub$j`0f;CzQOk{?AKBI!3T~VQQlg()o=>harQaAyqEAn z1WMnBy!on5CE}6bU?dW2Z7A8gKD}&!Rl}b`Ro&J4^UDg%Bu`ORZFyd>G?cK1aVm`U zfg0mIN!wFye&F^bG8sZJeFK=5M3 zqB{}?_pmr=$Xw|c91_#%RWu@+rXcrZxU5{GQXEFT%VYV){wEzcBJx6qZ=8MN=;3%* zIOmfvjO40e#A%s1Wcay!c%*$1dlo^>W(ph3T<03qd`Yi!V&#zO`gw+z&jy_+l0D_( zG}DcGYb^3sbH*mIY2OC^ud%m)sw(Q*g^}(?8bs;th9fPFqI9ElcOxxGhoq!}Al)S) zaU`U>yStmaj^F?N|GnQk?ijyg92^5Zd#}CrT5~@0na`TDQg6kPylTG9?vj8fmb2}Q zfY$=F;r=GtsyLy$r>Ud*ChRcPABE(Z`KZX z7W^oWt+&WF_VuNYF@wcW7Sut@+;b0Pjr6FIC98CP7Q`>zJ4eY+kU}US%F=fuXA)J(asXea~!`p8o!v|{U zPI{F6mwv`9X#cfvQ)cBJ@=oq_^Q1=Lyp@Y8x)atbw}D!|)rVpohTMBPK`wv%IMU0q zqq$f^n^`L!3rnoiQZb^@Bf*)JkOx7@?7~O8u}q26_gUBJ3Nr)a9yC!3BtCPoVQAGUcUw`8OQXUnV?{JH*SJ4s=s8)3Do7nOjI8NBm$hH-OGKj)VDtqCDv}baW3< zId{RJ>0}~J4j4s~VqHA!ZccieMZ@ePJxP*l2gFIQ*^}os4#$K!P-YRJ$M>L z_rmI`oyR!a7KdeRi7$kcAYy5bzclmYNosyp;=?_Y`tUvtB&#@&lOlwCg!WWy?uTRp zI>$-?id*{l*LQ!a?)T(FomUQHO%Ij2?KBYQ2v)PLmgWxcN3WRR^jm|;qDX&yd+sof zM{iy|oL%KuMd^|rHEtG*rxY8Pv}Ba~7?YilbKf>?l{d0AoP?o5)A@=V3?E&Dgl8sv zBCJC9z9x_vO?c|k+Holm|^;C4f)PSWcfwJd&CtaKcl}X({uVN zEIb`$pQnfMC87PsCB2SI2W32uhs^i6!_(-{vEVeUcx|dt=kz~SGhD|h6c%)lx~Og= z)EC$;^d5i`(~uw>y2-4;X*q*7SVF#5o%})91N(lH5Up z-S3@UIjFVr((ke}eAP_MAi!K=!0+$vd5BVMu`*a+1BYm*n_#n zsCdPrqH7Z`MAgevK0|Yww?O@59TZhN%m^1b3{WV>-eMfta?bPNeR*=8DZYpIsgGad z=(Y2wpgJGtSh+KzLUn1eCZ0Nno%W&Ao2L@QlAo5rUMtvS%0){@FjRo3Zr`>3lx{dW z$n!0;x$xbkQpnPe(WaKBBcd+Z7PGr}a90sEySQZLG(k3Si@$p*vcC+c?G`Do!Gi2( zycb>j>=Xl{+!PgLnVv-JF!uZ;e5WNM{l09mYdk`hA&7!U;gt|!NLo+&h~)0EPlgf> z@G!~gk4cWQdC{>WR7ych~Zt|43J}!RMKdN1+OZR@nc6|e1fNSzTs?VNu zP+j_RGh-%*D5&LU#vFD=PxwK^bA;h9Sufkl#gs%bzjGyZYp~<-sJxcN2wit%b+c;F zMlsp!lvi^6q_Q7Z=59~_s4f!pt3<}dndjeg7fw!;;Om+&%SC6F)a-k|30fTJ~i#F=SQ)!v*@ z`AxcuAb;qI#kr(XO_~tHT>otj)B7njg)EN@wO^?k*fRl2f34TmONP3`4V5SBjd~#B z3eY*YtR6AUmyX}U-KAve(Fn@s5mk@n<*<8Vs4X6cLz)}}P&(e7(6w1gXvr+muSymitRsZ<*$fmVT`Qf7=Q zf0S}XPNCRgj|L|em;04bM0>4=oz%D}_V@JPRmD|C=QuYv$DgRh&dT~Ki)*BZpDf+q zNRn0ZSVV_r*IcHQZ(bLo{rZ6vDl4Omy)az2r#VzTC zX(kmU$%cMH#~u_=N3B{LQV_7Mwgn)t8n$GZLZcmf=#q~>QCfUd#81%GIhRr8yNkNk z@7dWOLBE2`k&!oW6J>^j8-LTeloO~Qj>1^=8(nM`GjPr097zSC2m+{XKP9+{#ceXB zot+UmtQtu5RoZ5C2^IUQ6!S9XxYJz#o63em zOFeu(-{R2RjQ2`Ap}+q5s!0?VT_|!qTYxyUFxIf8m<{h4S)IHK;*SQVU!6y$bR?K3 zKMn6A`ummQduX%n_sp+B#}GLg86@k8V&m(R^*Og$TbqUERM4#HE2v$ckem#CxWAol zbY;1mcc&hNJc@c>9((}P)(ncq_?+}G{8RaWQag%;6D7DSXHk7z1IKNz0?j2Em$ew2CC5d~seeFV!EZg%~Egdd@6FQ^Iyh zlzQxGxEt)ze--aB>abvb53fThx4uQ5JXTv;CaZ2O=Eo!! z%@fd!0{)}zY;A?px&qu6HeHYx26=-t*l&EUodVmR@tE~z7Z*nYb%&|VLL#m?O~Z<) z{B{hr+$@#sA8AX-5HE^k%06-_wnP1kWJphuS>F>2rMF%FtQ1EuQ`yz(LuZkMMIJj+QPMiEAL`#oaIQG#9wZ0 zbr!wYXk>@gnZLa}+>91EFq$aVUfb9((SEpPW@pc@t$q4&W=1DpH4FRW2ko`BHHW<^ zE-Pzm?Pd?hOXmxp{+^XxUZz zktyvWt}+?PuIwLjymWry%H^dZ7Q2k@ee1@!B1l9&UFZ;VI((QFrhpz*ZF)Qqoo+ME zY6T>$8>_m#;thrKFR^w>>s#B7@}o;4B*3Pv;>$Tr`_yF?@&quZqhn*8|5ElK z*&MUATVn7lZTzPuLb=6oE}kzN&A?N9L6l)<6NPPvXml-KPq2(S_wS|!-iO^$ZHnu1 zxT=n}9@2-U?KL6GC^=c(pkQtSi$M;iiN)d-0J~{ZOTznYpR*8d`aeu|2N*&|JN7tV z@uEmrz8&hQQXcY~uE>M(9M7ol-HgLP7Ey$HG7*)_b4_RK;M!>1o|KSjtDA-pN{FTJ z-><(Ic>cDw#{a@miOil>x3go{H1MP=Ykd$_R#p~_4*H-?A?}l6Ihy~3({_dzn^IUB z5KGakLvwRV5)u-Z7wlrxFM>%txw}(~1~7iA2?m7avVW1fXJ`oCRjRalmS=|efGl4{ zJW`5*3&C#>*G4G)>LNu3oSQ0(|HeLUS(!3creuhI!x~$FHw;`D3WW6x7uT;D#*{4IfUD`_lzt zK&gXxVnZLik8HZN4*NBe@M;DI17I`3d4NJ&4Le0Y)f8TX-%OO~hC^2=1RXx^>{vZ) z#XMO2+fg}a-d)-^t59#(pV7QYZ?m)Wg!*^05=SPeev4bV=jWa7>JR8^hR1E`vT*A= z8{S|iD~WWr>-v3}Sgn4NN}bw#I@Pw>rNsEQNq+AYw#vei_A{%N3#<*l0(^nJoK^bL zpGUtN2l3E%o;pd@4KF;Yw409*6(Din}cryKYm9EEWFazCcVDCwwZ4v`iO+_)B(sD zc>EuHSo>Cb7_t&cYa}Ccfk${8I${EQ8wCmQE1sYl?xdIha(+Uq3+H#pOfcy?sflIL zqdEkR8EU&irP}SnwJiRdcW=0r7p~0?PkC?S&@(V0kh1Zdw%{Q=g24$vuPw!y_g}&k z$SgWK`W+mrMy<#&TD0Y7_h^|ro}D;a86FtCI$hS!b8nIB`yGPexm!|qW0NK1Y}Q(3 zB9(*t2-4Iuht6W4ytwGm%Nr)#5ZnTLAGdL<)~7E%CLBTQ&F+lU%cMeCrUM2X99~dW zO=@EHokpQ)UZc%b-LQujwmec{&)vHg9k!xW8&>gn*~MSc65GU7Mg_Ino9du!tdTIU zt;n(^7N-7c2@LVq?ExWo%ISQs1U0B(gy%S99P?gd5#qM7xOjPtG5{K62Mam_Ql&5+ zeV(MPQeSCy|A3w{ZnBd1$7oi7@RvPV3`&9FgQZrLL1YFfo%0(JGnJ9D9HCB~el^DM zH)J2Y{2Xnu!bOv7x5=8`8Oxy9>+WUH_KyAdsF>YwXkC*fB0XY66HH=0a!@4ZvV|)! z??P~Xe$Mz^>z5ZFtOOb~hI%uU+%7vmKNPrj1CM2-larGn9cSR^s(f$Vp2wl8LhgCN z+CI)Mb9@j|pK{(5VDw&YqRrzs`<+D*A0f0@BAxEnzLQDnj+`r^wC9E}K6vS_N&I8j z%2@WDyH`WyCN=#u$=Z@_NBYX)+wZ~~SM7C^YA0i|3%}g-dk61TuH93v=U!M$zC_Y5 z{-`*@HKZ-?;+--S*PizPVq8+GMr)SD?}iC@5HeoiH-i*Qa!K zb=C7Z?y9b>b%FsG;LZXIvi#ES?tEbF)IzbyEo^MwuXab-EVg{5zTc9A{XO60{_g>S z7nd+J9nO{6o31h+GF8Z2_|u+#NPd>`kZ4={vcZpdqi0r3cQu4h$1+jFVpa-C)Fmu@ ze1$>Ufm@98j%(s=<7bGoCSB|8a%XBAcM5n?vq!AOofgBJ&Q-*iRH>&0?AP0-aKXTP zUtMf}{hT@|7D&z~RA2PC=*yh-wJIqiy*;V)KIXOm-!v?LuAMTbQ2w#jr0O!k&k+%f z%*^o5SXe%Lo^HI>)$Oabot_k~YFde4nW}euFNANYq z>8SdZ11e1?r_lO3qphv2p8LG3&*SYPgGkdQ8Paz`h3^9C1?E=eMm;W~Ecfg5Qc;!% z-VR4BE!`KK5`8&2Y(f3~B&Fs68#+P_i5~ZP{wJUNVQv)3nz`q0t{`REM!Z?zp4|&@c#jA_{&#Ga^>X{GEA=@@Vo^yCQt(b;Qo5^=C9X#gb_Qv~d(K&_V*jAj?I3FRB1n8TTrh2HX!(gX|YTcQjM`dw6ERtK)vOd9M~DKm8? zsEVgfSnr8x4Tc#0d`VO^s>7n~`zV%px5fpZ5UTY(D?gwy406{k=Ce_{km^wM$o{LM zIY?j;8voc7iYcNpSMkHo=m_eMf9Ol+UF7*5nm!%#Hn#s5wI;1Tr+w0E;J(%{VJ!72 zb%ivkBJArh>775xhgNbL>Zna=OGi4Q(vsYsMc73oZ<)vr$y9D5~-Vr|1_@;JDEp}L!is((F9mzJ&Zxf98OYcq&+ak0_+59~d<_f(9^ar&e4}Od zF}X$JfJj?Alg!w_W6}3e#I#krHDB@^2Y%I$BE#@siVzsW+;7Bc?XB|9R#jfEx|td9Wq{TJcMdR<;Z|JLF88-xbpG*zy*`5U@dVXi zPx_`2=kPq{>+xXBlB?EymG3+*Vhjs@12QG0gwt;>|9~A-;oMj6t>6ApB{?LbACgB<4HzErBr~D64TqD%*XHfyK?@)MCAz>(zZcxtf7kIg4 z?QHmL$zM(437I{|9>E?yM+Zs_Ql_#*W!w-<{m`Y&mth=QKPEwS!llrEYrki6V zTYimRs?dxu7S8wxj{t^q!4TZlnJdhUXh~}s73~+w?Rx$E2)0)JvaO;?#6uSQs<~)> zWNn{r8&r8t@_4)Niy_P+63{a^;jNYTOfv;QcE3jkKiwE!{Uo4W zP8)N7kH>k>l5a86JsMHm6Xil{n>O>Dx9fMcTQKTcXKMUxL;;cOA<<2Z5L?X4KkZmo zmM4ih;lcR4)V? zpDE+Z`+4To=C|j49lTZn{Z-5-|5E`}ODs8TH=2u{TfJ|^rNvm|4799m@9)Z(hK)062oRJ%{GoK{PW z)oeS!Q+$>k(!t}@kI!tc?l)uYcwtdrud{3^b1tM= zt%T^C*%dA2m1Ut)RZ$nhA?4&nK;C})l2zB5T8AJcv~^()wl-oqZv}h^`IwX$1Yhz~ z_E8C%iZ>F&ou-x35#jkgpK(uZp0^99&7pGHjxHk|sqxbNuBHnN zW(~s>3CQ7PJI19MZ68Liq4c}_`4bCR>il)y1Y4*>wZ!ilkJgsh_x-=o8>I_`I`bL# znEbq2rFB0pEyG#G3h^5FqH@f(+f*JEQzdD5Ias|Qkq3epLDhbKr#}7# z^Uds+jsVkZkIeROuSA605<#|VS|c(xj`lrmDw$RLA97*uScSkhxM=i3^-lZcnLp#O z)3O?>Mh?ludr%e)q_%zp%v+dr6Sk|OWOgPhG*sv_8U38j5#@}rj%u1vwV>*5rh>waeUS=mf*p!m*I zD-_BAb+U*E8`g1b<_og$j*a{TiJmz?v{aC_aFnbTlF*sQg%aS+O)b3>Gqb&?8i*tj zwi-E-AIOHf0qnEQJ78c4xE;} zy1BWP`6@6alC`A%0sX|y1~bI~;SvT)5aZ0AqC4^@v@vxuD$pnVi@LA-3^y`6;N_WyULX81D+0Sgj^Ez|Gn$gSzzl3lE(Hs^uWN0p5hNiVC)jj0{L( zCEgykwt7nr{VZ$gy*b~7u8AqXU9}Xgf*{nWc8fz%&@xt2GQtQ3f}M}k7wCAr z?I;arBZ^NvK+WnugM-xR0(70)7J36kM3R`TJhp-3+a!mY83=JK1H)W^4ssOeZZL&n zgZHVZt*w3ORm(G8^zJ7J>DTT~2M-tAm_IKwG%hP)J_7-Xtsaufq-(=!w1~%glI9dB zP7E3kQvjZea@Q;>CEdOyl~Tm*Z05^>$rVq#106EJD#M(m@S9*gN`M%Z$9#Ym7Zo-& zfNtWS_)EqG5`~^w6@~wuAOZw&4>(%#`CuQ$Bq}gH8J zsjm-UWL*xl|L@4YCmSfZy7Hl5Q#^}%1uLZA+t&we)Xpoi<`Nw;=epw=6b+h4({FNf z|2qjTzMxF(zqtXPw3PSup{_&3!Ax&^f+sNNQ z+CEK{EImhb@Kwv$HgG-3Zxa7?ePpx@Z~(zXP1<=z&|WPxrqvoqucsN}^ya^uSc)Fw4j4o|-|Y$V*iA+%qzN zvrOS!Fn{vCRJmx=cYd>>$w2em(`VD~yEpIYH|Uv%__#SpOiVC{xeu;x`!>Ue?A%jr zHT-=PD%^??e^LQ~<+b_v_=wi4ptlGapPj0OWldjk@j$lFGAmjl=$EUiF7>NPggem#d(pVjjW<1KA zgbJiajGUN{knh5m?(+u~hD@A0a{?m%%#XS^oxZ{`nnn≪02CyINip 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�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 ZIW$3#!(*ed#}NYlR1`E3MRHHy{vWgV6Bqyh literal 0 HcmV?d00001 diff --git a/_images/local_ndvi.jpg b/_images/local_ndvi.jpg new file mode 100644 index 0000000000000000000000000000000000000000..75c523dccbed143016ff1c8fc33c41b9f6cbd107 GIT binary patch literal 96185 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�fF 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 g+zNx}spK~^Ui>fC7XK{|@;};N{2$+g_P5=M^ literal 0 HcmV?d00001 diff --git a/_images/logging_arrayshape.png b/_images/logging_arrayshape.png new file mode 100644 index 0000000000000000000000000000000000000000..c8b8535efe4e4d9261585565c08b5807aea39375 GIT binary patch literal 65288 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 literal 0 HcmV?d00001 diff --git a/_images/welcome.png b/_images/welcome.png new file mode 100644 index 0000000000000000000000000000000000000000..84951d060af1d8b323509c619fc0457983efce23 GIT binary patch literal 92455 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 ZSIR!Tih}+U#5mwb`H7lB;bW6`{|}&iuCxFE literal 0 HcmV?d00001 diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 000000000..1931fd475 --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,144 @@ + + + + + + + Overview: module code — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/api/logs.html b/_modules/openeo/api/logs.html new file mode 100644 index 000000000..d5dabfec0 --- /dev/null +++ b/_modules/openeo/api/logs.html @@ -0,0 +1,227 @@ + + + + + + + openeo.api.logs — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.api.logs

    +import logging
    +from typing import Optional, Union
    +
    +
    +
    +[docs] +class LogEntry(dict): + """ + Log message and info for jobs and services + + Fields: + - ``id``: Unique ID for the log, string, REQUIRED + - ``code``: Error code, string, optional + - ``level``: Severity level, string (error, warning, info or debug), REQUIRED + - ``message``: Error message, string, REQUIRED + - ``time``: Date and time of the error event as RFC3339 date-time, string, available since API 1.1.0 + - ``path``: A "stack trace" for the process, array of dicts + - ``links``: Related links, array of dicts + - ``usage``: Usage metrics available as property 'usage', dict, available since API 1.1.0 + May contain the following metrics: cpu, memory, duration, network, disk, storage and other custom ones + Each of the metrics is also a dict with the following parts: value (numeric) and unit (string) + - ``data``: Arbitrary data the user wants to "log" for debugging purposes. + Please note that this property may not exist as there's a difference + between None and non-existing. None for example refers to no-data in + many cases while the absence of the property means that the user did + not provide any data for debugging. + """ + + _required = {"id", "level", "message"} + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Check required fields + missing = self._required.difference(self.keys()) + if missing: + raise ValueError("Missing required fields: {m}".format(m=sorted(missing))) + + @property + def id(self): + return self["id"] + + # Legacy alias + log_id = id + + @property + def message(self): + return self["message"] + + @property + def level(self): + return self["level"]
    + + + # TODO: add properties for "code", "time", "path", "links" and "data" with sensible defaults? + + +
    +[docs] +def normalize_log_level( + log_level: Union[int, str, None], default: int = logging.DEBUG +) -> int: + """ + Helper function to convert a openEO API log level (e.g. string "error") + to the integer constants defined in Python's standard library ``logging`` module (e.g. ``logging.ERROR``). + + :param log_level: log level to normalize: a log level string in the style of + the openEO API ("error", "warning", "info", or "debug"), + an integer value (e.g. a ``logging`` constant), or ``None``. + + :param default: fallback log level to return on unknown log level strings or ``None`` input. + + :raises TypeError: when log_level is any other type than str, an int or None. + :return: One of the following log level constants from the standard module ``logging``: + ``logging.ERROR``, ``logging.WARNING``, ``logging.INFO``, or ``logging.DEBUG`` . + """ + if isinstance(log_level, str): + log_level = log_level.upper() + if log_level in ["CRITICAL", "ERROR", "FATAL"]: + return logging.ERROR + elif log_level in ["WARNING", "WARN"]: + return logging.WARNING + elif log_level == "INFO": + return logging.INFO + elif log_level == "DEBUG": + return logging.DEBUG + else: + return default + elif isinstance(log_level, int): + return log_level + elif log_level is None: + return default + else: + raise TypeError( + f"Value for log_level is not an int or str: type={type(log_level)}, value={log_level!r}" + )
    + + + +def log_level_name(log_level: Union[int, str, None]) -> str: + """ + Get the name of a normalized log level. + This value conforms to log level names used in the openEO API. + """ + return logging.getLevelName(normalize_log_level(log_level)).lower() +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/api/process.html b/_modules/openeo/api/process.html new file mode 100644 index 000000000..a787d22eb --- /dev/null +++ b/_modules/openeo/api/process.html @@ -0,0 +1,290 @@ + + + + + + + openeo.api.process — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.api.process

    +from __future__ import annotations
    +
    +import warnings
    +from typing import Union, Optional, List
    +
    +
    +
    +[docs] +class Parameter: + """ + Wrapper for a process parameter, as used in predefined and user-defined processes. + """ + # TODO unify with openeo.internal.processes.parse.Parameter? + + _DEFAULT_UNDEFINED = object() + + def __init__( + self, name: str, description: str = None, schema: Union[dict, str] = None, + default=_DEFAULT_UNDEFINED, optional=None + ): + self.name = name + if description is None: + # Description is required in openEO API, we are a bit more permissive here. + warnings.warn("Parameter without description: using name as description.") + description = name + self.description = description + self.schema = {"type": schema} if isinstance(schema, str) else (schema or {}) + self.default = default + self.optional = optional + +
    +[docs] + def to_dict(self) -> dict: + """Convert to dictionary for JSON-serialization.""" + d = {"name": self.name, "description": self.description, "schema": self.schema} + if self.optional is not None: + d["optional"] = self.optional + if self.default is not self._DEFAULT_UNDEFINED: + d["default"] = self.default + d["optional"] = True + return d
    + + +
    +[docs] + @classmethod + def raster_cube(cls, name: str = "data", description: str = "A data cube.") -> Parameter: + """ + Helper to easily create a 'raster-cube' parameter. + + :param name: name of the parameter. + :param description: description of the parameter + :return: Parameter + """ + return cls(name=name, description=description, schema={"type": "object", "subtype": "raster-cube"})
    + + +
    +[docs] + @classmethod + def datacube(cls, name: str = "data", description: str = "A data cube.") -> Parameter: + """ + Helper to easily create a 'datacube' parameter. + + :param name: name of the parameter. + :param description: description of the parameter + :return: Parameter + + .. versionadded:: 0.22.0 + """ + return cls(name=name, description=description, schema={"type": "object", "subtype": "datacube"})
    + + +
    +[docs] + @classmethod + def string( + cls, + name: str, + description: str = None, + default=_DEFAULT_UNDEFINED, + values: Optional[List[str]] = None, + subtype: Optional[str] = None, + format: Optional[str] = None, + ) -> Parameter: + """Helper to create a 'string' type parameter.""" + schema = {"type": "string"} + if values is not None: + schema["enum"] = values + if subtype: + schema["subtype"] = subtype + if format: + schema["format"] = format + return cls(name=name, description=description, schema=schema, default=default)
    + + +
    +[docs] + @classmethod + def integer(cls, name: str, description: str = None, default=_DEFAULT_UNDEFINED) -> Parameter: + """Helper to create a 'integer' type parameter.""" + return cls(name=name, description=description, schema={"type": "integer"}, default=default)
    + + +
    +[docs] + @classmethod + def number(cls, name: str, description: str = None, default=_DEFAULT_UNDEFINED) -> Parameter: + """Helper to create a 'number' type parameter.""" + return cls(name=name, description=description, schema={"type": "number"}, default=default)
    + + +
    +[docs] + @classmethod + def boolean(cls, name: str, description: str = None, default=_DEFAULT_UNDEFINED) -> Parameter: + """Helper to create a 'boolean' type parameter.""" + return cls(name=name, description=description, schema={"type": "boolean"}, default=default)
    + + +
    +[docs] + @classmethod + def array( + cls, + name: str, + description: str = None, + default=_DEFAULT_UNDEFINED, + *, + item_schema: Optional[Union[str, dict]] = None, + ) -> Parameter: + """ + Helper to create an 'array' type parameter. + + :param item_schema: Schema of the array items given in JSON Schema style, e.g. ``{"type": "string"}``. + Simple schemas can also be specified as single string: + e.g. ``"string"`` will be expanded to ``{"type": "string"}``. + + .. versionchanged:: 0.23.0 + Added ``item_schema`` argument. + """ + schema = {"type": "array"} + if item_schema: + if isinstance(item_schema, str): + item_schema = {"type": item_schema} + schema["items"] = item_schema + return cls(name=name, description=description, schema=schema, default=default)
    + + +
    +[docs] + @classmethod + def object( + cls, name: str, description: Optional[str] = None, default=_DEFAULT_UNDEFINED, *, subtype: Optional[str] = None + ) -> Parameter: + """ + Helper to create an 'object' type parameter + + :param subtype: subtype of the 'object' schema + + .. versionadded:: 0.26.0 + """ + schema = {"type": "object"} + if subtype: + schema["subtype"] = subtype + return cls(name=name, description=description, schema=schema, default=default)
    +
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/extra/job_management.html b/_modules/openeo/extra/job_management.html new file mode 100644 index 000000000..8a119bd99 --- /dev/null +++ b/_modules/openeo/extra/job_management.html @@ -0,0 +1,607 @@ + + + + + + + openeo.extra.job_management — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.extra.job_management

    +import contextlib
    +import datetime
    +import json
    +import logging
    +import time
    +from pathlib import Path
    +from typing import Callable, Dict, NamedTuple, Optional, Union
    +
    +import pandas as pd
    +import requests
    +import shapely.wkt
    +from requests.adapters import HTTPAdapter, Retry
    +
    +from openeo import BatchJob, Connection
    +from openeo.rest import OpenEoApiError
    +from openeo.util import deep_get
    +
    +
    +_log = logging.getLogger(__name__)
    +
    +
    +class _Backend(NamedTuple):
    +    """Container for backend info/settings"""
    +
    +    # callable to create a backend connection
    +    get_connection: Callable[[], Connection]
    +    # Maximum number of jobs to allow in parallel on a backend
    +    parallel_jobs: int
    +
    +
    +MAX_RETRIES = 5
    +
    +
    +[docs] +class MultiBackendJobManager: + """ + Tracker for multiple jobs on multiple backends. + + Usage example: + + .. code-block:: python + + import pandas as pd + import openeo + from openeo.extra.job_management import MultiBackendJobManager + + manager = MultiBackendJobManager() + manager.add_backend("foo", connection=openeo.connect("http://foo.test")) + manager.add_backend("bar", connection=openeo.connect("http://bar.test")) + + jobs_df = pd.DataFrame(...) + output_file = "jobs.csv" + + def start_job( + row: pd.Series, + connection: openeo.Connection, + **kwargs + ) -> openeo.BatchJob: + year = row["year"] + cube = connection.load_collection( + ..., + temporal_extent=[f"{year}-01-01", f"{year+1}-01-01"], + ) + ... + return cube.create_job(...) + + manager.run_jobs(df=jobs_df, start_job=start_job, output_file=output_file) + + See :py:meth:`.run_jobs` for more information on the ``start_job`` callable. + + .. versionadded:: 0.14.0 + """ + + def __init__( + self, poll_sleep: int = 60, root_dir: Optional[Union[str, Path]] = "." + ): + """Create a MultiBackendJobManager. + + :param poll_sleep: + How many seconds to sleep between polls. + + :param root_dir: + Root directory to save files for the jobs, e.g. metadata and error logs. + This defaults to "." the current directory. + + Each job gets its own subfolder in this root directory. + You can use the following methods to find the relevant paths, + based on the job ID: + - get_job_dir + - get_error_log_path + - get_job_metadata_path + """ + self.backends: Dict[str, _Backend] = {} + self.poll_sleep = poll_sleep + self._connections: Dict[str, _Backend] = {} + + # An explicit None or "" should also default to "." + self._root_dir = Path(root_dir or ".") + +
    +[docs] + def add_backend( + self, + name: str, + connection: Union[Connection, Callable[[], Connection]], + parallel_jobs: int = 2, + ): + """ + Register a backend with a name and a Connection getter. + + :param name: + Name of the backend. + :param connection: + Either a Connection to the backend, or a callable to create a backend connection. + :param parallel_jobs: + Maximum number of jobs to allow in parallel on a backend. + """ + + # TODO: Code might become simpler if we turn _Backend into class move this logic there. + # We would need to keep add_backend here as part of the public API though. + # But the amount of unrelated "stuff to manage" would be less (better cohesion) + if isinstance(connection, Connection): + c = connection + connection = lambda: c + assert callable(connection) + self.backends[name] = _Backend( + get_connection=connection, parallel_jobs=parallel_jobs + )
    + + + def _get_connection(self, backend_name: str, resilient: bool = True) -> Connection: + """Get a connection for the backend and optionally make it resilient (adds retry behavior) + + The default is to get a resilient connection, but if necessary you can turn it off with + resilient=False + """ + + # TODO: Code could be simplified if _Backend is a class and this method is moved there. + # TODO: Is it better to make this a public method? + + # Reuse the connection if we can, in order to avoid modifying the same connection several times. + # This is to avoid adding the retry HTTPAdapter multiple times. + # Remember that the get_connection attribute on _Backend can be a Connection object instead + # of a callable, so we don't want to assume it is a fresh connection that doesn't have the + # retry adapter yet. + if backend_name in self._connections: + return self._connections[backend_name] + + connection = self.backends[backend_name].get_connection() + # If we really need it we can skip making it resilient, but by default it should be resilient. + if resilient: + self._make_resilient(connection) + + self._connections[backend_name] = connection + return connection + + def _make_resilient(self, connection): + """Add an HTTPAdapter that retries the request if it fails. + + Retry for the following HTTP 50x statuses: + 502 Bad Gateway + 503 Service Unavailable + 504 Gateway Timeout + """ + status_forcelist = [502, 503, 504] + retries = Retry( + total=MAX_RETRIES, + read=MAX_RETRIES, + other=MAX_RETRIES, + status=MAX_RETRIES, + backoff_factor=0.1, + status_forcelist=status_forcelist, + allowed_methods=["HEAD", "GET", "OPTIONS", "POST"], + ) + connection.session.mount("https://", HTTPAdapter(max_retries=retries)) + connection.session.mount("http://", HTTPAdapter(max_retries=retries)) + + def _normalize_df(self, df: pd.DataFrame) -> pd.DataFrame: + """Ensure we have the required columns and the expected type for the geometry column. + + :param df: The dataframe to normalize. + :return: a new dataframe that is normalized. + """ + + # check for some required columns. + required_with_default = [ + ("status", "not_started"), + ("id", None), + ("start_time", None), + ("cpu", None), + ("memory", None), + ("duration", None), + ("backend_name", None), + ] + new_columns = { + col: val for (col, val) in required_with_default if col not in df.columns + } + df = df.assign(**new_columns) + # Workaround for loading of geopandas "geometry" column. + if "geometry" in df.columns and df["geometry"].dtype.name != "geometry": + df["geometry"] = df["geometry"].apply(shapely.wkt.loads) + return df + + def _persists(self, df, output_file): + df.to_csv(output_file, index=False) + _log.info(f"Wrote job metadata to {output_file.absolute()}") + +
    +[docs] + def run_jobs( + self, + df: pd.DataFrame, + start_job: Callable[[], BatchJob], + output_file: Union[str, Path], + ): + """Runs jobs, specified in a dataframe, and tracks parameters. + + :param df: + DataFrame that specifies the jobs, and tracks the jobs' statuses. + + :param start_job: + A callback which will be invoked with, amongst others, + the row of the dataframe for which a job should be created and/or started. + This callable should return a :py:class:`openeo.rest.job.BatchJob` object. + + The following parameters will be passed to ``start_job``: + + ``row`` (:py:class:`pandas.Series`): + The row in the pandas dataframe that stores the jobs state and other tracked data. + + ``connection_provider``: + A getter to get a connection by backend name. + Typically, you would need either the parameter ``connection_provider``, + or the parameter ``connection``, but likely you will not need both. + + ``connection`` (:py:class:`Connection`): + The :py:class:`Connection` itself, that has already been created. + Typically, you would need either the parameter ``connection_provider``, + or the parameter ``connection``, but likely you will not need both. + + ``provider`` (``str``): + The name of the backend that will run the job. + + You do not have to define all the parameters described below, but if you leave + any of them out, then remember to include the ``*args`` and ``**kwargs`` parameters. + Otherwise you will have an exception because :py:meth:`run_jobs` passes unknown parameters to ``start_job``. + + :param output_file: + Path to output file (CSV) containing the status and metadata of the jobs. + """ + # TODO: Defining start_jobs as a Protocol might make its usage more clear, and avoid complicated doctrings, + # but Protocols are only supported in Python 3.8 and higher. + # TODO: this resume functionality better fits outside of this function + # (e.g. if `output_file` exists: `df` is fully discarded) + output_file = Path(output_file) + if output_file.exists() and output_file.is_file(): + # Resume from existing CSV + _log.info(f"Resuming `run_jobs` from {output_file.absolute()}") + df = pd.read_csv(output_file) + status_histogram = df.groupby("status").size().to_dict() + _log.info(f"Status histogram: {status_histogram}") + + df = self._normalize_df(df) + + while ( + df[ + (df.status != "finished") + & (df.status != "skipped") + & (df.status != "start_failed") + & (df.status != "error") + ].size + > 0 + ): + with ignore_connection_errors(context="get statuses"): + self._update_statuses(df) + status_histogram = df.groupby("status").size().to_dict() + _log.info(f"Status histogram: {status_histogram}") + self._persists(df, output_file) + + if len(df[df.status == "not_started"]) > 0: + # Check number of jobs running at each backend + running = df[ + (df.status == "created") + | (df.status == "queued") + | (df.status == "running") + ] + per_backend = running.groupby("backend_name").size().to_dict() + _log.info(f"Running per backend: {per_backend}") + for backend_name in self.backends: + backend_load = per_backend.get(backend_name, 0) + if backend_load < self.backends[backend_name].parallel_jobs: + to_add = ( + self.backends[backend_name].parallel_jobs - backend_load + ) + to_launch = df[df.status == "not_started"].iloc[0:to_add] + for i in to_launch.index: + self._launch_job(start_job, df, i, backend_name) + self._persists(df, output_file) + + time.sleep(self.poll_sleep)
    + + + def _launch_job(self, start_job, df, i, backend_name): + """Helper method for launching jobs + + :param start_job: + A callback which will be invoked with the row of the dataframe for which a job should be started. + This callable should return a :py:class:`openeo.rest.job.BatchJob` object. + + See also: + `MultiBackendJobManager.run_jobs` for the parameters and return type of this callable + + Even though it is called here in `_launch_job` and that is where the constraints + really come from, the public method `run_jobs` needs to document `start_job` anyway, + so let's avoid duplication in the docstrings. + + :param df: + DataFrame that specifies the jobs, and tracks the jobs' statuses. + + :param i: + index of the job's row in dataframe df + + :param backend_name: + name of the backend that will execute the job. + """ + + df.loc[i, "backend_name"] = backend_name + row = df.loc[i] + try: + _log.info(f"Starting job on backend {backend_name} for {row.to_dict()}") + connection = self._get_connection(backend_name, resilient=True) + + job = start_job( + row=row, + connection_provider=self._get_connection, + connection=connection, + provider=backend_name, + ) + except requests.exceptions.ConnectionError as e: + _log.warning(f"Failed to start job for {row.to_dict()}", exc_info=True) + df.loc[i, "status"] = "start_failed" + else: + df.loc[i, "start_time"] = datetime.datetime.now().isoformat() + if job: + df.loc[i, "id"] = job.job_id + with ignore_connection_errors(context="get status"): + status = job.status() + df.loc[i, "status"] = status + if status == "created": + # start job if not yet done by callback + try: + job.start() + df.loc[i, "status"] = job.status() + except OpenEoApiError as e: + _log.error(e) + df.loc[i, "status"] = "start_failed" + else: + df.loc[i, "status"] = "skipped" + +
    +[docs] + def on_job_done(self, job: BatchJob, row): + """ + Handles jobs that have finished. Can be overridden to provide custom behaviour. + + Default implementation downloads the results into a folder containing the title. + + :param job: The job that has finished. + :param row: DataFrame row containing the job's metadata. + """ + # TODO: param `row` is never accessed in this method. Remove it? Is this intended for future use? + + job_metadata = job.describe() + job_dir = self.get_job_dir(job.job_id) + metadata_path = self.get_job_metadata_path(job.job_id) + + self.ensure_job_dir_exists(job.job_id) + job.get_results().download_files(target=job_dir) + + with open(metadata_path, "w") as f: + json.dump(job_metadata, f, ensure_ascii=False)
    + + +
    +[docs] + def on_job_error(self, job: BatchJob, row): + """ + Handles jobs that stopped with errors. Can be overridden to provide custom behaviour. + + Default implementation writes the error logs to a JSON file. + + :param job: The job that has finished. + :param row: DataFrame row containing the job's metadata. + """ + # TODO: param `row` is never accessed in this method. Remove it? Is this intended for future use? + + error_logs = job.logs(level="error") + error_log_path = self.get_error_log_path(job.job_id) + + if len(error_logs) > 0: + self.ensure_job_dir_exists(job.job_id) + error_log_path.write_text(json.dumps(error_logs, indent=2))
    + + +
    +[docs] + def get_job_dir(self, job_id: str) -> Path: + """Path to directory where job metadata, results and error logs are be saved.""" + return self._root_dir / f"job_{job_id}"
    + + +
    +[docs] + def get_error_log_path(self, job_id: str) -> Path: + """Path where error log file for the job is saved.""" + return self.get_job_dir(job_id) / f"job_{job_id}_errors.json"
    + + +
    +[docs] + def get_job_metadata_path(self, job_id: str) -> Path: + """Path where job metadata file is saved.""" + return self.get_job_dir(job_id) / f"job_{job_id}.json"
    + + +
    +[docs] + def ensure_job_dir_exists(self, job_id: str) -> Path: + """Create the job folder if it does not exist yet.""" + job_dir = self.get_job_dir(job_id) + if not job_dir.exists(): + job_dir.mkdir(parents=True)
    + + + def _update_statuses(self, df: pd.DataFrame): + """Update status (and stats) of running jobs (in place).""" + active = df.loc[ + (df.status == "created") + | (df.status == "queued") + | (df.status == "running") + ] + for i in active.index: + job_id = df.loc[i, "id"] + backend_name = df.loc[i, "backend_name"] + + try: + con = self._get_connection(backend_name) + the_job = con.job(job_id) + job_metadata = the_job.describe() + _log.info( + f"Status of job {job_id!r} (on backend {backend_name}) is {job_metadata['status']!r}" + ) + if job_metadata["status"] == "finished": + self.on_job_done(the_job, df.loc[i]) + if df.loc[i, "status"] != "error" and job_metadata["status"] == "error": + self.on_job_error(the_job, df.loc[i]) + + df.loc[i, "status"] = job_metadata["status"] + for key in job_metadata.get("usage", {}).keys(): + df.loc[i, key] = _format_usage_stat(job_metadata, key) + + except OpenEoApiError as e: + print(f"error for job {job_id!r} on backend {backend_name}") + print(e)
    + + + +def _format_usage_stat(job_metadata: dict, field: str) -> str: + value = deep_get(job_metadata, "usage", field, "value", default=0) + unit = deep_get(job_metadata, "usage", field, "unit", default="") + return f"{value} {unit}".strip() + + +
    +[docs] +@contextlib.contextmanager +def ignore_connection_errors(context: Optional[str] = None): + """Context manager to ignore connection errors.""" + try: + yield + except requests.exceptions.ConnectionError as e: + _log.warning(f"Ignoring connection error (context {context or 'n/a'}): {e}") + # Back off a bit + time.sleep(5)
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/extra/spectral_indices/spectral_indices.html b/_modules/openeo/extra/spectral_indices/spectral_indices.html new file mode 100644 index 000000000..57df1de56 --- /dev/null +++ b/_modules/openeo/extra/spectral_indices/spectral_indices.html @@ -0,0 +1,618 @@ + + + + + + + openeo.extra.spectral_indices.spectral_indices — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.extra.spectral_indices.spectral_indices

    +import functools
    +import json
    +import re
    +from typing import Dict, List, Optional, Set
    +
    +from openeo import BaseOpenEoException
    +from openeo.processes import ProcessBuilder, array_create, array_modify
    +from openeo.rest.datacube import DataCube
    +
    +try:
    +    import importlib_resources
    +except ImportError:
    +    import importlib.resources as importlib_resources
    +
    +
    +@functools.lru_cache(maxsize=1)
    +def load_indices() -> Dict[str, dict]:
    +    """Load set of supported spectral indices."""
    +    # TODO: encapsulate all this json loading in a single Awesome Spectral Indices registry class?
    +    specs = {}
    +
    +    for path in [
    +        "resources/awesome-spectral-indices/spectral-indices-dict.json",
    +        # TODO #506 Deprecate extra-indices-dict.json as a whole
    +        #      and provide an alternative mechanism to work with custom indices
    +        "resources/extra-indices-dict.json",
    +    ]:
    +        with importlib_resources.files("openeo.extra.spectral_indices") / path as resource_path:
    +            data = json.loads(resource_path.read_text(encoding="utf8"))
    +            overwrites = set(specs.keys()).intersection(data["SpectralIndices"].keys())
    +            if overwrites:
    +                raise RuntimeError(f"Duplicate spectral indices: {overwrites} from {path}")
    +            specs.update(data["SpectralIndices"])
    +
    +    return specs
    +
    +
    +@functools.lru_cache(maxsize=1)
    +def load_constants() -> Dict[str, float]:
    +    """Load constants defined by Awesome Spectral Indices."""
    +    # TODO: encapsulate all this json loading in a single Awesome Spectral Indices registry class?
    +    with importlib_resources.files(
    +        "openeo.extra.spectral_indices"
    +    ) / "resources/awesome-spectral-indices/constants.json" as resource_path:
    +        data = json.loads(resource_path.read_text(encoding="utf8"))
    +
    +    return {k: v["default"] for k, v in data.items() if isinstance(v["default"], (int, float))}
    +
    +
    +@functools.lru_cache(maxsize=1)
    +def _load_bands() -> Dict[str, dict]:
    +    """Load band name mapping defined by Awesome Spectral Indices."""
    +    # TODO: encapsulate all this json loading in a single Awesome Spectral Indices registry class?
    +    with importlib_resources.files(
    +        "openeo.extra.spectral_indices"
    +    ) / "resources/awesome-spectral-indices/bands.json" as resource_path:
    +        data = json.loads(resource_path.read_text(encoding="utf8"))
    +    return data
    +
    +
    +class BandMappingException(BaseOpenEoException):
    +    """Failure to determine band-variable mapping."""
    +
    +
    +class _BandMapping:
    +    """
    +    Helper class to extract mappings between band names and variable names used in Awesome Spectral Indices formulas.
    +    """
    +
    +    _EXTRA = {
    +        "sentinel1": {"HH": "HH", "HV": "HV", "VH": "VH", "VV": "VV"},
    +    }
    +
    +    def __init__(self):
    +        # Load bands.json from Awesome Spectral Indices
    +        self._band_data = _load_bands()
    +
    +    @staticmethod
    +    def _normalize_platform(platform: str) -> str:
    +        platform = platform.lower().replace("-", "").replace(" ", "")
    +        if platform in {"sentinel2a", "sentinel2b"}:
    +            platform = "sentinel2"
    +        return platform
    +
    +    @staticmethod
    +    def _normalize_band_name(band_name: str) -> str:
    +        band_name = band_name.upper()
    +        # Normalize band names like "B01" to "B1"
    +        band_name = re.sub(r"^B0+(\d+)$", r"B\1", band_name)
    +        return band_name
    +
    +    @functools.lru_cache(maxsize=1)
    +    def get_platforms(self) -> Set[str]:
    +        """Get list of supported (normalized) satellite platforms."""
    +        platforms = {p for var_data in self._band_data.values() for p in var_data.get("platforms", {}).keys()}
    +        platforms.update(self._EXTRA.keys())
    +        platforms.update({self._normalize_platform(p) for p in platforms})
    +        return platforms
    +
    +    def guess_platform(self, name: str) -> str:
    +        """Guess platform from given collection id or name."""
    +        # First check original id, then retry with removed separators as last resort.
    +        for haystack in [name.lower(), re.sub("[_ -]", "", name.lower())]:
    +            for platform in sorted(self.get_platforms(), key=len, reverse=True):
    +                if platform in haystack:
    +                    return platform
    +        raise BandMappingException(f"Unable to guess satellite platform from id {name!r}.")
    +
    +    def variable_to_band_name_map(self, platform: str) -> Dict[str, str]:
    +        """
    +        Build mapping from Awesome Spectral Indices variable names to (normalized) band names for given satellite platform.
    +        """
    +        platform_normalized = self._normalize_platform(platform)
    +        if platform_normalized in self._EXTRA:
    +            return self._EXTRA[platform_normalized]
    +
    +        var_to_band = {
    +            var: pf_data["band"]
    +            for var, var_data in self._band_data.items()
    +            for pf, pf_data in var_data.get("platforms", {}).items()
    +            if self._normalize_platform(pf) == platform_normalized
    +        }
    +        if not var_to_band:
    +            raise BandMappingException(f"Empty band mapping derived for satellite platform {platform!r}")
    +        return var_to_band
    +
    +    def actual_band_name_to_variable_map(self, platform: str, band_names: List[str]) -> Dict[str, str]:
    +        """Build mapping from actual band names (as given) to Awesome Spectral Indices variable names."""
    +        var_to_band = self.variable_to_band_name_map(platform=platform)
    +        band_to_var = {
    +            band_name: var
    +            for var, normalized_band_name in var_to_band.items()
    +            for band_name in band_names
    +            if self._normalize_band_name(band_name) == normalized_band_name
    +        }
    +        return band_to_var
    +
    +
    +
    +[docs] +def list_indices() -> List[str]: + """List names of supported spectral indices""" + specs = load_indices() + return list(specs.keys())
    + + + +def _check_params(item, params): + range_vals = ["input_range", "output_range"] + if set(params) != set(range_vals): + raise ValueError( + f"You have set the parameters {params} on {item}, while the following are required {range_vals}" + ) + for rng in range_vals: + if params[rng] is None: + continue + if len(params[rng]) != 2: + raise ValueError( + f"The list of provided values {params[rng]} for parameter {rng} for {item} is not of length 2" + ) + # TODO: allow float too? + if not all(isinstance(val, int) for val in params[rng]): + raise ValueError("The ranges you supplied are not all of type int") + if (params["input_range"] is None) != (params["output_range"] is None): + raise ValueError(f"The index_range and output_range of {item} should either be both supplied, or both None") + + +def _check_validity_index_dict(index_dict: dict, index_specs: dict): + # TODO: this `index_dict` API needs some more rethinking: + # - the dictionary has no explicit order of indices, which can be important for end user + # - allow "collection" to be missing (e.g. if no rescaling is desired, or input data is not kept)? + # - option to define default output range, instead of having it to specify it for each index? + # - keep "rescaling" feature separate/orthogonal from "spectral indices" feature. It could be useful as + # a more generic machine learning data preparation feature + input_vals = ["collection", "indices"] + if set(index_dict.keys()) != set(input_vals): + raise ValueError( + f"The first level of the dictionary should contain the keys 'collection' and 'indices', but they contain {index_dict.keys()}" + ) + _check_params("collection", index_dict["collection"]) + for index, params in index_dict["indices"].items(): + if index not in index_specs.keys(): + raise NotImplementedError("Index " + index + " is not supported.") + _check_params(index, params) + + +def _callback( + x: ProcessBuilder, + index_dict: dict, + index_specs: dict, + append: bool, + band_names: List[str], + band_to_var: Dict[str, str], +) -> ProcessBuilder: + index_values = [] + x_res = x + + # TODO: use `label` parameter of `array_element` to avoid index based band references + variables = {band_to_var[bn]: x.array_element(i) for i, bn in enumerate(band_names) if bn in band_to_var} + eval_globals = { + **load_constants(), + **variables, + } + # TODO: user might want to control order of indices, which is tricky through a dictionary. + for index, params in index_dict["indices"].items(): + index_result = eval(index_specs[index]["formula"], eval_globals) + if params["input_range"] is not None: + index_result = index_result.linear_scale_range(*params["input_range"], *params["output_range"]) + index_values.append(index_result) + if index_dict["collection"]["input_range"] is not None: + x_res = x_res.linear_scale_range( + *index_dict["collection"]["input_range"], *index_dict["collection"]["output_range"] + ) + if append: + return array_modify(data=x_res, values=index_values, index=len(band_names)) + else: + return array_create(data=index_values) + + +
    +[docs] +def compute_and_rescale_indices( + datacube: DataCube, + index_dict: dict, + *, + append: bool = False, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Computes a list of indices from a data cube + + :param datacube: input data cube + :param index_dict: a dictionary that contains the input- and output range of the collection on which you calculate the indices + as well as the indices that you want to calculate with their responding input- and output ranges + It follows the following format:: + + { + "collection": { + "input_range": [0,8000], + "output_range": [0,250] + }, + "indices": { + "NDVI": { + "input_range": [-1,1], + "output_range": [0,250] + }, + } + } + + If you don't want to rescale your data, you can fill the input-, index- and output-range with ``None``. + + See `list_indices()` for supported indices. + + :param append: append the indices as bands to the given data cube + instead of creating a new cube with only the calculated indices + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: the datacube with the indices attached as bands + + .. warning:: this "rescaled" index helper uses an experimental API (e.g. `index_dict` argument) that is subject to change. + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + + """ + index_specs = load_indices() + + _check_validity_index_dict(index_dict, index_specs) + + if variable_map is None: + # Automatic band mapping + band_mapping = _BandMapping() + if platform is None: + if datacube.metadata and datacube.metadata.get("id"): + platform = band_mapping.guess_platform(name=datacube.metadata.get("id")) + else: + raise BandMappingException("Unable to determine satellite platform from data cube metadata") + band_to_var = band_mapping.actual_band_name_to_variable_map( + platform=platform, band_names=datacube.metadata.band_names + ) + else: + band_to_var = {b: v for v, b in variable_map.items()} + + res = datacube.apply_dimension( + dimension="bands", + process=lambda x: _callback( + x, + index_dict=index_dict, + index_specs=index_specs, + append=append, + band_names=datacube.metadata.band_names, + band_to_var=band_to_var, + ), + ) + if append: + return res.rename_labels("bands", target=datacube.metadata.band_names + list(index_dict["indices"].keys())) + else: + return res.rename_labels("bands", target=list(index_dict["indices"].keys()))
    + + + +
    +[docs] +def append_and_rescale_indices( + datacube: DataCube, + index_dict: dict, + *, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Computes a list of indices from a datacube and appends them to the existing datacube + + :param datacube: input data cube + :param index_dict: a dictionary that contains the input- and output range of the collection on which you calculate the indices + as well as the indices that you want to calculate with their responding input- and output ranges + It follows the following format:: + + { + "collection": { + "input_range": [0,8000], + "output_range": [0,250] + }, + "indices": { + "NDVI": { + "input_range": [-1,1], + "output_range": [0,250] + }, + } + } + + See `list_indices()` for supported indices. + + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube with appended indices + + .. warning:: this "rescaled" index helper uses an experimental API (e.g. `index_dict` argument) that is subject to change. + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + return compute_and_rescale_indices( + datacube=datacube, index_dict=index_dict, append=True, variable_map=variable_map, platform=platform + )
    + + + +
    +[docs] +def compute_indices( + datacube: DataCube, + indices: List[str], + *, + append: bool = False, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Compute multiple spectral indices from the given data cube. + + :param datacube: input data cube + :param indices: list of names of the indices to compute and append. See `list_indices()` for supported indices. + :param append: append the indices as bands to the given data cube + instead of creating a new cube with only the calculated indices + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube containing the indices as bands + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + # TODO: it's bit weird to have to specify all these None's in this structure + index_dict = { + "collection": { + "input_range": None, + "output_range": None, + }, + "indices": {index: {"input_range": None, "output_range": None} for index in indices}, + } + return compute_and_rescale_indices( + datacube=datacube, index_dict=index_dict, append=append, variable_map=variable_map, platform=platform + )
    + + + +
    +[docs] +def append_indices( + datacube: DataCube, + indices: List[str], + *, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Compute multiple spectral indices and append them to the given data cube. + + :param datacube: input data cube + :param indices: list of names of the indices to compute and append. See `list_indices()` for supported indices. + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube with appended indices + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + + return compute_indices( + datacube=datacube, indices=indices, append=True, variable_map=variable_map, platform=platform + )
    + + + +
    +[docs] +def compute_index( + datacube: DataCube, index: str, *, variable_map: Optional[Dict[str, str]] = None, platform: Optional[str] = None +) -> DataCube: + """ + Compute a single spectral index from a data cube. + + :param datacube: input data cube + :param index: name of the index to compute. See `list_indices()` for supported indices. + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube containing the index as band + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + # TODO: option to compute the index with `reduce_dimension` instead of `apply_dimension`? + return compute_indices( + datacube=datacube, indices=[index], append=False, variable_map=variable_map, platform=platform + )
    + + + +
    +[docs] +def append_index( + datacube: DataCube, index: str, *, variable_map: Optional[Dict[str, str]] = None, platform: Optional[str] = None +) -> DataCube: + """ + Compute a single spectral index and append it to the given data cube. + + :param cube: input data cube + :param index: name of the index to compute and append. See `list_indices()` for supported indices. + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube with appended index + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + return compute_indices( + datacube=datacube, indices=[index], append=True, variable_map=variable_map, platform=platform + )
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/internal/graph_building.html b/_modules/openeo/internal/graph_building.html new file mode 100644 index 000000000..ed8f7c8f7 --- /dev/null +++ b/_modules/openeo/internal/graph_building.html @@ -0,0 +1,571 @@ + + + + + + + openeo.internal.graph_building — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.internal.graph_building

    +"""
    +Internal openEO process graph building utilities
    +''''''''''''''''''''''''''''''''''''''''''''''''''
    +
    +Internal functionality for abstracting, building, manipulating and processing openEO process graphs.
    +
    +"""
    +
    +from __future__ import annotations
    +
    +import abc
    +import collections
    +import json
    +import sys
    +from pathlib import Path
    +from typing import Any, Dict, Optional, Tuple, Union
    +
    +from openeo.api.process import Parameter
    +from openeo.internal.compat import nullcontext
    +from openeo.internal.process_graph_visitor import (
    +    ProcessGraphUnflattener,
    +    ProcessGraphVisitException,
    +    ProcessGraphVisitor,
    +)
    +from openeo.util import dict_no_none, load_json_resource
    +
    +
    +
    +[docs] +class FlatGraphableMixin(metaclass=abc.ABCMeta): + """ + Mixin for classes that can be exported/converted to + a "flat graph" representation of an openEO process graph. + """ + + @abc.abstractmethod + def flat_graph(self) -> Dict[str, dict]: + ... + +
    +[docs] + def to_json(self, *, indent: Union[int, None] = 2, separators: Optional[Tuple[str, str]] = None) -> str: + """ + Get interoperable JSON representation of the process graph. + + See :py:meth:`DataCube.print_json` to directly print the JSON representation + and :ref:`process_graph_export` for more usage information. + + Also see ``json.dumps`` docs for more information on the JSON formatting options. + + :param indent: JSON indentation level. + :param separators: (optional) tuple of item/key separators. + :return: JSON string + """ + pg = {"process_graph": self.flat_graph()} + return json.dumps(pg, indent=indent, separators=separators)
    + + +
    +[docs] + def print_json( + self, + *, + file=None, + indent: Union[int, None] = 2, + separators: Optional[Tuple[str, str]] = None, + end: str = "\n", + ): + """ + Print interoperable JSON representation of the process graph. + + See :py:meth:`DataCube.to_json` to get the JSON representation as a string + and :ref:`process_graph_export` for more usage information. + + Also see ``json.dumps`` docs for more information on the JSON formatting options. + + :param file: file-like object (stream) to print to (current ``sys.stdout`` by default). + Or a path (string or pathlib.Path) to a file to write to. + :param indent: JSON indentation level. + :param separators: (optional) tuple of item/key separators. + :param end: additional string to be printed at the end (newline by default). + + .. versionadded:: 0.12.0 + + .. versionadded:: 0.23.0 + added the ``end`` argument. + """ + pg = {"process_graph": self.flat_graph()} + if isinstance(file, (str, Path)): + # Create (new) file and automatically close it + file_ctx = Path(file).open("w", encoding="utf8") + else: + # Just use file as-is, but don't close it automatically. + file_ctx = nullcontext(enter_result=file or sys.stdout) + with file_ctx as f: + json.dump(pg, f, indent=indent, separators=separators) + if end: + f.write(end)
    +
    + + + +class _FromNodeMixin(abc.ABC): + """Mixin for classes that want to hook into the generation of a "from_node" reference.""" + + @abc.abstractmethod + def from_node(self) -> PGNode: + # TODO: "from_node" is a bit a confusing name: + # it refers to the "from_node" node reference in openEO process graphs, + # but as a method name here it reads like "construct from PGNode", + # while it is actually meant as "export as PGNode" (that can be used in a "from_node" reference). + pass + + +
    +[docs] +class PGNode(_FromNodeMixin, FlatGraphableMixin): + """ + A process node in a process graph: has at least a process_id and arguments. + + Note that a full openEO "process graph" is essentially a directed acyclic graph of nodes + pointing to each other. A full process graph is practically equivalent with its "result" node, + as it points (directly or indirectly) to all the other nodes it depends on. + + .. warning:: + This class is an implementation detail meant for internal use. + It is not recommended for general use in normal user code. + Instead, use process graph abstraction builders like + :py:meth:`Connection.load_collection() <openeo.rest.connection.Connection.load_collection>`, + :py:meth:`Connection.datacube_from_process() <openeo.rest.connection.Connection.datacube_from_process>`, + :py:meth:`Connection.datacube_from_flat_graph() <openeo.rest.connection.Connection.datacube_from_flat_graph>`, + :py:meth:`Connection.datacube_from_json() <openeo.rest.connection.Connection.datacube_from_json>`, + :py:meth:`Connection.load_ml_model() <openeo.rest.connection.Connection.load_ml_model>`, + :py:func:`openeo.processes.process()`, + + """ + + __slots__ = ["_process_id", "_arguments", "_namespace"] + + def __init__(self, process_id: str, arguments: dict = None, namespace: Union[str, None] = None, **kwargs): + self._process_id = process_id + # Merge arguments dict and kwargs + arguments = dict(**(arguments or {}), **kwargs) + # Make sure direct PGNode arguments are properly wrapped in a "from_node" dict + for arg, value in arguments.items(): + if isinstance(value, _FromNodeMixin): + arguments[arg] = {"from_node": value.from_node()} + elif isinstance(value, list): + for index, arrayelement in enumerate(value): + if isinstance(arrayelement, _FromNodeMixin): + value[index] = {"from_node": arrayelement.from_node()} + # TODO: use a frozendict of some sort to ensure immutability? + self._arguments = arguments + self._namespace = namespace + + def from_node(self): + return self + + def __repr__(self): + return "<{c} {p!r} at 0x{m:x}>".format(c=self.__class__.__name__, p=self.process_id, m=id(self)) + + @property + def process_id(self) -> str: + return self._process_id + + @property + def arguments(self) -> dict: + return self._arguments + + @property + def namespace(self) -> Union[str, None]: + return self._namespace + +
    +[docs] + def update_arguments(self, **kwargs): + """ + Add/Update arguments of the process node. + + .. versionadded:: 0.10.1 + """ + self._arguments = {**self._arguments, **kwargs}
    + + + def _as_tuple(self): + return (self._process_id, self._arguments, self._namespace) + + def __eq__(self, other): + return isinstance(other, type(self)) and self._as_tuple() == other._as_tuple() + +
    +[docs] + def to_dict(self) -> dict: + """ + Convert process graph to a nested dictionary structure. + Uses deep copy style: nodes that are reused in graph will be deduplicated + """ + + def _deep_copy(x): + """PGNode aware deep copy helper""" + if isinstance(x, PGNode): + return dict_no_none(process_id=x.process_id, arguments=_deep_copy(x.arguments), namespace=x.namespace) + if isinstance(x, Parameter): + return {"from_parameter": x.name} + elif isinstance(x, dict): + return {str(k): _deep_copy(v) for k, v in x.items()} + elif isinstance(x, (list, tuple)): + return type(x)(_deep_copy(v) for v in x) + elif isinstance(x, (str, int, float)) or x is None: + return x + else: + raise ValueError(repr(x)) + + return _deep_copy(self)
    + + +
    +[docs] + def flat_graph(self) -> Dict[str, dict]: + """Get the process graph in internal flat dict representation.""" + return GraphFlattener().flatten(node=self)
    + + +
    +[docs] + @staticmethod + def to_process_graph_argument(value: Union['PGNode', str, dict]) -> dict: + """ + Normalize given argument properly to a "process_graph" argument + to be used as reducer/subprocess for processes like + ``reduce_dimension``, ``aggregate_spatial``, ``apply``, ``merge_cubes``, ``resample_cube_temporal`` + """ + if isinstance(value, str): + # assume string with predefined reduce/apply process ("mean", "sum", ...) + # TODO: is this case still used? It's invalid anyway for 1.0 openEO spec I think? + return value + elif isinstance(value, PGNode): + return {"process_graph": value} + elif isinstance(value, dict) and isinstance(value.get("process_graph"), PGNode): + return value + else: + raise ValueError(value)
    + + +
    +[docs] + @staticmethod + def from_flat_graph(flat_graph: dict, parameters: Optional[dict] = None) -> PGNode: + """Unflatten a given flat dict representation of a process graph and return result node.""" + return PGNodeGraphUnflattener.unflatten(flat_graph=flat_graph, parameters=parameters)
    +
    + + + +def as_flat_graph(x: Union[dict, FlatGraphableMixin, Path, Any]) -> Dict[str, dict]: + """ + Convert given object to a internal flat dict graph representation. + """ + # TODO: document or verify which process graph flavor this is: + # including `{"process": {"process_graph": {nodes}}` ("process graph with metadata") + # including `{"process_graph": {nodes}}` ("process graph") + # or just the raw process graph nodes? + if isinstance(x, dict): + return x + elif isinstance(x, FlatGraphableMixin): + return x.flat_graph() + elif isinstance(x, (str, Path)): + # Assume a JSON resource (raw JSON, path to local file, JSON url, ...) + return load_json_resource(x) + raise ValueError(x) + + +class ReduceNode(PGNode): + """ + A process graph node for "reduce" processes (has a reducer sub-process-graph) + """ + + def __init__( + self, + data: _FromNodeMixin, + reducer: Union[PGNode, str, dict], + dimension: str, + context=None, + process_id="reduce_dimension", + band_math_mode: bool = False, + ): + assert process_id in ("reduce_dimension", "reduce_dimension_binary") + arguments = { + "data": data, + "reducer": self.to_process_graph_argument(reducer), + "dimension": dimension, + } + if context is not None: + arguments["context"] = context + super().__init__(process_id=process_id, arguments=arguments) + # TODO #123 is it (still) necessary to make "band" math a special case? + self.band_math_mode = band_math_mode + + @property + def dimension(self): + return self.arguments["dimension"] + + def reducer_process_graph(self) -> PGNode: + return self.arguments["reducer"]["process_graph"] + + def clone_with_new_reducer(self, reducer: PGNode) -> ReduceNode: + """Copy/clone this reduce node: keep input reference, but use new reducer""" + return ReduceNode( + data=self.arguments["data"]["from_node"], + reducer=reducer, + dimension=self.arguments["dimension"], + band_math_mode=self.band_math_mode, + context=self.arguments.get("context"), + ) + + +class FlatGraphNodeIdGenerator: + """ + Helper class to generate unique node ids (e.g. autoincrement style) + for processes in a flat process graph. + """ + + def __init__(self): + self._counters = collections.defaultdict(int) + + def generate(self, process_id: str): + """Generate new key for given process id.""" + self._counters[process_id] += 1 + return "{p}{c}".format(p=process_id.replace('_', ''), c=self._counters[process_id]) + + +class GraphFlattener(ProcessGraphVisitor): + + def __init__(self, node_id_generator: FlatGraphNodeIdGenerator = None): + super().__init__() + self._node_id_generator = node_id_generator or FlatGraphNodeIdGenerator() + self._last_node_id = None + self._flattened: Dict[str, dict] = {} + self._argument_stack = [] + self._node_cache = {} + + def flatten(self, node: PGNode) -> Dict[str, dict]: + """Consume given nested process graph and return flat dict representation""" + self.accept_node(node) + assert len(self._argument_stack) == 0 + self._flattened[self._last_node_id]["result"] = True + return self._flattened + + def accept_node(self, node: PGNode): + # Process reused nodes only first time and remember node id. + node_id = id(node) + if node_id not in self._node_cache: + super()._accept_process(process_id=node.process_id, arguments=node.arguments, namespace=node.namespace) + self._node_cache[node_id] = self._last_node_id + else: + self._last_node_id = self._node_cache[node_id] + + def enterProcess(self, process_id: str, arguments: dict, namespace: Union[str, None]): + self._argument_stack.append({}) + + def leaveProcess(self, process_id: str, arguments: dict, namespace: Union[str, None]): + node_id = self._node_id_generator.generate(process_id) + self._flattened[node_id] = dict_no_none( + process_id=process_id, + arguments=self._argument_stack.pop(), + namespace=namespace, + ) + self._last_node_id = node_id + + def _store_argument(self, argument_id: str, value): + if isinstance(value, Parameter): + value = {"from_parameter": value.name} + self._argument_stack[-1][argument_id] = value + + def _store_array_element(self, value): + if isinstance(value, Parameter): + value = {"from_parameter": value.name} + self._argument_stack[-1].append(value) + + def enterArray(self, argument_id: str): + array = [] + self._store_argument(argument_id, array) + self._argument_stack.append(array) + + def leaveArray(self, argument_id: str): + self._argument_stack.pop() + + def arrayElementDone(self, value): + self._store_array_element(self._flatten_argument(value)) + + def constantArrayElement(self, value): + self._store_array_element(self._flatten_argument(value)) + + def _flatten_argument(self, value): + if isinstance(value, dict): + if "from_node" in value: + value = {"from_node": self._last_node_id} + elif "process_graph" in value: + pg = value["process_graph"] + if isinstance(pg, PGNode): + value = {"process_graph": GraphFlattener(node_id_generator=self._node_id_generator).flatten(pg)} + elif isinstance(pg, dict): + # Assume it is already a valid flat graph representation of a subprocess + value = {"process_graph": pg} + else: + raise ValueError(pg) + else: + value = {k: self._flatten_argument(v) for k, v in value.items()} + elif isinstance(value, Parameter): + value = {"from_parameter": value.name} + return value + + def leaveArgument(self, argument_id: str, value): + self._store_argument(argument_id, self._flatten_argument(value)) + + def constantArgument(self, argument_id: str, value): + self._store_argument(argument_id, value) + + +class PGNodeGraphUnflattener(ProcessGraphUnflattener): + """ + Unflatten a flat process graph to a graph of :py:class:`PGNode` objects + + Parameter substitution can also be performed, but is optional: + if the ``parameters=None`` is given, no parameter substitution is done, + if it is a dictionary (even an empty one) is given, every parameter encountered in the process + graph must have an entry for substitution. + """ + + def __init__(self, flat_graph: dict, parameters: Optional[dict] = None): + super().__init__(flat_graph=flat_graph) + self._parameters = parameters + + def _process_node(self, node: dict) -> PGNode: + return PGNode( + process_id=node["process_id"], + arguments=self._process_value(value=node["arguments"]), + namespace=node.get("namespace") + ) + + def _process_from_node(self, key: str, node: dict) -> PGNode: + return self.get_node(key=key) + + def _process_from_parameter(self, name: str) -> Any: + if self._parameters is None: + return super()._process_from_parameter(name=name) + if name not in self._parameters: + raise ProcessGraphVisitException("No substitution value for parameter {p!r}.".format(p=name)) + return self._parameters[name] +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/metadata.html b/_modules/openeo/metadata.html new file mode 100644 index 000000000..55e41a176 --- /dev/null +++ b/_modules/openeo/metadata.html @@ -0,0 +1,670 @@ + + + + + + + openeo.metadata — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.metadata

    +from __future__ import annotations
    +
    +import logging
    +import warnings
    +from typing import Any, Callable, List, NamedTuple, Optional, Tuple, Union
    +
    +from openeo.internal.jupyter import render_component
    +from openeo.util import deep_get
    +
    +_log = logging.getLogger(__name__)
    +
    +
    +class MetadataException(Exception):
    +    pass
    +
    +
    +class DimensionAlreadyExistsException(MetadataException):
    +    pass
    +
    +
    +class Dimension:
    +    """Base class for dimensions."""
    +
    +    def __init__(self, type: str, name: str):
    +        self.type = type
    +        self.name = name
    +
    +    def __repr__(self):
    +        return "{c}({f})".format(
    +            c=self.__class__.__name__,
    +            f=", ".join("{k!s}={v!r}".format(k=k, v=v) for (k, v) in self.__dict__.items())
    +        )
    +
    +    def __eq__(self, other):
    +        return self.__class__ == other.__class__ and self.__dict__ == other.__dict__
    +
    +    def rename(self, name) -> Dimension:
    +        """Create new dimension with new name."""
    +        return Dimension(type=self.type, name=name)
    +
    +    def rename_labels(self, target, source) -> Dimension:
    +        """
    +        Rename labels, if the type of dimension allows it.
    +
    +        :param target: List of target labels
    +        :param source: Source labels, or empty list
    +        :return: A new dimension with modified labels, or the same if no change is applied.
    +        """
    +        # In general, we don't have/manage label info here, so do nothing.
    +        return Dimension(type=self.type, name=self.name)
    +
    +
    +
    +[docs] +class SpatialDimension(Dimension): + DEFAULT_CRS = 4326 + + def __init__( + self, + name: str, + extent: Union[Tuple[float, float], List[float]], + crs: Union[str, int, dict] = DEFAULT_CRS, + step=None, + ): + """ + + @param name: + @param extent: + @param crs: + @param step: The space between the values. Use null for irregularly spaced steps. + """ + super().__init__(type="spatial", name=name) + self.extent = extent + self.crs = crs + self.step = step + +
    +[docs] + def rename(self, name) -> Dimension: + return SpatialDimension(name=name, extent=self.extent, crs=self.crs, step=self.step)
    +
    + + + +
    +[docs] +class TemporalDimension(Dimension): + def __init__(self, name: str, extent: Union[Tuple[str, str], List[str]]): + super().__init__(type="temporal", name=name) + self.extent = extent + +
    +[docs] + def rename(self, name) -> Dimension: + return TemporalDimension(name=name, extent=self.extent)
    +
    + + + +class Band(NamedTuple): + """ + Simple container class for band metadata. + Based on https://github.com/stac-extensions/eo#band-object + """ + + name: str + common_name: Optional[str] = None + # wavelength in micrometer + wavelength_um: Optional[float] = None + aliases: Optional[List[str]] = None + # "openeo:gsd" field (https://github.com/Open-EO/openeo-stac-extensions#GSD-Object) + gsd: Optional[dict] = None + + +
    +[docs] +class BandDimension(Dimension): + def __init__(self, name: str, bands: List[Band]): + super().__init__(type="bands", name=name) + self.bands = bands + + @property + def band_names(self) -> List[str]: + return [b.name for b in self.bands] + + @property + def band_aliases(self) -> List[List[str]]: + return [b.aliases for b in self.bands] + + @property + def common_names(self) -> List[str]: + return [b.common_name for b in self.bands] + +
    +[docs] + def band_index(self, band: Union[int, str]) -> int: + """ + Resolve a given band (common) name/index to band index + + :param band: band name, common name or index + :return int: band index + """ + band_names = self.band_names + if isinstance(band, int) and 0 <= band < len(band_names): + return band + elif isinstance(band, str): + common_names = self.common_names + # First try common names if possible + if band in common_names: + return common_names.index(band) + if band in band_names: + return band_names.index(band) + # Check band aliases to still support old band names + aliases = [True if aliases and band in aliases else False for aliases in self.band_aliases] + if any(aliases): + return aliases.index(True) + raise ValueError("Invalid band name/index {b!r}. Valid names: {n!r}".format(b=band, n=band_names))
    + + +
    +[docs] + def band_name(self, band: Union[str, int], allow_common=True) -> str: + """Resolve (common) name or index to a valid (common) name""" + if isinstance(band, str): + if band in self.band_names: + return band + elif band in self.common_names: + if allow_common: + return band + else: + return self.band_names[self.common_names.index(band)] + elif any([True if aliases and band in aliases else False for aliases in self.band_aliases]): + return self.band_names[self.band_index(band)] + elif isinstance(band, int) and 0 <= band < len(self.bands): + return self.band_names[band] + raise ValueError("Invalid band name/index {b!r}. Valid names: {n!r}".format(b=band, n=self.band_names))
    + + +
    +[docs] + def filter_bands(self, bands: List[Union[int, str]]) -> BandDimension: + """ + Construct new BandDimension with subset of bands, + based on given band indices or (common) names + """ + return BandDimension( + name=self.name, + bands=[self.bands[self.band_index(b)] for b in bands] + )
    + + +
    +[docs] + def append_band(self, band: Band) -> BandDimension: + """Create new BandDimension with appended band.""" + if band.name in self.band_names: + raise ValueError("Duplicate band {b!r}".format(b=band)) + + return BandDimension( + name=self.name, + bands=self.bands + [band] + )
    + + +
    +[docs] + def rename_labels(self, target, source) -> Dimension: + if source: + if len(target) != len(source): + raise ValueError( + "In rename_labels, `target` and `source` should have same number of labels, " + "but got: `target` {t} and `source` {s}".format(t=target, s=source) + ) + new_bands = self.bands.copy() + for old_name, new_name in zip(source, target): + band_index = self.band_index(old_name) + the_band = new_bands[band_index] + new_bands[band_index] = Band( + name=new_name, + common_name=the_band.common_name, + wavelength_um=the_band.wavelength_um, + aliases=the_band.aliases, + gsd=the_band.gsd, + ) + else: + new_bands = [Band(name=n) for n in target] + return BandDimension(name=self.name, bands=new_bands)
    +
    + + + +
    +[docs] +class CollectionMetadata: + """ + Wrapper for Image Collection metadata. + + Simplifies getting values from deeply nested mappings, + allows additional parsing and normalizing compatibility issues. + + Metadata is expected to follow format defined by + https://openeo.org/documentation/1.0/developers/api/reference.html#operation/describe-collection + (with partial support for older versions) + + """ + + # TODO: "CollectionMetadata" is also used as "cube metadata" where the link to original collection + # might be lost (if any). Better separation between rich EO raster collection metadata and + # essential cube metadata? E.g.: also thing of vector cubes. + + def __init__(self, metadata: dict, dimensions: List[Dimension] = None): + # Original collection metadata (actual cube metadata might be altered through processes) + self._orig_metadata = metadata + + if dimensions == None: + self._dimensions = self._parse_dimensions(self._orig_metadata) + else: + self._dimensions = dimensions + self._band_dimension = None + self._temporal_dimension = None + for dim in self._dimensions: + # TODO: here we blindly pick last bands or temporal dimension if multiple. Let user choose? + if dim.type == "bands": + self._band_dimension = dim + if dim.type == "temporal": + self._temporal_dimension = dim + + def __eq__(self, o: Any) -> bool: + return isinstance(o, CollectionMetadata) and self._dimensions == o._dimensions + + def _clone_and_update( + self, metadata: dict = None, dimensions: List[Dimension] = None, **kwargs + ) -> CollectionMetadata: + """Create a new instance (of same class) with copied/updated fields.""" + cls = type(self) + if dimensions == None: + dimensions = self._dimensions + return cls(metadata=metadata or self._orig_metadata, dimensions=dimensions, **kwargs) + + @classmethod + def _parse_dimensions(cls, spec: dict, complain: Callable[[str], None] = warnings.warn) -> List[Dimension]: + """ + Extract data cube dimension metadata from STAC-like description of a collection. + + Dimension metadata comes from different places in spec: + - 'cube:dimensions' has dimension names (e.g. 'x', 'y', 't'), dimension extent info + and band names for band dimensions + - 'eo:bands' has more detailed band information like "common" name and wavelength info + + This helper tries to normalize/combine these sources. + + :param spec: STAC like collection metadata dict + :param complain: handler for warnings + :return list: list of `Dimension` objects + + """ + + # Dimension info is in `cube:dimensions` (or 0.4-style `properties/cube:dimensions`) + cube_dimensions = ( + deep_get(spec, "cube:dimensions", default=None) + or deep_get(spec, "properties", "cube:dimensions", default=None) + or {} + ) + if not cube_dimensions: + complain("No cube:dimensions metadata") + dimensions = [] + for name, info in cube_dimensions.items(): + dim_type = info.get("type") + if dim_type == "spatial": + dimensions.append( + SpatialDimension( + name=name, + extent=info.get("extent"), + crs=info.get("reference_system", SpatialDimension.DEFAULT_CRS), + step=info.get("step", None), + ) + ) + elif dim_type == "temporal": + dimensions.append(TemporalDimension(name=name, extent=info.get("extent"))) + elif dim_type == "bands": + bands = [Band(name=b) for b in info.get("values", [])] + if not bands: + complain("No band names in dimension {d!r}".format(d=name)) + dimensions.append(BandDimension(name=name, bands=bands)) + else: + complain("Unknown dimension type {t!r}".format(t=dim_type)) + dimensions.append(Dimension(name=name, type=dim_type)) + + # Detailed band information: `summaries/[eo|raster]:bands` (and 0.4 style `properties/eo:bands`) + eo_bands = ( + deep_get(spec, "summaries", "eo:bands", default=None) + or deep_get(spec, "summaries", "raster:bands", default=None) + or deep_get(spec, "properties", "eo:bands", default=None) + ) + if eo_bands: + # center_wavelength is in micrometer according to spec + bands_detailed = [ + Band( + name=b["name"], + common_name=b.get("common_name"), + wavelength_um=b.get("center_wavelength"), + aliases=b.get("aliases"), + gsd=b.get("openeo:gsd"), + ) + for b in eo_bands + ] + # Update band dimension with more detailed info + band_dimensions = [d for d in dimensions if d.type == "bands"] + if len(band_dimensions) == 1: + dim = band_dimensions[0] + # Update band values from 'cube:dimensions' with more detailed 'eo:bands' info + eo_band_names = [b.name for b in bands_detailed] + cube_dimension_band_names = [b.name for b in dim.bands] + if eo_band_names == cube_dimension_band_names: + dim.bands = bands_detailed + else: + complain("Band name mismatch: {a} != {b}".format(a=cube_dimension_band_names, b=eo_band_names)) + elif len(band_dimensions) == 0: + if len(dimensions) == 0: + complain("Assuming name 'bands' for anonymous band dimension.") + dimensions.append(BandDimension(name="bands", bands=bands_detailed)) + else: + complain("No 'bands' dimension in 'cube:dimensions' while having 'eo:bands' or 'raster:bands'") + else: + complain("Multiple dimensions of type 'bands'") + + return dimensions + + def get(self, *args, default=None): + return deep_get(self._orig_metadata, *args, default=default) + + @property + def extent(self) -> dict: + # TODO: is this currently used and relevant? + # TODO: check against extent metadata in dimensions + return self._orig_metadata.get("extent") + + def dimension_names(self) -> List[str]: + return list(d.name for d in self._dimensions) + +
    +[docs] + def assert_valid_dimension(self, dimension: str) -> str: + """Make sure given dimension name is valid.""" + names = self.dimension_names() + if dimension not in names: + raise ValueError(f"Invalid dimension {dimension!r}. Should be one of {names}") + return dimension
    + + + def has_band_dimension(self) -> bool: + return isinstance(self._band_dimension, BandDimension) + + @property + def band_dimension(self) -> BandDimension: + """Dimension corresponding to spectral/logic/thematic "bands".""" + if not self.has_band_dimension(): + raise MetadataException("No band dimension") + return self._band_dimension + + def has_temporal_dimension(self) -> bool: + return isinstance(self._temporal_dimension, TemporalDimension) + + @property + def temporal_dimension(self) -> TemporalDimension: + if not self.has_temporal_dimension(): + raise MetadataException("No temporal dimension") + return self._temporal_dimension + + @property + def spatial_dimensions(self) -> List[SpatialDimension]: + return [d for d in self._dimensions if isinstance(d, SpatialDimension)] + + @property + def bands(self) -> List[Band]: + """Get band metadata as list of Band metadata tuples""" + return self.band_dimension.bands + + @property + def band_names(self) -> List[str]: + """Get band names of band dimension""" + return self.band_dimension.band_names + + @property + def band_common_names(self) -> List[str]: + return self.band_dimension.common_names + + def get_band_index(self, band: Union[int, str]) -> int: + # TODO: eliminate this shortcut for smaller API surface + return self.band_dimension.band_index(band) + +
    +[docs] + def filter_bands(self, band_names: List[Union[int, str]]) -> CollectionMetadata: + """ + Create new `CollectionMetadata` with filtered band dimension + :param band_names: list of band names/indices to keep + :return: + """ + assert self.band_dimension + return self._clone_and_update(dimensions=[ + d.filter_bands(band_names) if isinstance(d, BandDimension) else d + for d in self._dimensions + ])
    + + +
    +[docs] + def append_band(self, band: Band) -> CollectionMetadata: + """ + Create new `CollectionMetadata` with given band added to band dimension. + """ + assert self.band_dimension + return self._clone_and_update(dimensions=[ + d.append_band(band) if isinstance(d, BandDimension) else d + for d in self._dimensions + ])
    + + +
    +[docs] + def rename_labels(self, dimension: str, target: list, source: list = None) -> CollectionMetadata: + """ + Renames the labels of the specified dimension from source to target. + + :param dimension: Dimension name + :param target: The new names for the labels. + :param source: The names of the labels as they are currently in the data cube. + + :return: Updated metadata + """ + self.assert_valid_dimension(dimension) + loc = self.dimension_names().index(dimension) + new_dimensions = self._dimensions.copy() + new_dimensions[loc] = new_dimensions[loc].rename_labels(target, source) + + return self._clone_and_update(dimensions=new_dimensions)
    + + +
    +[docs] + def rename_dimension(self, source: str, target: str) -> CollectionMetadata: + """ + Rename source dimension into target, preserving other properties + """ + self.assert_valid_dimension(source) + loc = self.dimension_names().index(source) + new_dimensions = self._dimensions.copy() + new_dimensions[loc] = new_dimensions[loc].rename(target) + + return self._clone_and_update(dimensions=new_dimensions)
    + + +
    +[docs] + def reduce_dimension(self, dimension_name: str) -> CollectionMetadata: + """Create new metadata object by collapsing/reducing a dimension.""" + # TODO: option to keep reduced dimension (with a single value)? + # TODO: rename argument to `name` for more internal consistency + # TODO: merge with drop_dimension (which does the same). + self.assert_valid_dimension(dimension_name) + loc = self.dimension_names().index(dimension_name) + dimensions = self._dimensions[:loc] + self._dimensions[loc + 1:] + return self._clone_and_update(dimensions=dimensions)
    + + +
    +[docs] + def reduce_spatial(self) -> CollectionMetadata: + """Create new metadata object by reducing the spatial dimensions.""" + dimensions = [d for d in self._dimensions if not isinstance(d, SpatialDimension)] + return self._clone_and_update(dimensions=dimensions)
    + + +
    +[docs] + def add_dimension(self, name: str, label: Union[str, float], type: str = None) -> CollectionMetadata: + """Create new metadata object with added dimension""" + if any(d.name == name for d in self._dimensions): + raise DimensionAlreadyExistsException(f"Dimension with name {name!r} already exists") + if type == "bands": + dim = BandDimension(name=name, bands=[Band(name=label)]) + elif type == "spatial": + dim = SpatialDimension(name=name, extent=[label, label]) + elif type == "temporal": + dim = TemporalDimension(name=name, extent=[label, label]) + else: + dim = Dimension(type=type or "other", name=name) + return self._clone_and_update(dimensions=self._dimensions + [dim])
    + + +
    +[docs] + def drop_dimension(self, name: str = None) -> CollectionMetadata: + """Drop dimension with given name""" + dimension_names = self.dimension_names() + if name not in dimension_names: + raise ValueError("No dimension named {n!r} (valid names: {ns!r})".format(n=name, ns=dimension_names)) + return self._clone_and_update(dimensions=[d for d in self._dimensions if not d.name == name])
    + + + def _repr_html_(self): + return render_component("collection", data=self._orig_metadata) + + def __str__(self) -> str: + bands = self.band_names if self.has_band_dimension() else "no bands dimension" + return f"CollectionMetadata({self.extent} - {bands} - {self.dimension_names()})"
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/processes.html b/_modules/openeo/processes.html new file mode 100644 index 000000000..e5366020a --- /dev/null +++ b/_modules/openeo/processes.html @@ -0,0 +1,6332 @@ + + + + + + + openeo.processes — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.processes

    +
    +# Do not edit this file directly.
    +# It is automatically generated.
    +# Used command line arguments:
    +#    openeo/internal/processes/generator.py specs/openeo-processes specs/openeo-processes/proposals --output openeo/processes.py
    +# Generated on 2023-09-08
    +
    +from __future__ import annotations
    +
    +import builtins
    +
    +from openeo.internal.processes.builder import ProcessBuilderBase, UNSET
    +from openeo.internal.documentation import openeo_process
    +from openeo.rest._datacube import build_child_callback
    +
    +
    +
    +[docs] +class ProcessBuilder(ProcessBuilderBase): + """ + .. include:: api-processbuilder.rst + """ + + _ITERATION_LIMIT = 100 + + @openeo_process(process_id="add", mode="operator") + def __add__(self, other) -> ProcessBuilder: + return self.add(other) + + @openeo_process(process_id="add", mode="operator") + def __radd__(self, other) -> ProcessBuilder: + return add(other, self) + + @openeo_process(process_id="subtract", mode="operator") + def __sub__(self, other) -> ProcessBuilder: + return self.subtract(other) + + @openeo_process(process_id="subtract", mode="operator") + def __rsub__(self, other) -> ProcessBuilder: + return subtract(other, self) + + @openeo_process(process_id="multiply", mode="operator") + def __mul__(self, other) -> ProcessBuilder: + return self.multiply(other) + + @openeo_process(process_id="multiply", mode="operator") + def __rmul__(self, other) -> ProcessBuilder: + return multiply(other, self) + + @openeo_process(process_id="divide", mode="operator") + def __truediv__(self, other) -> ProcessBuilder: + return self.divide(other) + + @openeo_process(process_id="divide", mode="operator") + def __rtruediv__(self, other) -> ProcessBuilder: + return divide(other, self) + + @openeo_process(process_id="multiply", mode="operator") + def __neg__(self) -> ProcessBuilder: + return self.multiply(-1) + + @openeo_process(process_id="power", mode="operator") + def __pow__(self, other) -> ProcessBuilder: + return self.power(other) + + @openeo_process(process_id="array_element", mode="operator") + def __getitem__(self, key) -> ProcessBuilder: + if isinstance(key, builtins.int): + if key > self._ITERATION_LIMIT: + raise RuntimeError( + "Exceeded ProcessBuilder iteration limit. " + "Are you mistakenly using a Python builtin like `sum()` or `all()` in a callback " + "instead of the appropriate helpers from the `openeo.processes` module?" + ) + return self.array_element(index=key) + else: + return self.array_element(label=key) + + @openeo_process(process_id="eq", mode="operator") + def __eq__(self, other) -> ProcessBuilder: + return eq(self, other) + + @openeo_process(process_id="neq", mode="operator") + def __ne__(self, other) -> ProcessBuilder: + return neq(self, other) + + @openeo_process(process_id="lt", mode="operator") + def __lt__(self, other) -> ProcessBuilder: + return lt(self, other) + + @openeo_process(process_id="lte", mode="operator") + def __le__(self, other) -> ProcessBuilder: + return lte(self, other) + + @openeo_process(process_id="ge", mode="operator") + def __ge__(self, other) -> ProcessBuilder: + return gte(self, other) + + @openeo_process(process_id="gt", mode="operator") + def __gt__(self, other) -> ProcessBuilder: + return gt(self, other) + +
    +[docs] + @openeo_process + def absolute(self) -> ProcessBuilder: + """ + Absolute value + + :param self: A number. + + :return: The computed absolute value. + """ + return absolute(x=self)
    + + +
    +[docs] + @openeo_process + def add(self, y) -> ProcessBuilder: + """ + Addition of two numbers + + :param self: The first summand. + :param y: The second summand. + + :return: The computed sum of the two numbers. + """ + return add(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def add_dimension(self, name, label, type=UNSET) -> ProcessBuilder: + """ + Add a new dimension + + :param self: A data cube to add the dimension to. + :param name: Name for the dimension. + :param label: A dimension label. + :param type: The type of dimension, defaults to `other`. + + :return: The data cube with a newly added dimension. The new dimension has exactly one dimension label. + All other dimensions remain unchanged. + """ + return add_dimension(data=self, name=name, label=label, type=type)
    + + +
    +[docs] + @openeo_process + def aggregate_spatial(self, geometries, reducer, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for geometries + + :param self: A raster data cube. The 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. 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. + :param geometries: Geometries as GeoJSON on which the aggregation will be based. Vector properties are + preserved for vector data cubes and all GeoJSON Features. One 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. - + 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). - For + **points**, the process considers the closest pixel center. - For **lines** (line strings), the process + considers all the pixels whose centers are closest to at least one point on the line. Thus, pixels may + be part of multiple geometries and be part of multiple aggregations. To 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`). + :param reducer: A reducer to be applied on all values of each geometry. 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. + :param target_dimension: The name of a new dimensions that is used to store the results. A new + dimension will be created with the given name and type `other` (see ``add_dimension()``). Defaults to + the dimension name `result`. Fails with a `TargetDimensionExists` exception if a dimension with the + specified name exists. + :param context: Additional data to be passed to the reducer. + + :return: A vector data cube with the computed results and restricted to the bounds of the geometries. + The computed value is used for the dimension with the name that was specified in the parameter + `target_dimension`. The 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`. + """ + return aggregate_spatial( + data=self, + geometries=geometries, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + target_dimension=target_dimension, + context=context + )
    + + +
    +[docs] + @openeo_process + def aggregate_spatial_window(self, reducer, size, boundary=UNSET, align=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for rectangular windows + + :param self: 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. + :param reducer: 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. + :param size: Window size in pixels along the horizontal spatial dimensions. The first value + corresponds to the `x` axis, the second value corresponds to the `y` axis. + :param boundary: 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: - `pad` (default): pad the data cube + with the no-data value `null` to fit the required window size. - `trim`: trim the data cube to fit the + required window size. Set the parameter `align` to specifies to which corner the data is aligned to. + :param align: 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. + :param context: Additional data to be passed to the reducer. + + :return: A data cube with the newly computed values and the same dimensions. The 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. The + 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. + """ + return aggregate_spatial_window( + data=self, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + size=size, + boundary=boundary, + align=align, + context=context + )
    + + +
    +[docs] + @openeo_process + def aggregate_temporal(self, intervals, reducer, labels=UNSET, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations + + :param self: A data cube. + :param intervals: Left-closed temporal intervals, which are allowed to overlap. Each temporal interval + in the array has exactly two elements: 1. The first element is the start of the temporal interval. The + specified instance in time is **included** in the interval. 2. The second element is the end of the + temporal interval. The specified instance in time is **excluded** from the interval. The 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. + :param reducer: 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. + :param labels: Distinct labels for the intervals, which can contain dates and/or times. Is only + required to be specified if the values for the start of the temporal intervals are not distinct and + thus the default labels would not be unique. The number of labels and the number of groups need to be + equal. + :param dimension: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return aggregate_temporal( + data=self, + intervals=intervals, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + labels=labels, + dimension=dimension, + context=context + )
    + + +
    +[docs] + @openeo_process + def aggregate_temporal_period(self, period, reducer, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations based on calendar hierarchies + + :param self: The source data cube. + :param period: The time intervals to aggregate. The following pre-defined values are available: * + `hour`: Hour of the day * `day`: Day of the year * `week`: Week of the year * `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. * `month`: Month of the year * `season`: Three month periods of the calendar seasons (December - + February, March - May, June - August, September - November). * `tropical-season`: Six month periods of + the tropical seasons (November - April, May - October). * `year`: Proleptic years * `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. * `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. + :param reducer: 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. + :param dimension: 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 source 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. + :param context: Additional data to be passed to the reducer. + + :return: 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): * `hour`: `YYYY-MM- + DD-00` - `YYYY-MM-DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - `YYYY-52` * `dekad`: + `YYYY-00` - `YYYY-36` * `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` (December - February), + `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - November). * `tropical- + season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October). * `year`: `YYYY` * `decade`: + `YYY0` * `decade-ad`: `YYY1` The dimension labels in the new data cube are complete for the whole + extent of the source data cube. For example, if `period` is set to `day` and the source data cube has + two dimension labels at the beginning of the year (`2020-01-01`) and the end of a year (`2020-12-31`), + the process returns a data cube with 365 dimension labels (`2020-001`, `2020-002`, ..., `2020-365`). In + contrast, if `period` is set to `day` and the source data cube has just one dimension label + `2020-01-05`, the process returns a data cube with just a single dimension label (`2020-005`). + """ + return aggregate_temporal_period( + data=self, + period=period, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + )
    + + +
    +[docs] + @openeo_process + def all(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Are all of the values true? + + :param self: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return all(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def and_(self, y) -> ProcessBuilder: + """ + Logical AND + + :param self: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical AND. + """ + return and_(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def anomaly(self, normals, period) -> ProcessBuilder: + """ + Compute anomalies + + :param self: A data cube with exactly one temporal dimension and the following dimension labels for the + given period (`YYYY` = four-digit year, `MM` = two-digit month, `DD` two-digit day of month): * + `hour`: `YYYY-MM-DD-00` - `YYYY-MM-DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - + `YYYY-52` * `dekad`: `YYYY-00` - `YYYY-36` * `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` + (December - February), `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - + November). * `tropical-season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October). * + `year`: `YYYY` * `decade`: `YYY0` * `decade-ad`: `YYY1` * `single-period` / `climatology-period`: Any + ``aggregate_temporal_period()`` can compute such a data cube. + :param normals: A data cube with normals, e.g. daily, monthly or yearly values computed from a process + such as ``climatological_normal()``. Must contain exactly one temporal dimension with the following + dimension labels for the given period: * `hour`: `00` - `23` * `day`: `001` - `365` * `week`: `01` - + `52` * `dekad`: `00` - `36` * `month`: `01` - `12` * `season`: `djf` (December - February), `mam` + (March - May), `jja` (June - August), `son` (September - November) * `tropical-season`: `ndjfma` + (November - April), `mjjaso` (May - October) * `year`: Four-digit year numbers * `decade`: Four-digit + year numbers, the last digit being a `0` * `decade-ad`: Four-digit year numbers, the last digit being a + `1` * `single-period` / `climatology-period`: A single dimension label with any name is expected. + :param period: Specifies the time intervals available in the normals data cube. The following options + are available: * `hour`: Hour of the day * `day`: Day of the year * `week`: Week of the year * + `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. * `month`: Month of the year * `season`: Three month periods of the + calendar seasons (December - February, March - May, June - August, September - November). * `tropical- + season`: Six month periods of the tropical seasons (November - April, May - October). * `year`: + Proleptic years * `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. * `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. * `single-period` / + `climatology-period`: A single period of arbitrary length + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged. + """ + return anomaly(data=self, normals=normals, period=period)
    + + +
    +[docs] + @openeo_process + def any(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Is at least one value true? + + :param self: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return any(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def apply(self, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each pixel + + :param self: A data cube. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return apply(data=self, process=build_child_callback(process, parent_parameters=['x', 'context']), context=context)
    + + +
    +[docs] + @openeo_process + def apply_dimension(self, process, dimension, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels along a dimension + + :param self: A data cube. + :param process: 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. + :param dimension: The name of the source dimension to apply the process on. Fails with a + `DimensionNotAvailable` exception if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or `null` (the default) to use the source + dimension specified in the parameter `dimension`. By 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. + :param context: Additional data to be passed to the process. + + :return: 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 dimensions can change: + 1. The source dimension is the target dimension: - The (number of) dimensions remain unchanged as + the source dimension is the target dimension. - The source dimension properties name and type remain + unchanged. - 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. 2. The source + dimension is not the target dimension and the latter exists: - The number of dimensions decreases by + one as the source dimension is dropped. - The target dimension properties name and type remain + unchanged. All other dimension properties change as defined in the list below. 3. The source dimension + is not the target dimension and the latter does not exist: - The number of dimensions remain + unchanged, but the source dimension is replaced with the target dimension. - The target dimension + has the specified name and the type other. All other dimension properties are set as defined in the + list below. Unless otherwise stated above, for the given (target) dimension the following applies: - + the number of dimension labels is equal to the number of values computed by the process, - the + dimension labels are incrementing integers starting from zero, - the resolution changes, and - the + reference system is undefined. + """ + return apply_dimension( + data=self, + process=build_child_callback(process, parent_parameters=['data', 'context']), + dimension=dimension, + target_dimension=target_dimension, + context=context + )
    + + +
    +[docs] + @openeo_process + def apply_kernel(self, kernel, factor=UNSET, border=UNSET, replace_invalid=UNSET) -> ProcessBuilder: + """ + Apply a spatial convolution with a kernel + + :param self: A data cube. + :param kernel: 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. + :param factor: A factor that is multiplied to each value after the kernel has been applied. This is + basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often + required for some kernel-based algorithms such as the Gaussian blur. + :param border: Determines how the data is extended when the kernel overlaps with the borders. Defaults + to fill the border with zeroes. The following options are available: * *numeric value* - fill with a + user-defined constant number `n`: `nnnnnn|abcdefgh|nnnnnn` (default, with `n` = 0) * `replicate` - + repeat the value from the pixel at the border: `aaaaaa|abcdefgh|hhhhhh` * `reflect` - mirror/reflect + from the border: `fedcba|abcdefgh|hgfedc` * `reflect_pixel` - mirror/reflect from the center of the + pixel at the border: `gfedcb|abcdefgh|gfedcb` * `wrap` - repeat/wrap the image: + `cdefgh|abcdefgh|abcdef` + :param replace_invalid: This parameter specifies the value to replace non-numerical or infinite + numerical values with. By default, those values are replaced with zeroes. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return apply_kernel(data=self, kernel=kernel, factor=factor, border=border, replace_invalid=replace_invalid)
    + + +
    +[docs] + @openeo_process + def apply_neighborhood(self, process, size, overlap=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels in a n-dimensional neighborhood + + :param self: A data cube. + :param process: Process to be applied on all neighborhoods. + :param size: Neighborhood sizes along each dimension. This 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. + :param overlap: Overlap of neighborhoods along each dimension to avoid border effects. By default no + overlap is provided. For 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. Be aware that large overlaps increase the need for computational resources and modifying + overlapping data in subsequent operations have no effect. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return apply_neighborhood( + data=self, + process=build_child_callback(process, parent_parameters=['data', 'context']), + size=size, + overlap=overlap, + context=context + )
    + + +
    +[docs] + @openeo_process + def arccos(self) -> ProcessBuilder: + """ + Inverse cosine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arccos(x=self)
    + + +
    +[docs] + @openeo_process + def arcosh(self) -> ProcessBuilder: + """ + Inverse hyperbolic cosine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arcosh(x=self)
    + + +
    +[docs] + @openeo_process + def arcsin(self) -> ProcessBuilder: + """ + Inverse sine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arcsin(x=self)
    + + +
    +[docs] + @openeo_process + def arctan(self) -> ProcessBuilder: + """ + Inverse tangent + + :param self: A number. + + :return: The computed angle in radians. + """ + return arctan(x=self)
    + + +
    +[docs] + @openeo_process + def arctan2(self, x) -> ProcessBuilder: + """ + Inverse tangent of two numbers + + :param self: A number to be used as the dividend. + :param x: A number to be used as the divisor. + + :return: The computed angle in radians. + """ + return arctan2(y=self, x=x)
    + + +
    +[docs] + @openeo_process + def ard_normalized_radar_backscatter(self, elevation_model=UNSET, contributing_area=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant SAR NRB generation + + :param self: The source data cube containing SAR input. + :param elevation_model: 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. + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options + will reduce portability. + + :return: Backscatter values expressed as gamma0 in linear scale. In 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: - `mask`: A data mask that + indicates which values are valid (1), invalid (0) or contain no-data (null). - `local_incidence_angle`: + A band with DEM-based local incidence angles in degrees. The data returned is CARD4L compliant with + corresponding metadata. + """ + return ard_normalized_radar_backscatter( + data=self, + elevation_model=elevation_model, + contributing_area=contributing_area, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + )
    + + +
    +[docs] + @openeo_process + def ard_surface_reflectance(self, atmospheric_correction_method, cloud_detection_method, elevation_model=UNSET, atmospheric_correction_options=UNSET, cloud_detection_options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant Surface Reflectance generation + + :param self: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances. There must be a single dimension of type `bands` available. + :param atmospheric_correction_method: The atmospheric correction method to use. + :param cloud_detection_method: The cloud detection method to use. Each method supports detecting + different atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water + vapour in optical imagery. + :param elevation_model: 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. + :param atmospheric_correction_options: Proprietary options for the atmospheric correction method. + Specifying proprietary options will reduce portability. + :param cloud_detection_options: Proprietary options for the cloud detection method. Specifying + proprietary options will reduce portability. + + :return: 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: 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. Depending on the + methods used, several additional bands will be added to the data cube: - `date` (optional): Specifies + per-pixel acquisition timestamps. - `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. - `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. - `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. - `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. - `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. - `incidence-angle` (optional): Specifies per-pixel incidence angles in degrees. - `azimuth` + (optional): Specifies per-pixel azimuth angles in degrees. - `sun-azimuth:` (optional): Specifies per- + pixel sun azimuth angles in degrees. - `sun-elevation` (optional): Specifies per-pixel sun elevation + angles in degrees. - `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. - `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. - `terrain-illumination` (optional): + Contains coefficients used for terrain illumination correction are provided for each pixel. The data + returned is CARD4L compliant with corresponding metadata. + """ + return ard_surface_reflectance( + data=self, + atmospheric_correction_method=atmospheric_correction_method, + cloud_detection_method=cloud_detection_method, + elevation_model=elevation_model, + atmospheric_correction_options=atmospheric_correction_options, + cloud_detection_options=cloud_detection_options + )
    + + +
    +[docs] + @openeo_process + def array_append(self, value, label=UNSET) -> ProcessBuilder: + """ + Append a value to an array + + :param self: An array. + :param value: Value to append to the array. + :param label: If the given array is a labeled array, a new label for the new value should be given. If + not given or `null`, the array index as string is used as the label. If in any case the label exists, a + `LabelExists` exception is thrown. + + :return: The new array with the value being appended. + """ + return array_append(data=self, value=value, label=label)
    + + +
    +[docs] + @openeo_process + def array_apply(self, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each array element + + :param self: An array. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: An array with the newly computed values. The number of elements are the same as for the + original array. + """ + return array_apply( + data=self, + process=build_child_callback(process, parent_parameters=['x', 'index', 'label', 'context']), + context=context + )
    + + +
    +[docs] + @openeo_process + def array_concat(self, array2) -> ProcessBuilder: + """ + Merge two arrays + + :param self: The first array. + :param array2: The second array. + + :return: The merged array. + """ + return array_concat(array1=self, array2=array2)
    + + +
    +[docs] + @openeo_process + def array_contains(self, value) -> ProcessBuilder: + """ + Check whether the array contains a given value + + :param self: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `false`. + + :return: `true` if the list contains the value, false` otherwise. + """ + return array_contains(data=self, value=value)
    + + +
    +[docs] + @openeo_process + def array_create(self=UNSET, repeat=UNSET) -> ProcessBuilder: + """ + Create an array + + :param self: A (native) array to fill the newly created array with. Defaults to an empty array. + :param repeat: 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`. + + :return: The newly created array. + """ + return array_create(data=self, repeat=repeat)
    + + +
    +[docs] + @openeo_process + def array_create_labeled(self, labels) -> ProcessBuilder: + """ + Create a labeled array + + :param self: An array of values to be used. + :param labels: An array of labels to be used. + + :return: The newly created labeled array. + """ + return array_create_labeled(data=self, labels=labels)
    + + +
    +[docs] + @openeo_process + def array_element(self, index=UNSET, label=UNSET, return_nodata=UNSET) -> ProcessBuilder: + """ + Get an element from an array + + :param self: An array. + :param index: The zero-based index of the element to retrieve. + :param label: 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. + :param return_nodata: By default this process throws an `ArrayElementNotAvailable` exception if the + index or label is invalid. If you want to return `null` instead, set this flag to `true`. + + :return: The value of the requested element. + """ + return array_element(data=self, index=index, label=label, return_nodata=return_nodata)
    + + +
    +[docs] + @openeo_process + def array_filter(self, condition, context=UNSET) -> ProcessBuilder: + """ + Filter an array based on a condition + + :param self: An array. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: An array filtered by the specified condition. The number of elements are less than or equal + compared to the original array. + """ + return array_filter( + data=self, + condition=build_child_callback(condition, parent_parameters=['x', 'index', 'label', 'context']), + context=context + )
    + + +
    +[docs] + @openeo_process + def array_find(self, value, reverse=UNSET) -> ProcessBuilder: + """ + Get the index for a value in an array + + :param self: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `null`. + :param reverse: By default, this process finds the index of the first match. To return the index of the + last match instead, set this flag to `true`. + + :return: The index of the first element with the specified value. If no element was found, `null` is + returned. + """ + return array_find(data=self, value=value, reverse=reverse)
    + + +
    +[docs] + @openeo_process + def array_find_label(self, label) -> ProcessBuilder: + """ + Get the index for a label in a labeled array + + :param self: List to find the label in. + :param label: Label to find in `data`. + + :return: The index of the element with the specified label assigned. If no such label was found, `null` + is returned. + """ + return array_find_label(data=self, label=label)
    + + +
    +[docs] + @openeo_process + def array_interpolate_linear(self) -> ProcessBuilder: + """ + One-dimensional linear interpolation for arrays + + :param self: An array of numbers and no-data values. If 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. + + :return: 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. + """ + return array_interpolate_linear(data=self)
    + + +
    +[docs] + @openeo_process + def array_labels(self) -> ProcessBuilder: + """ + Get the labels for an array + + :param self: An array. + + :return: The labels or indices as array. + """ + return array_labels(data=self)
    + + +
    +[docs] + @openeo_process + def array_modify(self, values, index, length=UNSET) -> ProcessBuilder: + """ + Change the content of an array (remove, insert, update) + + :param self: The array to modify. + :param values: The values to insert into the `data` array. + :param index: The index in the `data` array of the element to insert the value(s) before. If the index + is greater than the number of elements in the `data` array, the process throws an + `ArrayElementNotAvailable` exception. To insert after the last element, there are two options: 1. Use + the simpler processes ``array_append()`` to append a single value or ``array_concat()`` to append + multiple values. 2. 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`. + :param length: The number of elements in the `data` array to remove (or replace) starting from the + given index. If the array contains fewer elements, the process simply removes all elements up to the + end. + + :return: An array with values added, updated or removed. + """ + return array_modify(data=self, values=values, index=index, length=length)
    + + +
    +[docs] + @openeo_process + def arsinh(self) -> ProcessBuilder: + """ + Inverse hyperbolic sine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arsinh(x=self)
    + + +
    +[docs] + @openeo_process + def artanh(self) -> ProcessBuilder: + """ + Inverse hyperbolic tangent + + :param self: A number. + + :return: The computed angle in radians. + """ + return artanh(x=self)
    + + +
    +[docs] + @openeo_process + def atmospheric_correction(self, method, elevation_model=UNSET, options=UNSET) -> ProcessBuilder: + """ + Apply atmospheric correction + + :param self: Data cube containing multi-spectral optical top of atmosphere reflectances to be + corrected. + :param method: The atmospheric correction method to use. To get reproducible results, you have to set a + specific method. Set 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. + :param elevation_model: 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. + :param options: Proprietary options for the atmospheric correction method. Specifying proprietary + options will reduce portability. + + :return: Data cube containing bottom of atmosphere reflectances. + """ + return atmospheric_correction(data=self, method=method, elevation_model=elevation_model, options=options)
    + + +
    +[docs] + @openeo_process + def between(self, min, max, exclude_max=UNSET) -> ProcessBuilder: + """ + Between comparison + + :param self: The value to check. + :param min: Lower boundary (inclusive) to check against. + :param max: Upper boundary (inclusive) to check against. + :param exclude_max: Exclude the upper boundary `max` if set to `true`. Defaults to `false`. + + :return: `true` if `x` is between the specified bounds, otherwise `false`. + """ + return between(x=self, min=min, max=max, exclude_max=exclude_max)
    + + +
    +[docs] + @openeo_process + def ceil(self) -> ProcessBuilder: + """ + Round fractions up + + :param self: A number to round up. + + :return: The number rounded up. + """ + return ceil(x=self)
    + + +
    +[docs] + @openeo_process + def climatological_normal(self, period, climatology_period=UNSET) -> ProcessBuilder: + """ + Compute climatology normals + + :param self: A data cube with exactly one temporal dimension. The data cube must span at least the + temporal interval specified in the parameter `climatology-period`. Seasonal periods may span two + consecutive years, e.g. temporal winter that includes months December, January and February. If the + required months before the actual climate period are available, the season is taken into account. If + not available, the first season is not taken into account and the seasonal mean is based on one year + less than the other seasonal normals. The incomplete season at the end of the last year is never taken + into account. + :param period: The time intervals to aggregate the average value for. The following pre-defined + frequencies are supported: * `day`: Day of the year * `month`: Month of the year * `climatology- + period`: The period specified in the `climatology-period`. * `season`: Three month periods of the + calendar seasons (December - February, March - May, June - August, September - November). * `tropical- + season`: Six month periods of the tropical seasons (November - April, May - October). + :param climatology_period: 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). + + :return: 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 temporal + dimension. The temporal dimension has the following dimension labels: * `day`: `001` - `365` * + `month`: `01` - `12` * `climatology-period`: `climatology-period` * `season`: `djf` (December - + February), `mam` (March - May), `jja` (June - August), `son` (September - November) * `tropical- + season`: `ndjfma` (November - April), `mjjaso` (May - October) + """ + return climatological_normal(data=self, period=period, climatology_period=climatology_period)
    + + +
    +[docs] + @openeo_process + def clip(self, min, max) -> ProcessBuilder: + """ + Clip a value between a minimum and a maximum + + :param self: A number. + :param min: Minimum value. If the value is lower than this value, the process will return the value of + this parameter. + :param max: Maximum value. If the value is greater than this value, the process will return the value + of this parameter. + + :return: The value clipped to the specified range. + """ + return clip(x=self, min=min, max=max)
    + + +
    +[docs] + @openeo_process + def cloud_detection(self, method, options=UNSET) -> ProcessBuilder: + """ + Create cloud masks + + :param self: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances on which to perform cloud detection. + :param method: The cloud detection method to use. To get reproducible results, you have to set a + specific method. Set 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. + :param options: Proprietary options for the cloud detection method. Specifying proprietary options will + reduce portability. + + :return: 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. + """ + return cloud_detection(data=self, method=method, options=options)
    + + +
    +[docs] + @openeo_process + def constant(self) -> ProcessBuilder: + """ + Define a constant value + + :param self: The value of the constant. + + :return: The value of the constant. + """ + return constant(x=self)
    + + +
    +[docs] + @openeo_process + def cos(self) -> ProcessBuilder: + """ + Cosine + + :param self: An angle in radians. + + :return: The computed cosine of `x`. + """ + return cos(x=self)
    + + +
    +[docs] + @openeo_process + def cosh(self) -> ProcessBuilder: + """ + Hyperbolic cosine + + :param self: An angle in radians. + + :return: The computed hyperbolic cosine of `x`. + """ + return cosh(x=self)
    + + +
    +[docs] + @openeo_process + def count(self, condition=UNSET, context=UNSET) -> ProcessBuilder: + """ + Count the number of elements + + :param self: An array with elements of any data type. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: The counted number of elements. + """ + return count(data=self, condition=condition, context=context)
    + + +
    +[docs] + @openeo_process + def create_raster_cube(self) -> ProcessBuilder: + """ + Create an empty raster data cube + + :return: An empty raster data cube with zero dimensions. + """ + return create_raster_cube()
    + + +
    +[docs] + @openeo_process + def cummax(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative maxima + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative maxima. + """ + return cummax(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def cummin(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative minima + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative minima. + """ + return cummin(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def cumproduct(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative products + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative products. + """ + return cumproduct(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def cumsum(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative sums + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative sums. + """ + return cumsum(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def date_shift(self, value, unit) -> ProcessBuilder: + """ + Manipulates dates and times by addition or subtraction + + :param self: The date (and optionally time) to manipulate. If 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. + :param value: 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. + :param unit: The unit for the value given. The following pre-defined units are available: - + millisecond: Milliseconds - second: Seconds - leap seconds are ignored in computations. - minute: + Minutes - hour: Hours - day: Days - changes only the the day part of a date - week: Weeks (equivalent + to 7 days) - month: Months - year: Years Manipulations 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`. + + :return: The manipulated date. If a time component was given in the parameter `date`, the time + component is returned with the date. + """ + return date_shift(date=self, value=value, unit=unit)
    + + +
    +[docs] + @openeo_process + def dimension_labels(self, dimension) -> ProcessBuilder: + """ + Get the dimension labels + + :param self: The data cube. + :param dimension: The name of the dimension to get the labels for. + + :return: The labels as an array. + """ + return dimension_labels(data=self, dimension=dimension)
    + + +
    +[docs] + @openeo_process + def divide(self, y) -> ProcessBuilder: + """ + Division of two numbers + + :param self: The dividend. + :param y: The divisor. + + :return: The computed result. + """ + return divide(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def drop_dimension(self, name) -> ProcessBuilder: + """ + Remove a dimension + + :param self: The data cube to drop a dimension from. + :param name: Name of the dimension to drop. + + :return: A data cube without the specified dimension. The number of dimensions decreases by one, but + the dimension properties (name, type, labels, reference system and resolution) for all other dimensions + remain unchanged. + """ + return drop_dimension(data=self, name=name)
    + + +
    +[docs] + @openeo_process + def e(self) -> ProcessBuilder: + """ + Euler's number (e) + + :return: The numerical value of Euler's number. + """ + return e()
    + + +
    +[docs] + @openeo_process + def eq(self, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Equal to comparison + + :param self: First operand. + :param y: Second operand. + :param delta: 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. + This option is basically an alias for the following computation: `lte(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be + disabled by setting this parameter to `false`. + + :return: `true` if `x` is equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return eq(x=self, y=y, delta=delta, case_sensitive=case_sensitive)
    + + +
    +[docs] + @openeo_process + def exp(self) -> ProcessBuilder: + """ + Exponentiation to the base e + + :param self: The numerical exponent. + + :return: The computed value for *e* raised to the power of `p`. + """ + return exp(p=self)
    + + +
    +[docs] + @openeo_process + def extrema(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum and maximum values + + :param self: An array of numbers. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. + Setting this flag to `false` considers no-data values so that an array with two `null` values is + returned if any value is such a value. + + :return: An array containing the minimum and maximum values for the specified numbers. The first + element is the minimum, the second element is the maximum. If the input array is empty both elements + are set to `null`. + """ + return extrema(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def filter_bands(self, bands=UNSET, wavelengths=UNSET) -> ProcessBuilder: + """ + Filter the bands by names + + :param self: A data cube with bands. + :param bands: 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. The 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. + :param wavelengths: 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). The 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. + + :return: A data cube limited to a subset of its original bands. The dimensions and dimension properties + (name, type, labels, reference system and resolution) remain unchanged, except that the dimension of + type `bands` has less (or the same) dimension labels. + """ + return filter_bands(data=self, bands=bands, wavelengths=wavelengths)
    + + +
    +[docs] + @openeo_process + def filter_bbox(self, extent) -> ProcessBuilder: + """ + Spatial filter using a bounding box + + :param self: A data cube. + :param extent: A bounding box, which may include a vertical axis (see `base` and `height`). + + :return: A data cube restricted to the bounding box. The dimensions and dimension properties (name, + type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions + have less (or the same) dimension labels. + """ + return filter_bbox(data=self, extent=extent)
    + + +
    +[docs] + @openeo_process + def filter_labels(self, condition, dimension, context=UNSET) -> ProcessBuilder: + """ + Filter dimension labels based on a condition + + :param self: A data cube. + :param condition: A condition that is evaluated against each dimension label in the specified + dimension. A dimension label and the corresponding data is preserved for the given dimension, if the + condition returns `true`. + :param dimension: The name of the dimension to filter on. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param context: Additional data to be passed to the condition. + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged, except that the given dimension has less (or the same) + dimension labels. + """ + return filter_labels( + data=self, + condition=build_child_callback(condition, parent_parameters=['value', 'context']), + dimension=dimension, + context=context + )
    + + +
    +[docs] + @openeo_process + def filter_spatial(self, geometries) -> ProcessBuilder: + """ + Spatial filter using geometries + + :param self: A data cube. + :param geometries: One or more geometries used for filtering, specified as GeoJSON. + + :return: A data cube restricted to the specified geometries. The dimensions and dimension properties + (name, type, labels, reference system and resolution) remain unchanged, except that the spatial + dimensions have less (or the same) dimension labels. + """ + return filter_spatial(data=self, geometries=geometries)
    + + +
    +[docs] + @openeo_process + def filter_temporal(self, extent, dimension=UNSET) -> ProcessBuilder: + """ + Temporal filter based on temporal intervals + + :param self: A data cube. + :param extent: Left-closed temporal interval, i.e. an array with exactly two elements: 1. The first + element is the start of the temporal interval. The specified instance in time is **included** in the + interval. 2. The second element is the end of the temporal interval. The specified instance in time is + **excluded** from the interval. The 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. + :param dimension: 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. + + :return: 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. + """ + return filter_temporal(data=self, extent=extent, dimension=dimension)
    + + +
    +[docs] + @openeo_process + def first(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + First element + + :param self: An array with elements of any data type. + :param ignore_nodata: 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 returned if the first value is + such a value. + + :return: The first element of the input array. + """ + return first(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def fit_class_random_forest(self, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest classification model + + :param self: The predictors for the classification model as a vector data cube. Aggregated to the + features (vectors) of the target input variable. + :param target: The training sites for the classification model as a vector data cube. This is + associated with the target variable for the Random Forest model. The geometry has to associated with a + value to predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options + are available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables + are considered for each split. - `onethird`: A third of the number of variables are considered for each + split. - `sqrt`: The square root of the number of variables are considered for each split. This is + often the default for classification. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, + no seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with + ``load_ml_model()``. + """ + return fit_class_random_forest(predictors=self, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed)
    + + +
    +[docs] + @openeo_process + def fit_curve(self, parameters, function, dimension) -> ProcessBuilder: + """ + Curve fitting + + :param self: A data cube. + :param parameters: Defined the number of parameters for the model function and provides an initial + guess for them. At least one parameter is required. + :param function: The model function. It must take the parameters to fit as array through the first + argument and the independent variable `x` as the second argument. It is recommended to store the model + function as a user-defined process on the back-end to be able to re-use the model function with the + computed optimal values for the parameters afterwards. + :param dimension: The name of the dimension for curve fitting. Must be a dimension with labels that + have a order (i.e. numerical labels or a temporal dimension). Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + + :return: A data cube with the optimal values for the parameters. + """ + return fit_curve( + data=self, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension + )
    + + +
    +[docs] + @openeo_process + def fit_regr_random_forest(self, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest regression model + + :param self: The predictors for the regression model as a vector data cube. Aggregated to the features + (vectors) of the target input variable. + :param target: The training sites for the regression model as a vector data cube. This is associated + with the target variable for the Random Forest model. The geometry has to associated with a value to + predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options + are available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables + are considered for each split. - `onethird`: A third of the number of variables are considered for each + split. This is often the default for regression. - `sqrt`: The square root of the number of variables + are considered for each split. + :param num_trees: The number of trees build within the Random Forest regression. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, + no seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with + ``load_ml_model()``. + """ + return fit_regr_random_forest(predictors=self, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed)
    + + +
    +[docs] + @openeo_process + def flatten_dimensions(self, dimensions, target_dimension, label_separator=UNSET) -> ProcessBuilder: + """ + Combine multiple dimensions into a single dimension + + :param self: A data cube. + :param dimensions: The names of the dimension to combine. The order of the array defines the order in + which the dimension labels and values are combined (see the example in the process description). Fails + with a `DimensionNotAvailable` exception if at least one of the specified dimensions does not exist. + :param target_dimension: The name of the new target dimension. A new dimensions will be created with + the given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` + exception if a dimension with the specified name exists. + :param label_separator: The string that will be used as a separator for the concatenated dimension + labels. To unambiguously revert the dimension labels with the process ``unflatten_dimension()``, the + given string must not be contained in any of the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system + and resolution) for all other dimensions remain unchanged. + """ + return flatten_dimensions(data=self, dimensions=dimensions, target_dimension=target_dimension, label_separator=label_separator)
    + + +
    +[docs] + @openeo_process + def floor(self) -> ProcessBuilder: + """ + Round fractions down + + :param self: A number to round down. + + :return: The number rounded down. + """ + return floor(x=self)
    + + +
    +[docs] + @openeo_process + def gt(self, y) -> ProcessBuilder: + """ + Greater than comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly greater than `y` or `null` if any operand is `null`, otherwise + `false`. + """ + return gt(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def gte(self, y) -> ProcessBuilder: + """ + Greater than or equal to comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is greater than or equal to `y`, `null` if any operand is `null`, otherwise + `false`. + """ + return gte(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def if_(self, accept, reject=UNSET) -> ProcessBuilder: + """ + If-Then-Else conditional + + :param self: A boolean value. + :param accept: A value that is returned if the boolean value is `true`. + :param reject: A value that is returned if the boolean value is **not** `true`. Defaults to `null`. + + :return: Either the `accept` or `reject` argument depending on the given boolean value. + """ + return if_(value=self, accept=accept, reject=reject)
    + + +
    +[docs] + @openeo_process + def inspect(self, code=UNSET, level=UNSET, message=UNSET) -> ProcessBuilder: + """ + Add information to the logs + + :param self: Data to log. + :param code: A label to help identify one or more log entries originating from this process in the list + of all log entries. It can help to group or filter log entries and is usually not unique. + :param level: The severity level of this message, defaults to `info`. + :param message: A message to send in addition to the data. + + :return: The data as passed to the `data` parameter without any modification. + """ + return inspect(data=self, code=code, level=level, message=message)
    + + +
    +[docs] + @openeo_process + def int(self) -> ProcessBuilder: + """ + Integer part of a number + + :param self: A number. + + :return: Integer part of the number. + """ + return int(x=self)
    + + +
    +[docs] + @openeo_process + def is_infinite(self) -> ProcessBuilder: + """ + Value is an infinite number + + :param self: The data to check. + + :return: `true` if the data is an infinite number, otherwise `false`. + """ + return is_infinite(x=self)
    + + +
    +[docs] + @openeo_process + def is_nan(self) -> ProcessBuilder: + """ + Value is not a number + + :param self: The data to check. + + :return: `true` if the data is not a number, otherwise `false`. + """ + return is_nan(x=self)
    + + +
    +[docs] + @openeo_process + def is_nodata(self) -> ProcessBuilder: + """ + Value is a no-data value + + :param self: The data to check. + + :return: `true` if the data is a no-data value, otherwise `false`. + """ + return is_nodata(x=self)
    + + +
    +[docs] + @openeo_process + def is_valid(self) -> ProcessBuilder: + """ + Value is valid data + + :param self: The data to check. + + :return: `true` if the data is valid, otherwise `false`. + """ + return is_valid(x=self)
    + + +
    +[docs] + @openeo_process + def last(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Last element + + :param self: An array with elements of any data type. + :param ignore_nodata: 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 returned if the last value is + such a value. + + :return: The last element of the input array. + """ + return last(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def linear_scale_range(self, inputMin, inputMax, outputMin=UNSET, outputMax=UNSET) -> ProcessBuilder: + """ + Linear transformation between two ranges + + :param self: A number to transform. The number gets clipped to the bounds specified in `inputMin` and + `inputMax`. + :param inputMin: Minimum value the input can obtain. + :param inputMax: Maximum value the input can obtain. + :param outputMin: Minimum value of the desired output range. + :param outputMax: Maximum value of the desired output range. + + :return: The transformed number. + """ + return linear_scale_range(x=self, inputMin=inputMin, inputMax=inputMax, outputMin=outputMin, outputMax=outputMax)
    + + +
    +[docs] + @openeo_process + def ln(self) -> ProcessBuilder: + """ + Natural logarithm + + :param self: A number to compute the natural logarithm for. + + :return: The computed natural logarithm. + """ + return ln(x=self)
    + + +
    +[docs] + @openeo_process + def load_collection(self, spatial_extent, temporal_extent, bands=UNSET, properties=UNSET) -> ProcessBuilder: + """ + Load a collection + + :param self: The collection id. + :param spatial_extent: Limits the data to load from the collection to the specified bounding box or + polygons. The 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). The + GeoJSON can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a + `Feature` with a `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one + `Feature` with `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` + or `MultiPolygon` geometries. To maximize interoperability, `GeometryCollection` should be avoided in + favour of one of the alternatives above. Set 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. + :param temporal_extent: 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: 1. The first element is the start of the temporal interval. The specified + instance in time is **included** in the interval. 2. The second element is the end of the temporal + interval. The specified instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is + recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded + data. + :param properties: Limits the data by metadata properties to include only data in the data cube which + all given conditions return `true` for (AND operation). Specify key-value-pairs with the key being the + name of the metadata property, which can be retrieved with the openEO Data Discovery for Collections. + The value must be a condition (user-defined process) to be evaluated against the collection metadata, + see the example. + + :return: A data cube for further processing. The dimensions and dimension properties (name, type, + labels, reference system and resolution) correspond to the collection's metadata, but the dimension + labels are restricted as specified in the parameters. + """ + return load_collection(id=self, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands, properties=properties)
    + + +
    +[docs] + @openeo_process + def load_ml_model(self) -> ProcessBuilder: + """ + Load a ML model + + :param self: The STAC Item to load the machine learning model from. The STAC Item must implement the + `ml-model` extension. + + :return: A machine learning model to be used with machine learning processes such as + ``predict_random_forest()``. + """ + return load_ml_model(id=self)
    + + +
    +[docs] + @openeo_process + def load_result(self, spatial_extent=UNSET, temporal_extent=UNSET, bands=UNSET) -> ProcessBuilder: + """ + Load batch job results + + :param self: The id of a batch job with results. + :param spatial_extent: Limits the data to load from the batch job result to the specified bounding box + or polygons. The 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). + The GeoJSON can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a + `Feature` with a `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one + `Feature` with `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` + or `MultiPolygon` geometries. To maximize interoperability, `GeometryCollection` should be avoided in + favour of one of the alternatives above. Set 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. + :param temporal_extent: Limits the data to load from the batch job result 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: 1. The first element is the start of the temporal interval. The specified + instance in time is **included** in the interval. 2. The second element is the end of the temporal + interval. The specified instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is + recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded + data. + + :return: A data cube for further processing. + """ + return load_result(id=self, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands)
    + + +
    +[docs] + @openeo_process + def load_uploaded_files(self, format, options=UNSET) -> ProcessBuilder: + """ + Load files from the user workspace + + :param self: The files to read. Folders can't be specified, specify all files instead. An exception is + thrown if a file can't be read. + :param format: The file format to read from. It must be one of the values that the server reports as + supported input file formats, which usually correspond to the short GDAL/OGR codes. If the format is + not suitable for loading the data, a `FormatUnsuitable` exception will be thrown. This parameter is + *case insensitive*. + :param options: The file format parameters to be used to read the files. Must correspond to the + parameters that the server reports as supported parameters for the chosen `format`. The parameter names + and valid values usually correspond to the GDAL/OGR format options. + + :return: A data cube for further processing. + """ + return load_uploaded_files(paths=self, format=format, options=options)
    + + +
    +[docs] + @openeo_process + def log(self, base) -> ProcessBuilder: + """ + Logarithm to a base + + :param self: A number to compute the logarithm for. + :param base: The numerical base. + + :return: The computed logarithm. + """ + return log(x=self, base=base)
    + + +
    +[docs] + @openeo_process + def lt(self, y) -> ProcessBuilder: + """ + Less than comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly less than `y`, `null` if any operand is `null`, otherwise `false`. + """ + return lt(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def lte(self, y) -> ProcessBuilder: + """ + Less than or equal to comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is less than or equal to `y`, `null` if any operand is `null`, otherwise + `false`. + """ + return lte(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def mask(self, mask, replacement=UNSET) -> ProcessBuilder: + """ + Apply a raster mask + + :param self: A raster data cube. + :param mask: A mask as a raster data cube. Every pixel in `data` must have a corresponding element in + `mask`. + :param replacement: The value used to replace masked values with. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, + labels, reference system and resolution) remain unchanged. + """ + return mask(data=self, mask=mask, replacement=replacement)
    + + +
    +[docs] + @openeo_process + def mask_polygon(self, mask, replacement=UNSET, inside=UNSET) -> ProcessBuilder: + """ + Apply a polygon mask + + :param self: A raster data cube. + :param mask: A GeoJSON object containing at least one polygon. The provided feature types can be one of + the following: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a `Polygon` or + `MultiPolygon` geometry, * a `FeatureCollection` containing at least one `Feature` with `Polygon` or + `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` + geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of + the alternatives above. + :param replacement: The value used to replace masked values with. + :param inside: If set to `true` all pixels for which the point at the pixel center **does** intersect + with any polygon are replaced. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, + labels, reference system and resolution) remain unchanged. + """ + return mask_polygon(data=self, mask=mask, replacement=replacement, inside=inside)
    + + +
    +[docs] + @openeo_process + def max(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Maximum value + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The maximum value. + """ + return max(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def mean(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Arithmetic mean (average) + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed arithmetic mean. + """ + return mean(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def median(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Statistical median + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed statistical median. + """ + return median(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def merge_cubes(self, cube2, overlap_resolver=UNSET, context=UNSET) -> ProcessBuilder: + """ + Merge two data cubes + + :param self: The first data cube. + :param cube2: The second data cube. + :param overlap_resolver: A reduction operator that resolves the conflict if the data overlaps. The + reducer must return a value of the same data type as the input values are. The reduction operator may + be a single process such as ``multiply()`` or consist of multiple sub-processes. `null` (the default) + can be specified if no overlap resolver is required. + :param context: Additional data to be passed to the overlap resolver. + + :return: The merged data cube. See the process description for details regarding the dimensions and + dimension properties (name, type, labels, reference system and resolution). + """ + return merge_cubes( + cube1=self, + cube2=cube2, + overlap_resolver=build_child_callback(overlap_resolver, parent_parameters=['x', 'y', 'context']), + context=context + )
    + + +
    +[docs] + @openeo_process + def min(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum value + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The minimum value. + """ + return min(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def mod(self, y) -> ProcessBuilder: + """ + Modulo + + :param self: A number to be used as the dividend. + :param y: A number to be used as the divisor. + + :return: The remainder after division. + """ + return mod(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def multiply(self, y) -> ProcessBuilder: + """ + Multiplication of two numbers + + :param self: The multiplier. + :param y: The multiplicand. + + :return: The computed product of the two numbers. + """ + return multiply(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def nan(self) -> ProcessBuilder: + """ + Not a Number (NaN) + + :return: Returns `NaN`. + """ + return nan()
    + + +
    +[docs] + @openeo_process + def ndvi(self, nir=UNSET, red=UNSET, target_band=UNSET) -> ProcessBuilder: + """ + Normalized Difference Vegetation Index + + :param self: A raster data cube with two bands that have the common names `red` and `nir` assigned. + :param nir: The name of the NIR band. Defaults to the band that has the common name `nir` assigned. + Either 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. + :param red: The name of the red band. Defaults to the band that has the common name `red` assigned. + Either 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. + :param target_band: By default, the dimension of type `bands` is dropped. To keep the dimension specify + a new band name in this parameter so that a new dimension label with the specified name will be added + for the computed values. + + :return: A raster data cube containing the computed NDVI values. The structure of the data cube differs + depending on the value passed to `target_band`: * `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. * `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`. + """ + return ndvi(data=self, nir=nir, red=red, target_band=target_band)
    + + +
    +[docs] + @openeo_process + def neq(self, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Not equal to comparison + + :param self: First operand. + :param y: Second operand. + :param delta: 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. + This option is basically an alias for the following computation: `gt(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be + disabled by setting this parameter to `false`. + + :return: `true` if `x` is *not* equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return neq(x=self, y=y, delta=delta, case_sensitive=case_sensitive)
    + + +
    +[docs] + @openeo_process + def normalized_difference(self, y) -> ProcessBuilder: + """ + Normalized difference + + :param self: The value for the first band. + :param y: The value for the second band. + + :return: The computed normalized difference. + """ + return normalized_difference(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def not_(self) -> ProcessBuilder: + """ + Inverting a boolean + + :param self: Boolean value to invert. + + :return: Inverted boolean value. + """ + return not_(x=self)
    + + +
    +[docs] + @openeo_process + def or_(self, y) -> ProcessBuilder: + """ + Logical OR + + :param self: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical OR. + """ + return or_(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def order(self, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Create a permutation + + :param self: An array to compute the order for. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The computed permutation. + """ + return order(data=self, asc=asc, nodata=nodata)
    + + +
    +[docs] + @openeo_process + def pi(self) -> ProcessBuilder: + """ + Pi (π) + + :return: The numerical value of Pi. + """ + return pi()
    + + +
    +[docs] + @openeo_process + def power(self, p) -> ProcessBuilder: + """ + Exponentiation + + :param self: The numerical base. + :param p: The numerical exponent. + + :return: The computed value for `base` raised to the power of `p`. + """ + return power(base=self, p=p)
    + + +
    +[docs] + @openeo_process + def predict_curve(self, parameters, function, dimension, labels=UNSET) -> ProcessBuilder: + """ + Predict values + + :param self: A data cube to predict values for. + :param parameters: A data cube with optimal values from a result of e.g. ``fit_curve()``. + :param function: The model function. It must take the parameters to fit as array through the first + argument and the independent variable `x` as the second argument. It is recommended to store the model + function as a user-defined process on the back-end. + :param dimension: The name of the dimension for predictions. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param labels: The labels to predict values for. If no labels are given, predicts values only for no- + data (`null`) values in the data cube. + + :return: A data cube with the predicted values. + """ + return predict_curve( + data=self, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension, + labels=labels + )
    + + +
    +[docs] + @openeo_process + def predict_random_forest(self, model) -> ProcessBuilder: + """ + Predict values from a Random Forest model + + :param self: An array of numbers. + :param model: A model object that can be trained with the processes ``fit_regr_random_forest()`` + (regression) and ``fit_class_random_forest()`` (classification). + + :return: The predicted value. Returns `null` if any of the given values in the array is a no-data + value. + """ + return predict_random_forest(data=self, model=model)
    + + +
    +[docs] + @openeo_process + def product(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the product by multiplying numbers + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed product of the sequence of numbers. + """ + return product(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def quantiles(self, probabilities=UNSET, q=UNSET, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Quantiles + + :param self: An array of numbers. + :param probabilities: A list of probabilities to calculate quantiles for. The probabilities must be + between 0 and 1 (inclusive). + :param q: Number of intervals to calculate quantiles for. Calculates q-quantiles with equal-sized + intervals. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. + Setting this flag to `false` considers no-data values so that an array with `null` values is returned + if any element is such a value. + + :return: An array with the computed quantiles. The list has either * as many elements as the given + list of `probabilities` had or * *`q`-1* elements. If 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. + """ + return quantiles(data=self, probabilities=probabilities, q=q, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def rearrange(self, order) -> ProcessBuilder: + """ + Rearrange an array based on a permutation + + :param self: The array to rearrange. + :param order: The permutation used for rearranging. + + :return: The rearranged array. + """ + return rearrange(data=self, order=order)
    + + +
    +[docs] + @openeo_process + def reduce_dimension(self, reducer, dimension, context=UNSET) -> ProcessBuilder: + """ + Reduce dimensions + + :param self: A data cube. + :param reducer: A reducer to apply on 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. + :param dimension: The name of the dimension over which to reduce. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return reduce_dimension( + data=self, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + )
    + + +
    +[docs] + @openeo_process + def reduce_spatial(self, reducer, context=UNSET) -> ProcessBuilder: + """ + Reduce spatial dimensions 'x' and 'y' + + :param self: A data cube. + :param reducer: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return reduce_spatial(data=self, reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), context=context)
    + + +
    +[docs] + @openeo_process + def rename_dimension(self, source, target) -> ProcessBuilder: + """ + Rename a dimension + + :param self: The data cube. + :param source: The current name of the dimension. Fails with a `DimensionNotAvailable` exception if the + specified dimension does not exist. + :param target: A new Name for the dimension. Fails with a `DimensionExists` exception if a dimension + with the specified name exists. + + :return: A data cube with the same dimensions, but the name of one of the dimensions changes. The old + name can not be referred to any longer. The dimension properties (name, type, labels, reference system + and resolution) remain unchanged. + """ + return rename_dimension(data=self, source=source, target=target)
    + + +
    +[docs] + @openeo_process + def rename_labels(self, dimension, target, source=UNSET) -> ProcessBuilder: + """ + Rename dimension labels + + :param self: The data cube. + :param dimension: The name of the dimension to rename the labels for. + :param target: The new names for the labels. If a target dimension label already exists in the data + cube, a `LabelExists` exception is thrown. + :param source: The original names of the labels to be renamed to corresponding array elements in the + parameter `target`. It is allowed to only specify a subset of labels to rename, as long as the `target` + and `source` parameter have the same length. The order of the labels doesn't need to match the order of + the dimension labels in the data cube. By default, the array is empty so that the dimension labels in + the data cube are expected to be enumerated. If the dimension labels are not enumerated and the given + array is empty, the `LabelsNotEnumerated` exception is thrown. If one of the source dimension labels + doesn't exist, the `LabelNotAvailable` exception is thrown. + + :return: The data cube with the same dimensions. The dimension properties (name, type, labels, + reference system and resolution) remain unchanged, except that for the given dimension the labels + change. The old labels can not be referred to any longer. The number of labels remains the same. + """ + return rename_labels(data=self, dimension=dimension, target=target, source=source)
    + + +
    +[docs] + @openeo_process + def resample_cube_spatial(self, target, method=UNSET) -> ProcessBuilder: + """ + Resample the spatial dimensions to match a target data cube + + :param self: A data cube. + :param target: A data cube that describes the spatial target resolution. + :param method: 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): * `average`: average + (mean) resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling + * `cubic`: cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc + resampling * `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median + resampling, selects the median value of all valid pixels * `min`: minimum resampling, selects the + minimum value from all valid pixels * `mode`: mode resampling, selects the value which appears most + often of all the sampled points * `near`: nearest neighbour resampling (default) * `q1`: first quartile + resampling, selects the first quartile value of all valid pixels * `q3`: third quartile resampling, + selects the third quartile value of all valid pixels * `rms` root mean square (quadratic mean) of all + valid pixels * `sum`: compute the weighted sum of all valid pixels Valid pixels are determined based + on the function ``is_valid()``. + + :return: 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 spatial + dimensions. + """ + return resample_cube_spatial(data=self, target=target, method=method)
    + + +
    +[docs] + @openeo_process + def resample_cube_temporal(self, target, dimension=UNSET, valid_within=UNSET) -> ProcessBuilder: + """ + Resample temporal dimensions to match a target data cube + + :param self: A data cube with one or more temporal dimensions. + :param target: A data cube that describes the temporal target resolution. + :param dimension: 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. The following exceptions may occur: * A + dimension is given, but it does not exist in any of the data cubes: `DimensionNotAvailable` * A + dimension is given, but one of them is not temporal: `DimensionMismatch` * No specific dimension name + is given and there are no temporal dimensions with the same name in the data: `DimensionMismatch` + :param valid_within: 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`). + + :return: 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. + """ + return resample_cube_temporal(data=self, target=target, dimension=dimension, valid_within=valid_within)
    + + +
    +[docs] + @openeo_process + def resample_spatial(self, resolution=UNSET, projection=UNSET, method=UNSET, align=UNSET) -> ProcessBuilder: + """ + Resample and warp the spatial dimensions + + :param self: A raster data cube. + :param resolution: 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`). + :param projection: Warps the data cube to the target projection, specified as as [EPSG + code](http://www.epsg-registry.org/), [WKT2 (ISO 19162) + string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html), [PROJ definition + (deprecated)](https://proj.org/usage/quickstart.html). By default (`null`), the projection is not + changed. + :param method: 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): * `average`: average + (mean) resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling + * `cubic`: cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc + resampling * `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median + resampling, selects the median value of all valid pixels * `min`: minimum resampling, selects the + minimum value from all valid pixels * `mode`: mode resampling, selects the value which appears most + often of all the sampled points * `near`: nearest neighbour resampling (default) * `q1`: first quartile + resampling, selects the first quartile value of all valid pixels * `q3`: third quartile resampling, + selects the third quartile value of all valid pixels * `rms` root mean square (quadratic mean) of all + valid pixels * `sum`: compute the weighted sum of all valid pixels Valid pixels are determined based + on the function ``is_valid()``. + :param align: Specifies to which corner of the spatial extent the new resampled data is aligned to. + + :return: A raster data cube with values warped onto the new projection. It has the same dimensions and + the same dimension properties (name, type, labels, reference system and resolution) for all non-spatial + or vertical spatial dimensions. For the horizontal spatial dimensions the name and type remain + unchanged, but reference system, labels and resolution may change depending on the given parameters. + """ + return resample_spatial(data=self, resolution=resolution, projection=projection, method=method, align=align)
    + + +
    +[docs] + @openeo_process + def round(self, p=UNSET) -> ProcessBuilder: + """ + Round to a specified precision + + :param self: A number to round. + :param p: A positive number specifies the number of digits after the decimal point to round to. A + negative number means rounding to a power of ten, so for example *-2* rounds to the nearest hundred. + Defaults to *0*. + + :return: The rounded number. + """ + return round(x=self, p=p)
    + + +
    +[docs] + @openeo_process + def run_udf(self, udf, runtime, version=UNSET, context=UNSET) -> ProcessBuilder: + """ + Run a UDF + + :param self: The data to be passed to the UDF. + :param udf: Either source code, an absolute URL or a path to a UDF script. + :param runtime: A UDF runtime identifier available at the back-end. + :param version: An UDF runtime version. If set to `null`, the default runtime version specified for + each runtime is used. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can be of any data type and is exactly what + the UDF code returns. + """ + return run_udf(data=self, udf=udf, runtime=runtime, version=version, context=context)
    + + +
    +[docs] + @openeo_process + def run_udf_externally(self, url, context=UNSET) -> ProcessBuilder: + """ + Run an externally hosted UDF container + + :param self: The data to be passed to the UDF. + :param url: Absolute URL to a remote UDF service. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can in principle be of any data type, but it + depends on what is returned by the UDF code. Please see the implemented UDF interface for details. + """ + return run_udf_externally(data=self, url=url, context=context)
    + + +
    +[docs] + @openeo_process + def sar_backscatter(self, coefficient=UNSET, elevation_model=UNSET, mask=UNSET, contributing_area=UNSET, local_incidence_angle=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + Computes backscatter from SAR input + + :param self: The source data cube containing SAR input. + :param coefficient: Select the radiometric correction coefficient. The following options are available: + * `beta0`: radar brightness * `sigma0-ellipsoid`: ground area computed with ellipsoid earth model * + `sigma0-terrain`: ground area computed with terrain earth model * `gamma0-ellipsoid`: ground area + computed with ellipsoid earth model in sensor line of sight * `gamma0-terrain`: ground area computed + with terrain earth model in sensor line of sight (default) * `null`: non-normalized backscatter + :param elevation_model: 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. + :param mask: 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). + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param local_incidence_angle: If set to `true`, a DEM-based local incidence angle band named + `local_incidence_angle` is added. The values are given in degrees. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options + will reduce portability. + + :return: Backscatter values corresponding to the chosen parametrization. The values are given in linear + scale. + """ + return sar_backscatter( + data=self, + coefficient=coefficient, + elevation_model=elevation_model, + mask=mask, + contributing_area=contributing_area, + local_incidence_angle=local_incidence_angle, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + )
    + + +
    +[docs] + @openeo_process + def save_ml_model(self, options=UNSET) -> ProcessBuilder: + """ + Save a ML model + + :param self: The data to store as a machine learning model. + :param options: Additional parameters to create the file(s). + + :return: Returns `false` if the process failed to store the model, `true` otherwise. + """ + return save_ml_model(data=self, options=options)
    + + +
    +[docs] + @openeo_process + def save_result(self, format, options=UNSET) -> ProcessBuilder: + """ + Save processed data + + :param self: The data to deliver in the given file format. + :param format: The file format to use. It must be one of the values that the server reports as + supported output file formats, which usually correspond to the short GDAL/OGR codes. If the format is + not suitable for storing the underlying data structure, a `FormatUnsuitable` exception will be thrown. + This parameter is *case insensitive*. + :param options: The file format parameters to be used to create the file(s). Must correspond to the + parameters that the server reports as supported parameters for the chosen `format`. The parameter names + and valid values usually correspond to the GDAL/OGR format options. + + :return: Returns `false` if the process failed to make the data available, `true` otherwise. + """ + return save_result(data=self, format=format, options=options)
    + + +
    +[docs] + @openeo_process + def sd(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Standard deviation + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed sample standard deviation. + """ + return sd(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def sgn(self) -> ProcessBuilder: + """ + Signum + + :param self: A number. + + :return: The computed signum value of `x`. + """ + return sgn(x=self)
    + + +
    +[docs] + @openeo_process + def sin(self) -> ProcessBuilder: + """ + Sine + + :param self: An angle in radians. + + :return: The computed sine of `x`. + """ + return sin(x=self)
    + + +
    +[docs] + @openeo_process + def sinh(self) -> ProcessBuilder: + """ + Hyperbolic sine + + :param self: An angle in radians. + + :return: The computed hyperbolic sine of `x`. + """ + return sinh(x=self)
    + + +
    +[docs] + @openeo_process + def sort(self, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Sort data + + :param self: An array with data to sort. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The sorted array. + """ + return sort(data=self, asc=asc, nodata=nodata)
    + + +
    +[docs] + @openeo_process + def sqrt(self) -> ProcessBuilder: + """ + Square root + + :param self: A number. + + :return: The computed square root. + """ + return sqrt(x=self)
    + + +
    +[docs] + @openeo_process + def subtract(self, y) -> ProcessBuilder: + """ + Subtraction of two numbers + + :param self: The minuend. + :param y: The subtrahend. + + :return: The computed result. + """ + return subtract(x=self, y=y)
    + + +
    +[docs] + @openeo_process + def sum(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the sum by adding up numbers + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed sum of the sequence of numbers. + """ + return sum(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def tan(self) -> ProcessBuilder: + """ + Tangent + + :param self: An angle in radians. + + :return: The computed tangent of `x`. + """ + return tan(x=self)
    + + +
    +[docs] + @openeo_process + def tanh(self) -> ProcessBuilder: + """ + Hyperbolic tangent + + :param self: An angle in radians. + + :return: The computed hyperbolic tangent of `x`. + """ + return tanh(x=self)
    + + +
    +[docs] + @openeo_process + def text_begins(self, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text begins with another text + + :param self: Text in which to find something at the beginning. + :param pattern: Text to find at the beginning of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` begins with `pattern`, false` otherwise. + """ + return text_begins(data=self, pattern=pattern, case_sensitive=case_sensitive)
    + + +
    +[docs] + @openeo_process + def text_concat(self, separator=UNSET) -> ProcessBuilder: + """ + Concatenate elements to a single text + + :param self: A set of elements. Numbers, boolean values and null values get converted to their (lower + case) string representation. For example: `1` (integer), `-1.5` (number), `true` / `false` (boolean + values) + :param separator: A separator to put between each of the individual texts. Defaults to an empty string. + + :return: A string containing a string representation of all the array elements in the same order, with + the separator between each element. + """ + return text_concat(data=self, separator=separator)
    + + +
    +[docs] + @openeo_process + def text_contains(self, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text contains another text + + :param self: Text in which to find something in. + :param pattern: Text to find in `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` contains the `pattern`, false` otherwise. + """ + return text_contains(data=self, pattern=pattern, case_sensitive=case_sensitive)
    + + +
    +[docs] + @openeo_process + def text_ends(self, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text ends with another text + + :param self: Text in which to find something at the end. + :param pattern: Text to find at the end of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` ends with `pattern`, false` otherwise. + """ + return text_ends(data=self, pattern=pattern, case_sensitive=case_sensitive)
    + + +
    +[docs] + @openeo_process + def trim_cube(self) -> ProcessBuilder: + """ + Remove dimension labels with no-data values + + :param self: A raster data cube to trim. + + :return: A trimmed raster data cube with the same dimensions. The dimension properties name, type, + reference system and resolution remain unchanged. The number of dimension labels may decrease. + """ + return trim_cube(data=self)
    + + +
    +[docs] + @openeo_process + def unflatten_dimension(self, dimension, target_dimensions, label_separator=UNSET) -> ProcessBuilder: + """ + Split a single dimensions into multiple dimensions + + :param self: A data cube that is consistently structured so that operation can execute flawlessly (e.g. + the dimension labels need to contain the `label_separator` exactly 1 time for two target dimensions, 2 + times for three target dimensions etc.). + :param dimension: The name of the dimension to split. + :param target_dimensions: The names of the new target dimensions. New dimensions will be created with + the given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` + exception if any of the dimensions exists. The order of the array defines the order in which the + dimensions and dimension labels are added to the data cube (see the example in the process + description). + :param label_separator: The string that will be used as a separator to split the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system + and resolution) for all other dimensions remain unchanged. + """ + return unflatten_dimension(data=self, dimension=dimension, target_dimensions=target_dimensions, label_separator=label_separator)
    + + +
    +[docs] + @openeo_process + def variance(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Variance + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed sample variance. + """ + return variance(data=self, ignore_nodata=ignore_nodata)
    + + +
    +[docs] + @openeo_process + def vector_buffer(self, distance) -> ProcessBuilder: + """ + Buffer geometries by distance + + :param self: Geometries to apply the buffer on. Vector properties are preserved for vector data cubes + and all GeoJSON Features. To 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`). + :param distance: The distance of the buffer in the unit of the spatial reference system. A positive + distance expands the geometries and results in outward buffering (dilation) while a negative distance + shrinks the geometries and results in inward buffering (erosion). + + :return: Returns a vector data cube with the computed new geometries. + """ + return vector_buffer(geometries=self, distance=distance)
    + + +
    +[docs] + @openeo_process + def vector_to_random_points(self, geometry_count=UNSET, total_count=UNSET, group=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Sample random points from geometries + + :param self: Input geometries for sample extraction. To 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`). + :param geometry_count: The maximum number of points to compute per geometry. Points in the input + geometries can be selected only once by the sampling. + :param total_count: The maximum number of points to compute overall. Throws a `CountMismatch` + exception if the specified value is less than the provided number of geometries. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a + `MultiPoint` per geometry given which keeps the original identifier if present. * Otherwise, each + sampled point is generated as a distinct `Point` geometry without identifier. + :param seed: A randomization seed to use for random sampling. If not given or `null`, no seed is used + and results may differ on subsequent use. + + :return: Returns a vector data cube with the sampled points. + """ + return vector_to_random_points(data=self, geometry_count=geometry_count, total_count=total_count, group=group, seed=seed)
    + + +
    +[docs] + @openeo_process + def vector_to_regular_points(self, distance, group=UNSET) -> ProcessBuilder: + """ + Sample regular points from geometries + + :param self: Input geometries for sample extraction. To 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`). + :param distance: Defines the minimum distance in the unit of the reference system that is required + between two samples generated *inside* a single geometry. - For **polygons**, the distance defines the + cell sizes of a regular grid that starts at the upper-left bound of each polygon. The centroid of each + cell is then a sample point. If the centroid is not enclosed in the polygon, no point is sampled. If no + point can be sampled for the geometry at all, the first coordinate of the geometry is returned as + point. - For **lines** (line strings), the sampling starts with a point at the first coordinate of the + line and then walks along the line and samples a new point each time the distance to the previous point + has been reached again. - For **points**, the point is returned as given. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a + `MultiPoint` per geometry given which keeps the original identifier if present. * Otherwise, each + sampled point is generated as a distinct `Point` geometry without identifier. + + :return: Returns a vector data cube with the sampled points. + """ + return vector_to_regular_points(data=self, distance=distance, group=group)
    + + +
    +[docs] + @openeo_process + def xor(self, y) -> ProcessBuilder: + """ + Logical XOR (exclusive or) + + :param self: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical XOR. + """ + return xor(x=self, y=y)
    +
    + + + +# Public shortcut +process = ProcessBuilder.process +# Private shortcut that has lower chance to collide with a process argument named `process` +_process = ProcessBuilder.process + + +
    +[docs] +@openeo_process +def absolute(x) -> ProcessBuilder: + """ + Absolute value + + :param x: A number. + + :return: The computed absolute value. + """ + return _process('absolute', x=x)
    + + + +
    +[docs] +@openeo_process +def add(x, y) -> ProcessBuilder: + """ + Addition of two numbers + + :param x: The first summand. + :param y: The second summand. + + :return: The computed sum of the two numbers. + """ + return _process('add', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def add_dimension(data, name, label, type=UNSET) -> ProcessBuilder: + """ + Add a new dimension + + :param data: A data cube to add the dimension to. + :param name: Name for the dimension. + :param label: A dimension label. + :param type: The type of dimension, defaults to `other`. + + :return: The data cube with a newly added dimension. The new dimension has exactly one dimension label. All + other dimensions remain unchanged. + """ + return _process('add_dimension', data=data, name=name, label=label, type=type)
    + + + +
    +[docs] +@openeo_process +def aggregate_spatial(data, geometries, reducer, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for geometries + + :param data: A raster data cube. The 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. 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. + :param geometries: Geometries as GeoJSON on which the aggregation will be based. Vector properties are + preserved for vector data cubes and all GeoJSON Features. One 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. - 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). - For **points**, the process considers + the closest pixel center. - For **lines** (line strings), the process considers all the pixels whose + centers are closest to at least one point on the line. Thus, pixels may be part of multiple geometries and + be part of multiple aggregations. To 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`). + :param reducer: A reducer to be applied on all values of each geometry. 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. + :param target_dimension: The name of a new dimensions that is used to store the results. A new dimension + will be created with the given name and type `other` (see ``add_dimension()``). Defaults to the dimension + name `result`. Fails with a `TargetDimensionExists` exception if a dimension with the specified name + exists. + :param context: Additional data to be passed to the reducer. + + :return: A vector data cube with the computed results and restricted to the bounds of the geometries. The + computed value is used for the dimension with the name that was specified in the parameter + `target_dimension`. The 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`. + """ + return _process('aggregate_spatial', + data=data, + geometries=geometries, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + target_dimension=target_dimension, + context=context + )
    + + + +
    +[docs] +@openeo_process +def aggregate_spatial_window(data, reducer, size, boundary=UNSET, align=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for rectangular windows + + :param data: 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. + :param reducer: 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. + :param size: Window size in pixels along the horizontal spatial dimensions. The first value corresponds to + the `x` axis, the second value corresponds to the `y` axis. + :param boundary: 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: - `pad` (default): pad the data cube with + the no-data value `null` to fit the required window size. - `trim`: trim the data cube to fit the required + window size. Set the parameter `align` to specifies to which corner the data is aligned to. + :param align: 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. + :param context: Additional data to be passed to the reducer. + + :return: A data cube with the newly computed values and the same dimensions. The 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. The 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. + """ + return _process('aggregate_spatial_window', + data=data, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + size=size, + boundary=boundary, + align=align, + context=context + )
    + + + +
    +[docs] +@openeo_process +def aggregate_temporal(data, intervals, reducer, labels=UNSET, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations + + :param data: A data cube. + :param intervals: Left-closed temporal intervals, which are allowed to overlap. Each temporal interval in + the array has exactly two elements: 1. The first element is the start of the temporal interval. The + specified instance in time is **included** in the interval. 2. The second element is the end of the + temporal interval. The specified instance in time is **excluded** from the interval. The 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. + :param reducer: 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. + :param labels: Distinct labels for the intervals, which can contain dates and/or times. Is only required to + be specified if the values for the start of the temporal intervals are not distinct and thus the default + labels would not be unique. The number of labels and the number of groups need to be equal. + :param dimension: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return _process('aggregate_temporal', + data=data, + intervals=intervals, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + labels=labels, + dimension=dimension, + context=context + )
    + + + +
    +[docs] +@openeo_process +def aggregate_temporal_period(data, period, reducer, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations based on calendar hierarchies + + :param data: The source data cube. + :param period: The time intervals to aggregate. The following pre-defined values are available: * `hour`: + Hour of the day * `day`: Day of the year * `week`: Week of the year * `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. * `month`: Month + of the year * `season`: Three month periods of the calendar seasons (December - February, March - May, June + - August, September - November). * `tropical-season`: Six month periods of the tropical seasons (November - + April, May - October). * `year`: Proleptic years * `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. * `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. + :param reducer: 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. + :param dimension: 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 source 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. + :param context: Additional data to be passed to the reducer. + + :return: 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): * `hour`: `YYYY-MM-DD-00` - `YYYY-MM- + DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - `YYYY-52` * `dekad`: `YYYY-00` - `YYYY-36` * + `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` (December - February), `YYYY-mam` (March - May), + `YYYY-jja` (June - August), `YYYY-son` (September - November). * `tropical-season`: `YYYY-ndjfma` (November + - April), `YYYY-mjjaso` (May - October). * `year`: `YYYY` * `decade`: `YYY0` * `decade-ad`: `YYY1` The + dimension labels in the new data cube are complete for the whole extent of the source data cube. For + example, if `period` is set to `day` and the source data cube has two dimension labels at the beginning of + the year (`2020-01-01`) and the end of a year (`2020-12-31`), the process returns a data cube with 365 + dimension labels (`2020-001`, `2020-002`, ..., `2020-365`). In contrast, if `period` is set to `day` and + the source data cube has just one dimension label `2020-01-05`, the process returns a data cube with just a + single dimension label (`2020-005`). + """ + return _process('aggregate_temporal_period', + data=data, + period=period, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + )
    + + + +
    +[docs] +@openeo_process +def all(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Are all of the values true? + + :param data: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return _process('all', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def and_(x, y) -> ProcessBuilder: + """ + Logical AND + + :param x: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical AND. + """ + return _process('and', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def anomaly(data, normals, period) -> ProcessBuilder: + """ + Compute anomalies + + :param data: A data cube with exactly one temporal dimension and the following dimension labels for the + given period (`YYYY` = four-digit year, `MM` = two-digit month, `DD` two-digit day of month): * `hour`: + `YYYY-MM-DD-00` - `YYYY-MM-DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - `YYYY-52` * + `dekad`: `YYYY-00` - `YYYY-36` * `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` (December - + February), `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - November). * + `tropical-season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October). * `year`: `YYYY` * + `decade`: `YYY0` * `decade-ad`: `YYY1` * `single-period` / `climatology-period`: Any + ``aggregate_temporal_period()`` can compute such a data cube. + :param normals: A data cube with normals, e.g. daily, monthly or yearly values computed from a process such + as ``climatological_normal()``. Must contain exactly one temporal dimension with the following dimension + labels for the given period: * `hour`: `00` - `23` * `day`: `001` - `365` * `week`: `01` - `52` * `dekad`: + `00` - `36` * `month`: `01` - `12` * `season`: `djf` (December - February), `mam` (March - May), `jja` + (June - August), `son` (September - November) * `tropical-season`: `ndjfma` (November - April), `mjjaso` + (May - October) * `year`: Four-digit year numbers * `decade`: Four-digit year numbers, the last digit being + a `0` * `decade-ad`: Four-digit year numbers, the last digit being a `1` * `single-period` / `climatology- + period`: A single dimension label with any name is expected. + :param period: Specifies the time intervals available in the normals data cube. The following options are + available: * `hour`: Hour of the day * `day`: Day of the year * `week`: Week of the year * `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. * `month`: Month of the year * `season`: Three month periods of the calendar seasons (December - + February, March - May, June - August, September - November). * `tropical-season`: Six month periods of the + tropical seasons (November - April, May - October). * `year`: Proleptic years * `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. * `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. * `single-period` / `climatology- + period`: A single period of arbitrary length + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged. + """ + return _process('anomaly', data=data, normals=normals, period=period)
    + + + +
    +[docs] +@openeo_process +def any(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Is at least one value true? + + :param data: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return _process('any', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def apply(data, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each pixel + + :param data: A data cube. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return _process('apply', data=data, process=build_child_callback(process, parent_parameters=['x', 'context']), context=context)
    + + + +
    +[docs] +@openeo_process +def apply_dimension(data, process, dimension, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels along a dimension + + :param data: A data cube. + :param process: 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. + :param dimension: The name of the source dimension to apply the process on. Fails with a + `DimensionNotAvailable` exception if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or `null` (the default) to use the source + dimension specified in the parameter `dimension`. By 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. + :param context: Additional data to be passed to the process. + + :return: 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 dimensions can change: 1. + The source dimension is the target dimension: - The (number of) dimensions remain unchanged as the + source dimension is the target dimension. - The source dimension properties name and type remain + unchanged. - 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. 2. The source dimension is + not the target dimension and the latter exists: - The number of dimensions decreases by one as the + source dimension is dropped. - The target dimension properties name and type remain unchanged. All other + dimension properties change as defined in the list below. 3. The source dimension is not the target + dimension and the latter does not exist: - The number of dimensions remain unchanged, but the source + dimension is replaced with the target dimension. - The target dimension has the specified name and the + type other. All other dimension properties are set as defined in the list below. Unless otherwise stated + above, for the given (target) dimension the following applies: - the number of dimension labels is equal + to the number of values computed by the process, - the dimension labels are incrementing integers starting + from zero, - the resolution changes, and - the reference system is undefined. + """ + return _process('apply_dimension', + data=data, + process=build_child_callback(process, parent_parameters=['data', 'context']), + dimension=dimension, + target_dimension=target_dimension, + context=context + )
    + + + +
    +[docs] +@openeo_process +def apply_kernel(data, kernel, factor=UNSET, border=UNSET, replace_invalid=UNSET) -> ProcessBuilder: + """ + Apply a spatial convolution with a kernel + + :param data: A data cube. + :param kernel: 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. + :param factor: A factor that is multiplied to each value after the kernel has been applied. This is + basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often required + for some kernel-based algorithms such as the Gaussian blur. + :param border: Determines how the data is extended when the kernel overlaps with the borders. Defaults to + fill the border with zeroes. The following options are available: * *numeric value* - fill with a user- + defined constant number `n`: `nnnnnn|abcdefgh|nnnnnn` (default, with `n` = 0) * `replicate` - repeat the + value from the pixel at the border: `aaaaaa|abcdefgh|hhhhhh` * `reflect` - mirror/reflect from the border: + `fedcba|abcdefgh|hgfedc` * `reflect_pixel` - mirror/reflect from the center of the pixel at the border: + `gfedcb|abcdefgh|gfedcb` * `wrap` - repeat/wrap the image: `cdefgh|abcdefgh|abcdef` + :param replace_invalid: This parameter specifies the value to replace non-numerical or infinite numerical + values with. By default, those values are replaced with zeroes. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return _process('apply_kernel', data=data, kernel=kernel, factor=factor, border=border, replace_invalid=replace_invalid)
    + + + +
    +[docs] +@openeo_process +def apply_neighborhood(data, process, size, overlap=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels in a n-dimensional neighborhood + + :param data: A data cube. + :param process: Process to be applied on all neighborhoods. + :param size: Neighborhood sizes along each dimension. This 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. + :param overlap: Overlap of neighborhoods along each dimension to avoid border effects. By default no + overlap is provided. For 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. Be aware that + large overlaps increase the need for computational resources and modifying overlapping data in subsequent + operations have no effect. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return _process('apply_neighborhood', + data=data, + process=build_child_callback(process, parent_parameters=['data', 'context']), + size=size, + overlap=overlap, + context=context + )
    + + + +
    +[docs] +@openeo_process +def arccos(x) -> ProcessBuilder: + """ + Inverse cosine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arccos', x=x)
    + + + +
    +[docs] +@openeo_process +def arcosh(x) -> ProcessBuilder: + """ + Inverse hyperbolic cosine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arcosh', x=x)
    + + + +
    +[docs] +@openeo_process +def arcsin(x) -> ProcessBuilder: + """ + Inverse sine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arcsin', x=x)
    + + + +
    +[docs] +@openeo_process +def arctan(x) -> ProcessBuilder: + """ + Inverse tangent + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arctan', x=x)
    + + + +
    +[docs] +@openeo_process +def arctan2(y, x) -> ProcessBuilder: + """ + Inverse tangent of two numbers + + :param y: A number to be used as the dividend. + :param x: A number to be used as the divisor. + + :return: The computed angle in radians. + """ + return _process('arctan2', y=y, x=x)
    + + + +
    +[docs] +@openeo_process +def ard_normalized_radar_backscatter(data, elevation_model=UNSET, contributing_area=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant SAR NRB generation + + :param data: The source data cube containing SAR input. + :param elevation_model: 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. + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options will + reduce portability. + + :return: Backscatter values expressed as gamma0 in linear scale. In 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: - `mask`: A data mask that indicates + which values are valid (1), invalid (0) or contain no-data (null). - `local_incidence_angle`: A band with + DEM-based local incidence angles in degrees. The data returned is CARD4L compliant with corresponding + metadata. + """ + return _process('ard_normalized_radar_backscatter', + data=data, + elevation_model=elevation_model, + contributing_area=contributing_area, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + )
    + + + +
    +[docs] +@openeo_process +def ard_surface_reflectance(data, atmospheric_correction_method, cloud_detection_method, elevation_model=UNSET, atmospheric_correction_options=UNSET, cloud_detection_options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant Surface Reflectance generation + + :param data: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances. There must be a single dimension of type `bands` available. + :param atmospheric_correction_method: The atmospheric correction method to use. + :param cloud_detection_method: The cloud detection method to use. Each method supports detecting different + atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water vapour in + optical imagery. + :param elevation_model: 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. + :param atmospheric_correction_options: Proprietary options for the atmospheric correction method. + Specifying proprietary options will reduce portability. + :param cloud_detection_options: Proprietary options for the cloud detection method. Specifying proprietary + options will reduce portability. + + :return: 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: 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. Depending on the methods + used, several additional bands will be added to the data cube: - `date` (optional): Specifies per-pixel + acquisition timestamps. - `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. - `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. - `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. - `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. + - `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. - `incidence-angle` (optional): Specifies per-pixel + incidence angles in degrees. - `azimuth` (optional): Specifies per-pixel azimuth angles in degrees. - `sun- + azimuth:` (optional): Specifies per-pixel sun azimuth angles in degrees. - `sun-elevation` (optional): + Specifies per-pixel sun elevation angles in degrees. - `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. - + `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. - `terrain-illumination` + (optional): Contains coefficients used for terrain illumination correction are provided for each pixel. + The data returned is CARD4L compliant with corresponding metadata. + """ + return _process('ard_surface_reflectance', + data=data, + atmospheric_correction_method=atmospheric_correction_method, + cloud_detection_method=cloud_detection_method, + elevation_model=elevation_model, + atmospheric_correction_options=atmospheric_correction_options, + cloud_detection_options=cloud_detection_options + )
    + + + +
    +[docs] +@openeo_process +def array_append(data, value, label=UNSET) -> ProcessBuilder: + """ + Append a value to an array + + :param data: An array. + :param value: Value to append to the array. + :param label: If the given array is a labeled array, a new label for the new value should be given. If not + given or `null`, the array index as string is used as the label. If in any case the label exists, a + `LabelExists` exception is thrown. + + :return: The new array with the value being appended. + """ + return _process('array_append', data=data, value=value, label=label)
    + + + +
    +[docs] +@openeo_process +def array_apply(data, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each array element + + :param data: An array. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: An array with the newly computed values. The number of elements are the same as for the original + array. + """ + return _process('array_apply', + data=data, + process=build_child_callback(process, parent_parameters=['x', 'index', 'label', 'context']), + context=context + )
    + + + +
    +[docs] +@openeo_process +def array_concat(array1, array2) -> ProcessBuilder: + """ + Merge two arrays + + :param array1: The first array. + :param array2: The second array. + + :return: The merged array. + """ + return _process('array_concat', array1=array1, array2=array2)
    + + + +
    +[docs] +@openeo_process +def array_contains(data, value) -> ProcessBuilder: + """ + Check whether the array contains a given value + + :param data: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `false`. + + :return: `true` if the list contains the value, false` otherwise. + """ + return _process('array_contains', data=data, value=value)
    + + + +
    +[docs] +@openeo_process +def array_create(data=UNSET, repeat=UNSET) -> ProcessBuilder: + """ + Create an array + + :param data: A (native) array to fill the newly created array with. Defaults to an empty array. + :param repeat: 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`. + + :return: The newly created array. + """ + return _process('array_create', data=data, repeat=repeat)
    + + + +
    +[docs] +@openeo_process +def array_create_labeled(data, labels) -> ProcessBuilder: + """ + Create a labeled array + + :param data: An array of values to be used. + :param labels: An array of labels to be used. + + :return: The newly created labeled array. + """ + return _process('array_create_labeled', data=data, labels=labels)
    + + + +
    +[docs] +@openeo_process +def array_element(data, index=UNSET, label=UNSET, return_nodata=UNSET) -> ProcessBuilder: + """ + Get an element from an array + + :param data: An array. + :param index: The zero-based index of the element to retrieve. + :param label: 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. + :param return_nodata: By default this process throws an `ArrayElementNotAvailable` exception if the index + or label is invalid. If you want to return `null` instead, set this flag to `true`. + + :return: The value of the requested element. + """ + return _process('array_element', data=data, index=index, label=label, return_nodata=return_nodata)
    + + + +
    +[docs] +@openeo_process +def array_filter(data, condition, context=UNSET) -> ProcessBuilder: + """ + Filter an array based on a condition + + :param data: An array. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: An array filtered by the specified condition. The number of elements are less than or equal + compared to the original array. + """ + return _process('array_filter', + data=data, + condition=build_child_callback(condition, parent_parameters=['x', 'index', 'label', 'context']), + context=context + )
    + + + +
    +[docs] +@openeo_process +def array_find(data, value, reverse=UNSET) -> ProcessBuilder: + """ + Get the index for a value in an array + + :param data: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `null`. + :param reverse: By default, this process finds the index of the first match. To return the index of the + last match instead, set this flag to `true`. + + :return: The index of the first element with the specified value. If no element was found, `null` is + returned. + """ + return _process('array_find', data=data, value=value, reverse=reverse)
    + + + +
    +[docs] +@openeo_process +def array_find_label(data, label) -> ProcessBuilder: + """ + Get the index for a label in a labeled array + + :param data: List to find the label in. + :param label: Label to find in `data`. + + :return: The index of the element with the specified label assigned. If no such label was found, `null` is + returned. + """ + return _process('array_find_label', data=data, label=label)
    + + + +
    +[docs] +@openeo_process +def array_interpolate_linear(data) -> ProcessBuilder: + """ + One-dimensional linear interpolation for arrays + + :param data: An array of numbers and no-data values. If 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. + + :return: 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. + """ + return _process('array_interpolate_linear', data=data)
    + + + +
    +[docs] +@openeo_process +def array_labels(data) -> ProcessBuilder: + """ + Get the labels for an array + + :param data: An array. + + :return: The labels or indices as array. + """ + return _process('array_labels', data=data)
    + + + +
    +[docs] +@openeo_process +def array_modify(data, values, index, length=UNSET) -> ProcessBuilder: + """ + Change the content of an array (remove, insert, update) + + :param data: The array to modify. + :param values: The values to insert into the `data` array. + :param index: The index in the `data` array of the element to insert the value(s) before. If the index is + greater than the number of elements in the `data` array, the process throws an `ArrayElementNotAvailable` + exception. To insert after the last element, there are two options: 1. Use the simpler processes + ``array_append()`` to append a single value or ``array_concat()`` to append multiple values. 2. 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`. + :param length: The number of elements in the `data` array to remove (or replace) starting from the given + index. If the array contains fewer elements, the process simply removes all elements up to the end. + + :return: An array with values added, updated or removed. + """ + return _process('array_modify', data=data, values=values, index=index, length=length)
    + + + +
    +[docs] +@openeo_process +def arsinh(x) -> ProcessBuilder: + """ + Inverse hyperbolic sine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arsinh', x=x)
    + + + +
    +[docs] +@openeo_process +def artanh(x) -> ProcessBuilder: + """ + Inverse hyperbolic tangent + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('artanh', x=x)
    + + + +
    +[docs] +@openeo_process +def atmospheric_correction(data, method, elevation_model=UNSET, options=UNSET) -> ProcessBuilder: + """ + Apply atmospheric correction + + :param data: Data cube containing multi-spectral optical top of atmosphere reflectances to be corrected. + :param method: The atmospheric correction method to use. To get reproducible results, you have to set a + specific method. Set 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. + :param elevation_model: 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. + :param options: Proprietary options for the atmospheric correction method. Specifying proprietary options + will reduce portability. + + :return: Data cube containing bottom of atmosphere reflectances. + """ + return _process('atmospheric_correction', data=data, method=method, elevation_model=elevation_model, options=options)
    + + + +
    +[docs] +@openeo_process +def between(x, min, max, exclude_max=UNSET) -> ProcessBuilder: + """ + Between comparison + + :param x: The value to check. + :param min: Lower boundary (inclusive) to check against. + :param max: Upper boundary (inclusive) to check against. + :param exclude_max: Exclude the upper boundary `max` if set to `true`. Defaults to `false`. + + :return: `true` if `x` is between the specified bounds, otherwise `false`. + """ + return _process('between', x=x, min=min, max=max, exclude_max=exclude_max)
    + + + +
    +[docs] +@openeo_process +def ceil(x) -> ProcessBuilder: + """ + Round fractions up + + :param x: A number to round up. + + :return: The number rounded up. + """ + return _process('ceil', x=x)
    + + + +
    +[docs] +@openeo_process +def climatological_normal(data, period, climatology_period=UNSET) -> ProcessBuilder: + """ + Compute climatology normals + + :param data: A data cube with exactly one temporal dimension. The data cube must span at least the temporal + interval specified in the parameter `climatology-period`. Seasonal periods may span two consecutive years, + e.g. temporal winter that includes months December, January and February. If the required months before the + actual climate period are available, the season is taken into account. If not available, the first season + is not taken into account and the seasonal mean is based on one year less than the other seasonal normals. + The incomplete season at the end of the last year is never taken into account. + :param period: The time intervals to aggregate the average value for. The following pre-defined frequencies + are supported: * `day`: Day of the year * `month`: Month of the year * `climatology-period`: The period + specified in the `climatology-period`. * `season`: Three month periods of the calendar seasons (December - + February, March - May, June - August, September - November). * `tropical-season`: Six month periods of the + tropical seasons (November - April, May - October). + :param climatology_period: 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). + + :return: 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 temporal + dimension. The temporal dimension has the following dimension labels: * `day`: `001` - `365` * `month`: + `01` - `12` * `climatology-period`: `climatology-period` * `season`: `djf` (December - February), `mam` + (March - May), `jja` (June - August), `son` (September - November) * `tropical-season`: `ndjfma` (November + - April), `mjjaso` (May - October) + """ + return _process('climatological_normal', data=data, period=period, climatology_period=climatology_period)
    + + + +
    +[docs] +@openeo_process +def clip(x, min, max) -> ProcessBuilder: + """ + Clip a value between a minimum and a maximum + + :param x: A number. + :param min: Minimum value. If the value is lower than this value, the process will return the value of this + parameter. + :param max: Maximum value. If the value is greater than this value, the process will return the value of + this parameter. + + :return: The value clipped to the specified range. + """ + return _process('clip', x=x, min=min, max=max)
    + + + +
    +[docs] +@openeo_process +def cloud_detection(data, method, options=UNSET) -> ProcessBuilder: + """ + Create cloud masks + + :param data: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances on which to perform cloud detection. + :param method: The cloud detection method to use. To get reproducible results, you have to set a specific + method. Set 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. + :param options: Proprietary options for the cloud detection method. Specifying proprietary options will + reduce portability. + + :return: 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. + """ + return _process('cloud_detection', data=data, method=method, options=options)
    + + + +
    +[docs] +@openeo_process +def constant(x) -> ProcessBuilder: + """ + Define a constant value + + :param x: The value of the constant. + + :return: The value of the constant. + """ + return _process('constant', x=x)
    + + + +
    +[docs] +@openeo_process +def cos(x) -> ProcessBuilder: + """ + Cosine + + :param x: An angle in radians. + + :return: The computed cosine of `x`. + """ + return _process('cos', x=x)
    + + + +
    +[docs] +@openeo_process +def cosh(x) -> ProcessBuilder: + """ + Hyperbolic cosine + + :param x: An angle in radians. + + :return: The computed hyperbolic cosine of `x`. + """ + return _process('cosh', x=x)
    + + + +
    +[docs] +@openeo_process +def count(data, condition=UNSET, context=UNSET) -> ProcessBuilder: + """ + Count the number of elements + + :param data: An array with elements of any data type. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: The counted number of elements. + """ + return _process('count', data=data, condition=condition, context=context)
    + + + +
    +[docs] +@openeo_process +def create_raster_cube() -> ProcessBuilder: + """ + Create an empty raster data cube + + :return: An empty raster data cube with zero dimensions. + """ + return _process('create_raster_cube', )
    + + + +
    +[docs] +@openeo_process +def cummax(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative maxima + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative maxima. + """ + return _process('cummax', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def cummin(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative minima + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative minima. + """ + return _process('cummin', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def cumproduct(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative products + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative products. + """ + return _process('cumproduct', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def cumsum(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative sums + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative sums. + """ + return _process('cumsum', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def date_shift(date, value, unit) -> ProcessBuilder: + """ + Manipulates dates and times by addition or subtraction + + :param date: The date (and optionally time) to manipulate. If 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. + :param value: 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. + :param unit: The unit for the value given. The following pre-defined units are available: - millisecond: + Milliseconds - second: Seconds - leap seconds are ignored in computations. - minute: Minutes - hour: Hours + - day: Days - changes only the the day part of a date - week: Weeks (equivalent to 7 days) - month: Months + - year: Years Manipulations 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`. + + :return: The manipulated date. If a time component was given in the parameter `date`, the time component is + returned with the date. + """ + return _process('date_shift', date=date, value=value, unit=unit)
    + + + +
    +[docs] +@openeo_process +def dimension_labels(data, dimension) -> ProcessBuilder: + """ + Get the dimension labels + + :param data: The data cube. + :param dimension: The name of the dimension to get the labels for. + + :return: The labels as an array. + """ + return _process('dimension_labels', data=data, dimension=dimension)
    + + + +
    +[docs] +@openeo_process +def divide(x, y) -> ProcessBuilder: + """ + Division of two numbers + + :param x: The dividend. + :param y: The divisor. + + :return: The computed result. + """ + return _process('divide', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def drop_dimension(data, name) -> ProcessBuilder: + """ + Remove a dimension + + :param data: The data cube to drop a dimension from. + :param name: Name of the dimension to drop. + + :return: A data cube without the specified dimension. The number of dimensions decreases by one, but the + dimension properties (name, type, labels, reference system and resolution) for all other dimensions remain + unchanged. + """ + return _process('drop_dimension', data=data, name=name)
    + + + +
    +[docs] +@openeo_process +def e() -> ProcessBuilder: + """ + Euler's number (e) + + :return: The numerical value of Euler's number. + """ + return _process('e', )
    + + + +
    +[docs] +@openeo_process +def eq(x, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Equal to comparison + + :param x: First operand. + :param y: Second operand. + :param delta: 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. This option is basically + an alias for the following computation: `lte(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be disabled + by setting this parameter to `false`. + + :return: `true` if `x` is equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('eq', x=x, y=y, delta=delta, case_sensitive=case_sensitive)
    + + + +
    +[docs] +@openeo_process +def exp(p) -> ProcessBuilder: + """ + Exponentiation to the base e + + :param p: The numerical exponent. + + :return: The computed value for *e* raised to the power of `p`. + """ + return _process('exp', p=p)
    + + + +
    +[docs] +@openeo_process +def extrema(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum and maximum values + + :param data: An array of numbers. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. Setting + this flag to `false` considers no-data values so that an array with two `null` values is returned if any + value is such a value. + + :return: An array containing the minimum and maximum values for the specified numbers. The first element is + the minimum, the second element is the maximum. If the input array is empty both elements are set to + `null`. + """ + return _process('extrema', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def filter_bands(data, bands=UNSET, wavelengths=UNSET) -> ProcessBuilder: + """ + Filter the bands by names + + :param data: A data cube with bands. + :param bands: 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. The 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. + :param wavelengths: 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). The 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. + + :return: A data cube limited to a subset of its original bands. The dimensions and dimension properties + (name, type, labels, reference system and resolution) remain unchanged, except that the dimension of type + `bands` has less (or the same) dimension labels. + """ + return _process('filter_bands', data=data, bands=bands, wavelengths=wavelengths)
    + + + +
    +[docs] +@openeo_process +def filter_bbox(data, extent) -> ProcessBuilder: + """ + Spatial filter using a bounding box + + :param data: A data cube. + :param extent: A bounding box, which may include a vertical axis (see `base` and `height`). + + :return: A data cube restricted to the bounding box. The dimensions and dimension properties (name, type, + labels, reference system and resolution) remain unchanged, except that the spatial dimensions have less (or + the same) dimension labels. + """ + return _process('filter_bbox', data=data, extent=extent)
    + + + +
    +[docs] +@openeo_process +def filter_labels(data, condition, dimension, context=UNSET) -> ProcessBuilder: + """ + Filter dimension labels based on a condition + + :param data: A data cube. + :param condition: A condition that is evaluated against each dimension label in the specified dimension. A + dimension label and the corresponding data is preserved for the given dimension, if the condition returns + `true`. + :param dimension: The name of the dimension to filter on. Fails with a `DimensionNotAvailable` exception if + the specified dimension does not exist. + :param context: Additional data to be passed to the condition. + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged, except that the given dimension has less (or the same) dimension + labels. + """ + return _process('filter_labels', + data=data, + condition=build_child_callback(condition, parent_parameters=['value', 'context']), + dimension=dimension, + context=context + )
    + + + +
    +[docs] +@openeo_process +def filter_spatial(data, geometries) -> ProcessBuilder: + """ + Spatial filter using geometries + + :param data: A data cube. + :param geometries: One or more geometries used for filtering, specified as GeoJSON. + + :return: A data cube restricted to the specified geometries. The dimensions and dimension properties (name, + type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions have + less (or the same) dimension labels. + """ + return _process('filter_spatial', data=data, geometries=geometries)
    + + + +
    +[docs] +@openeo_process +def filter_temporal(data, extent, dimension=UNSET) -> ProcessBuilder: + """ + Temporal filter based on temporal intervals + + :param data: A data cube. + :param extent: Left-closed temporal interval, i.e. an array with exactly two elements: 1. The first + element is the start of the temporal interval. The specified instance in time is **included** in the + interval. 2. The second element is the end of the temporal interval. The specified instance in time is + **excluded** from the interval. The 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. + :param dimension: 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. + + :return: 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. + """ + return _process('filter_temporal', data=data, extent=extent, dimension=dimension)
    + + + +
    +[docs] +@openeo_process +def first(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + First element + + :param data: An array with elements of any data type. + :param ignore_nodata: 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 returned if the first value is such a + value. + + :return: The first element of the input array. + """ + return _process('first', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def fit_class_random_forest(predictors, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest classification model + + :param predictors: The predictors for the classification model as a vector data cube. Aggregated to the + features (vectors) of the target input variable. + :param target: The training sites for the classification model as a vector data cube. This is associated + with the target variable for the Random Forest model. The geometry has to associated with a value to + predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options are + available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables are + considered for each split. - `onethird`: A third of the number of variables are considered for each split. + - `sqrt`: The square root of the number of variables are considered for each split. This is often the + default for classification. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, no + seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with ``load_ml_model()``. + """ + return _process('fit_class_random_forest', predictors=predictors, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed)
    + + + +
    +[docs] +@openeo_process +def fit_curve(data, parameters, function, dimension) -> ProcessBuilder: + """ + Curve fitting + + :param data: A data cube. + :param parameters: Defined the number of parameters for the model function and provides an initial guess + for them. At least one parameter is required. + :param function: The model function. It must take the parameters to fit as array through the first argument + and the independent variable `x` as the second argument. It is recommended to store the model function as + a user-defined process on the back-end to be able to re-use the model function with the computed optimal + values for the parameters afterwards. + :param dimension: The name of the dimension for curve fitting. Must be a dimension with labels that have a + order (i.e. numerical labels or a temporal dimension). Fails with a `DimensionNotAvailable` exception if + the specified dimension does not exist. + + :return: A data cube with the optimal values for the parameters. + """ + return _process('fit_curve', + data=data, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension + )
    + + + +
    +[docs] +@openeo_process +def fit_regr_random_forest(predictors, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest regression model + + :param predictors: The predictors for the regression model as a vector data cube. Aggregated to the + features (vectors) of the target input variable. + :param target: The training sites for the regression model as a vector data cube. This is associated with + the target variable for the Random Forest model. The geometry has to associated with a value to predict + (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options are + available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables are + considered for each split. - `onethird`: A third of the number of variables are considered for each split. + This is often the default for regression. - `sqrt`: The square root of the number of variables are + considered for each split. + :param num_trees: The number of trees build within the Random Forest regression. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, no + seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with ``load_ml_model()``. + """ + return _process('fit_regr_random_forest', predictors=predictors, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed)
    + + + +
    +[docs] +@openeo_process +def flatten_dimensions(data, dimensions, target_dimension, label_separator=UNSET) -> ProcessBuilder: + """ + Combine multiple dimensions into a single dimension + + :param data: A data cube. + :param dimensions: The names of the dimension to combine. The order of the array defines the order in which + the dimension labels and values are combined (see the example in the process description). Fails with a + `DimensionNotAvailable` exception if at least one of the specified dimensions does not exist. + :param target_dimension: The name of the new target dimension. A new dimensions will be created with the + given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` exception if a + dimension with the specified name exists. + :param label_separator: The string that will be used as a separator for the concatenated dimension labels. + To unambiguously revert the dimension labels with the process ``unflatten_dimension()``, the given string + must not be contained in any of the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system and + resolution) for all other dimensions remain unchanged. + """ + return _process('flatten_dimensions', data=data, dimensions=dimensions, target_dimension=target_dimension, label_separator=label_separator)
    + + + +
    +[docs] +@openeo_process +def floor(x) -> ProcessBuilder: + """ + Round fractions down + + :param x: A number to round down. + + :return: The number rounded down. + """ + return _process('floor', x=x)
    + + + +
    +[docs] +@openeo_process +def gt(x, y) -> ProcessBuilder: + """ + Greater than comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly greater than `y` or `null` if any operand is `null`, otherwise `false`. + """ + return _process('gt', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def gte(x, y) -> ProcessBuilder: + """ + Greater than or equal to comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is greater than or equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('gte', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def if_(value, accept, reject=UNSET) -> ProcessBuilder: + """ + If-Then-Else conditional + + :param value: A boolean value. + :param accept: A value that is returned if the boolean value is `true`. + :param reject: A value that is returned if the boolean value is **not** `true`. Defaults to `null`. + + :return: Either the `accept` or `reject` argument depending on the given boolean value. + """ + return _process('if', value=value, accept=accept, reject=reject)
    + + + +
    +[docs] +@openeo_process +def inspect(data, code=UNSET, level=UNSET, message=UNSET) -> ProcessBuilder: + """ + Add information to the logs + + :param data: Data to log. + :param code: A label to help identify one or more log entries originating from this process in the list of + all log entries. It can help to group or filter log entries and is usually not unique. + :param level: The severity level of this message, defaults to `info`. + :param message: A message to send in addition to the data. + + :return: The data as passed to the `data` parameter without any modification. + """ + return _process('inspect', data=data, code=code, level=level, message=message)
    + + + +
    +[docs] +@openeo_process +def int(x) -> ProcessBuilder: + """ + Integer part of a number + + :param x: A number. + + :return: Integer part of the number. + """ + return _process('int', x=x)
    + + + +
    +[docs] +@openeo_process +def is_infinite(x) -> ProcessBuilder: + """ + Value is an infinite number + + :param x: The data to check. + + :return: `true` if the data is an infinite number, otherwise `false`. + """ + return _process('is_infinite', x=x)
    + + + +
    +[docs] +@openeo_process +def is_nan(x) -> ProcessBuilder: + """ + Value is not a number + + :param x: The data to check. + + :return: `true` if the data is not a number, otherwise `false`. + """ + return _process('is_nan', x=x)
    + + + +
    +[docs] +@openeo_process +def is_nodata(x) -> ProcessBuilder: + """ + Value is a no-data value + + :param x: The data to check. + + :return: `true` if the data is a no-data value, otherwise `false`. + """ + return _process('is_nodata', x=x)
    + + + +
    +[docs] +@openeo_process +def is_valid(x) -> ProcessBuilder: + """ + Value is valid data + + :param x: The data to check. + + :return: `true` if the data is valid, otherwise `false`. + """ + return _process('is_valid', x=x)
    + + + +
    +[docs] +@openeo_process +def last(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Last element + + :param data: An array with elements of any data type. + :param ignore_nodata: 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 returned if the last value is such a value. + + :return: The last element of the input array. + """ + return _process('last', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def linear_scale_range(x, inputMin, inputMax, outputMin=UNSET, outputMax=UNSET) -> ProcessBuilder: + """ + Linear transformation between two ranges + + :param x: A number to transform. The number gets clipped to the bounds specified in `inputMin` and + `inputMax`. + :param inputMin: Minimum value the input can obtain. + :param inputMax: Maximum value the input can obtain. + :param outputMin: Minimum value of the desired output range. + :param outputMax: Maximum value of the desired output range. + + :return: The transformed number. + """ + return _process('linear_scale_range', x=x, inputMin=inputMin, inputMax=inputMax, outputMin=outputMin, outputMax=outputMax)
    + + + +
    +[docs] +@openeo_process +def ln(x) -> ProcessBuilder: + """ + Natural logarithm + + :param x: A number to compute the natural logarithm for. + + :return: The computed natural logarithm. + """ + return _process('ln', x=x)
    + + + +
    +[docs] +@openeo_process +def load_collection(id, spatial_extent, temporal_extent, bands=UNSET, properties=UNSET) -> ProcessBuilder: + """ + Load a collection + + :param id: The collection id. + :param spatial_extent: Limits the data to load from the collection to the specified bounding box or + polygons. The 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). The GeoJSON + can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a + `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one `Feature` with + `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` + geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of the + alternatives above. Set 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. + :param temporal_extent: 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: 1. The first element is the start of the temporal interval. The specified instance in time is + **included** in the interval. 2. The second element is the end of the temporal interval. The specified + instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is recommended to use + this parameter instead of using ``filter_bands()`` directly after loading unbounded data. + :param properties: Limits the data by metadata properties to include only data in the data cube which all + given conditions return `true` for (AND operation). Specify key-value-pairs with the key being the name of + the metadata property, which can be retrieved with the openEO Data Discovery for Collections. The value + must be a condition (user-defined process) to be evaluated against the collection metadata, see the + example. + + :return: A data cube for further processing. The dimensions and dimension properties (name, type, labels, + reference system and resolution) correspond to the collection's metadata, but the dimension labels are + restricted as specified in the parameters. + """ + return _process('load_collection', id=id, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands, properties=properties)
    + + + +
    +[docs] +@openeo_process +def load_ml_model(id) -> ProcessBuilder: + """ + Load a ML model + + :param id: The STAC Item to load the machine learning model from. The STAC Item must implement the `ml- + model` extension. + + :return: A machine learning model to be used with machine learning processes such as + ``predict_random_forest()``. + """ + return _process('load_ml_model', id=id)
    + + + +
    +[docs] +@openeo_process +def load_result(id, spatial_extent=UNSET, temporal_extent=UNSET, bands=UNSET) -> ProcessBuilder: + """ + Load batch job results + + :param id: The id of a batch job with results. + :param spatial_extent: Limits the data to load from the batch job result to the specified bounding box or + polygons. The 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). The GeoJSON + can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a + `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one `Feature` with + `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` + geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of the + alternatives above. Set 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. + :param temporal_extent: Limits the data to load from the batch job result 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: 1. The first element is the start of the temporal interval. The specified instance + in time is **included** in the interval. 2. The second element is the end of the temporal interval. The + specified instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is recommended to use + this parameter instead of using ``filter_bands()`` directly after loading unbounded data. + + :return: A data cube for further processing. + """ + return _process('load_result', id=id, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands)
    + + + +
    +[docs] +@openeo_process +def load_uploaded_files(paths, format, options=UNSET) -> ProcessBuilder: + """ + Load files from the user workspace + + :param paths: The files to read. Folders can't be specified, specify all files instead. An exception is + thrown if a file can't be read. + :param format: The file format to read from. It must be one of the values that the server reports as + supported input file formats, which usually correspond to the short GDAL/OGR codes. If the format is not + suitable for loading the data, a `FormatUnsuitable` exception will be thrown. This parameter is *case + insensitive*. + :param options: The file format parameters to be used to read the files. Must correspond to the parameters + that the server reports as supported parameters for the chosen `format`. The parameter names and valid + values usually correspond to the GDAL/OGR format options. + + :return: A data cube for further processing. + """ + return _process('load_uploaded_files', paths=paths, format=format, options=options)
    + + + +
    +[docs] +@openeo_process +def log(x, base) -> ProcessBuilder: + """ + Logarithm to a base + + :param x: A number to compute the logarithm for. + :param base: The numerical base. + + :return: The computed logarithm. + """ + return _process('log', x=x, base=base)
    + + + +
    +[docs] +@openeo_process +def lt(x, y) -> ProcessBuilder: + """ + Less than comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly less than `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('lt', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def lte(x, y) -> ProcessBuilder: + """ + Less than or equal to comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is less than or equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('lte', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def mask(data, mask, replacement=UNSET) -> ProcessBuilder: + """ + Apply a raster mask + + :param data: A raster data cube. + :param mask: A mask as a raster data cube. Every pixel in `data` must have a corresponding element in + `mask`. + :param replacement: The value used to replace masked values with. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, labels, + reference system and resolution) remain unchanged. + """ + return _process('mask', data=data, mask=mask, replacement=replacement)
    + + + +
    +[docs] +@openeo_process +def mask_polygon(data, mask, replacement=UNSET, inside=UNSET) -> ProcessBuilder: + """ + Apply a polygon mask + + :param data: A raster data cube. + :param mask: A GeoJSON object containing at least one polygon. The provided feature types can be one of the + following: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a `Polygon` or `MultiPolygon` + geometry, * a `FeatureCollection` containing at least one `Feature` with `Polygon` or `MultiPolygon` + geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` geometries. To maximize + interoperability, `GeometryCollection` should be avoided in favour of one of the alternatives above. + :param replacement: The value used to replace masked values with. + :param inside: If set to `true` all pixels for which the point at the pixel center **does** intersect with + any polygon are replaced. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, labels, + reference system and resolution) remain unchanged. + """ + return _process('mask_polygon', data=data, mask=mask, replacement=replacement, inside=inside)
    + + + +
    +[docs] +@openeo_process +def max(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Maximum value + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The maximum value. + """ + return _process('max', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def mean(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Arithmetic mean (average) + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed arithmetic mean. + """ + return _process('mean', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def median(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Statistical median + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed statistical median. + """ + return _process('median', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def merge_cubes(cube1, cube2, overlap_resolver=UNSET, context=UNSET) -> ProcessBuilder: + """ + Merge two data cubes + + :param cube1: The first data cube. + :param cube2: The second data cube. + :param overlap_resolver: A reduction operator that resolves the conflict if the data overlaps. The reducer + must return a value of the same data type as the input values are. The reduction operator may be a single + process such as ``multiply()`` or consist of multiple sub-processes. `null` (the default) can be specified + if no overlap resolver is required. + :param context: Additional data to be passed to the overlap resolver. + + :return: The merged data cube. See the process description for details regarding the dimensions and + dimension properties (name, type, labels, reference system and resolution). + """ + return _process('merge_cubes', + cube1=cube1, + cube2=cube2, + overlap_resolver=build_child_callback(overlap_resolver, parent_parameters=['x', 'y', 'context']), + context=context + )
    + + + +
    +[docs] +@openeo_process +def min(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum value + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The minimum value. + """ + return _process('min', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def mod(x, y) -> ProcessBuilder: + """ + Modulo + + :param x: A number to be used as the dividend. + :param y: A number to be used as the divisor. + + :return: The remainder after division. + """ + return _process('mod', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def multiply(x, y) -> ProcessBuilder: + """ + Multiplication of two numbers + + :param x: The multiplier. + :param y: The multiplicand. + + :return: The computed product of the two numbers. + """ + return _process('multiply', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def nan() -> ProcessBuilder: + """ + Not a Number (NaN) + + :return: Returns `NaN`. + """ + return _process('nan', )
    + + + +
    +[docs] +@openeo_process +def ndvi(data, nir=UNSET, red=UNSET, target_band=UNSET) -> ProcessBuilder: + """ + Normalized Difference Vegetation Index + + :param data: A raster data cube with two bands that have the common names `red` and `nir` assigned. + :param nir: The name of the NIR band. Defaults to the band that has the common name `nir` assigned. Either + 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. + :param red: The name of the red band. Defaults to the band that has the common name `red` assigned. Either + 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. + :param target_band: By default, the dimension of type `bands` is dropped. To keep the dimension specify a + new band name in this parameter so that a new dimension label with the specified name will be added for the + computed values. + + :return: A raster data cube containing the computed NDVI values. The structure of the data cube differs + depending on the value passed to `target_band`: * `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. * `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`. + """ + return _process('ndvi', data=data, nir=nir, red=red, target_band=target_band)
    + + + +
    +[docs] +@openeo_process +def neq(x, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Not equal to comparison + + :param x: First operand. + :param y: Second operand. + :param delta: 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. This option is + basically an alias for the following computation: `gt(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be disabled + by setting this parameter to `false`. + + :return: `true` if `x` is *not* equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('neq', x=x, y=y, delta=delta, case_sensitive=case_sensitive)
    + + + +
    +[docs] +@openeo_process +def normalized_difference(x, y) -> ProcessBuilder: + """ + Normalized difference + + :param x: The value for the first band. + :param y: The value for the second band. + + :return: The computed normalized difference. + """ + return _process('normalized_difference', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def not_(x) -> ProcessBuilder: + """ + Inverting a boolean + + :param x: Boolean value to invert. + + :return: Inverted boolean value. + """ + return _process('not', x=x)
    + + + +
    +[docs] +@openeo_process +def or_(x, y) -> ProcessBuilder: + """ + Logical OR + + :param x: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical OR. + """ + return _process('or', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def order(data, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Create a permutation + + :param data: An array to compute the order for. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The computed permutation. + """ + return _process('order', data=data, asc=asc, nodata=nodata)
    + + + +
    +[docs] +@openeo_process +def pi() -> ProcessBuilder: + """ + Pi (π) + + :return: The numerical value of Pi. + """ + return _process('pi', )
    + + + +
    +[docs] +@openeo_process +def power(base, p) -> ProcessBuilder: + """ + Exponentiation + + :param base: The numerical base. + :param p: The numerical exponent. + + :return: The computed value for `base` raised to the power of `p`. + """ + return _process('power', base=base, p=p)
    + + + +
    +[docs] +@openeo_process +def predict_curve(data, parameters, function, dimension, labels=UNSET) -> ProcessBuilder: + """ + Predict values + + :param data: A data cube to predict values for. + :param parameters: A data cube with optimal values from a result of e.g. ``fit_curve()``. + :param function: The model function. It must take the parameters to fit as array through the first argument + and the independent variable `x` as the second argument. It is recommended to store the model function as + a user-defined process on the back-end. + :param dimension: The name of the dimension for predictions. Fails with a `DimensionNotAvailable` exception + if the specified dimension does not exist. + :param labels: The labels to predict values for. If no labels are given, predicts values only for no-data + (`null`) values in the data cube. + + :return: A data cube with the predicted values. + """ + return _process('predict_curve', + data=data, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension, + labels=labels + )
    + + + +
    +[docs] +@openeo_process +def predict_random_forest(data, model) -> ProcessBuilder: + """ + Predict values from a Random Forest model + + :param data: An array of numbers. + :param model: A model object that can be trained with the processes ``fit_regr_random_forest()`` + (regression) and ``fit_class_random_forest()`` (classification). + + :return: The predicted value. Returns `null` if any of the given values in the array is a no-data value. + """ + return _process('predict_random_forest', data=data, model=model)
    + + + +
    +[docs] +@openeo_process +def product(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the product by multiplying numbers + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed product of the sequence of numbers. + """ + return _process('product', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def quantiles(data, probabilities=UNSET, q=UNSET, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Quantiles + + :param data: An array of numbers. + :param probabilities: A list of probabilities to calculate quantiles for. The probabilities must be between + 0 and 1 (inclusive). + :param q: Number of intervals to calculate quantiles for. Calculates q-quantiles with equal-sized + intervals. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. Setting + this flag to `false` considers no-data values so that an array with `null` values is returned if any + element is such a value. + + :return: An array with the computed quantiles. The list has either * as many elements as the given list of + `probabilities` had or * *`q`-1* elements. If 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. + """ + return _process('quantiles', data=data, probabilities=probabilities, q=q, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def rearrange(data, order) -> ProcessBuilder: + """ + Rearrange an array based on a permutation + + :param data: The array to rearrange. + :param order: The permutation used for rearranging. + + :return: The rearranged array. + """ + return _process('rearrange', data=data, order=order)
    + + + +
    +[docs] +@openeo_process +def reduce_dimension(data, reducer, dimension, context=UNSET) -> ProcessBuilder: + """ + Reduce dimensions + + :param data: A data cube. + :param reducer: A reducer to apply on 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. + :param dimension: The name of the dimension over which to reduce. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return _process('reduce_dimension', + data=data, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + )
    + + + +
    +[docs] +@openeo_process +def reduce_spatial(data, reducer, context=UNSET) -> ProcessBuilder: + """ + Reduce spatial dimensions 'x' and 'y' + + :param data: A data cube. + :param reducer: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return _process('reduce_spatial', data=data, reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), context=context)
    + + + +
    +[docs] +@openeo_process +def rename_dimension(data, source, target) -> ProcessBuilder: + """ + Rename a dimension + + :param data: The data cube. + :param source: The current name of the dimension. Fails with a `DimensionNotAvailable` exception if the + specified dimension does not exist. + :param target: A new Name for the dimension. Fails with a `DimensionExists` exception if a dimension with + the specified name exists. + + :return: A data cube with the same dimensions, but the name of one of the dimensions changes. The old name + can not be referred to any longer. The dimension properties (name, type, labels, reference system and + resolution) remain unchanged. + """ + return _process('rename_dimension', data=data, source=source, target=target)
    + + + +
    +[docs] +@openeo_process +def rename_labels(data, dimension, target, source=UNSET) -> ProcessBuilder: + """ + Rename dimension labels + + :param data: The data cube. + :param dimension: The name of the dimension to rename the labels for. + :param target: The new names for the labels. If a target dimension label already exists in the data cube, + a `LabelExists` exception is thrown. + :param source: The original names of the labels to be renamed to corresponding array elements in the + parameter `target`. It is allowed to only specify a subset of labels to rename, as long as the `target` and + `source` parameter have the same length. The order of the labels doesn't need to match the order of the + dimension labels in the data cube. By default, the array is empty so that the dimension labels in the data + cube are expected to be enumerated. If the dimension labels are not enumerated and the given array is + empty, the `LabelsNotEnumerated` exception is thrown. If one of the source dimension labels doesn't exist, + the `LabelNotAvailable` exception is thrown. + + :return: The data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged, except that for the given dimension the labels change. The old + labels can not be referred to any longer. The number of labels remains the same. + """ + return _process('rename_labels', data=data, dimension=dimension, target=target, source=source)
    + + + +
    +[docs] +@openeo_process +def resample_cube_spatial(data, target, method=UNSET) -> ProcessBuilder: + """ + Resample the spatial dimensions to match a target data cube + + :param data: A data cube. + :param target: A data cube that describes the spatial target resolution. + :param method: 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): * `average`: average (mean) + resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling * `cubic`: + cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc resampling * + `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median resampling, + selects the median value of all valid pixels * `min`: minimum resampling, selects the minimum value from + all valid pixels * `mode`: mode resampling, selects the value which appears most often of all the sampled + points * `near`: nearest neighbour resampling (default) * `q1`: first quartile resampling, selects the + first quartile value of all valid pixels * `q3`: third quartile resampling, selects the third quartile + value of all valid pixels * `rms` root mean square (quadratic mean) of all valid pixels * `sum`: compute + the weighted sum of all valid pixels Valid pixels are determined based on the function ``is_valid()``. + + :return: 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 spatial + dimensions. + """ + return _process('resample_cube_spatial', data=data, target=target, method=method)
    + + + +
    +[docs] +@openeo_process +def resample_cube_temporal(data, target, dimension=UNSET, valid_within=UNSET) -> ProcessBuilder: + """ + Resample temporal dimensions to match a target data cube + + :param data: A data cube with one or more temporal dimensions. + :param target: A data cube that describes the temporal target resolution. + :param dimension: 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. The following exceptions may occur: * A dimension is + given, but it does not exist in any of the data cubes: `DimensionNotAvailable` * A dimension is given, but + one of them is not temporal: `DimensionMismatch` * No specific dimension name is given and there are no + temporal dimensions with the same name in the data: `DimensionMismatch` + :param valid_within: 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`). + + :return: 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. + """ + return _process('resample_cube_temporal', data=data, target=target, dimension=dimension, valid_within=valid_within)
    + + + +
    +[docs] +@openeo_process +def resample_spatial(data, resolution=UNSET, projection=UNSET, method=UNSET, align=UNSET) -> ProcessBuilder: + """ + Resample and warp the spatial dimensions + + :param data: A raster data cube. + :param resolution: 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`). + :param projection: Warps the data cube to the target projection, specified as as [EPSG + code](http://www.epsg-registry.org/), [WKT2 (ISO 19162) + string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html), [PROJ definition + (deprecated)](https://proj.org/usage/quickstart.html). By default (`null`), the projection is not changed. + :param method: 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): * `average`: average (mean) + resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling * `cubic`: + cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc resampling * + `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median resampling, + selects the median value of all valid pixels * `min`: minimum resampling, selects the minimum value from + all valid pixels * `mode`: mode resampling, selects the value which appears most often of all the sampled + points * `near`: nearest neighbour resampling (default) * `q1`: first quartile resampling, selects the + first quartile value of all valid pixels * `q3`: third quartile resampling, selects the third quartile + value of all valid pixels * `rms` root mean square (quadratic mean) of all valid pixels * `sum`: compute + the weighted sum of all valid pixels Valid pixels are determined based on the function ``is_valid()``. + :param align: Specifies to which corner of the spatial extent the new resampled data is aligned to. + + :return: A raster data cube with values warped onto the new projection. It has the same dimensions and the + same dimension properties (name, type, labels, reference system and resolution) for all non-spatial or + vertical spatial dimensions. For the horizontal spatial dimensions the name and type remain unchanged, but + reference system, labels and resolution may change depending on the given parameters. + """ + return _process('resample_spatial', data=data, resolution=resolution, projection=projection, method=method, align=align)
    + + + +
    +[docs] +@openeo_process +def round(x, p=UNSET) -> ProcessBuilder: + """ + Round to a specified precision + + :param x: A number to round. + :param p: A positive number specifies the number of digits after the decimal point to round to. A negative + number means rounding to a power of ten, so for example *-2* rounds to the nearest hundred. Defaults to + *0*. + + :return: The rounded number. + """ + return _process('round', x=x, p=p)
    + + + +
    +[docs] +@openeo_process +def run_udf(data, udf, runtime, version=UNSET, context=UNSET) -> ProcessBuilder: + """ + Run a UDF + + :param data: The data to be passed to the UDF. + :param udf: Either source code, an absolute URL or a path to a UDF script. + :param runtime: A UDF runtime identifier available at the back-end. + :param version: An UDF runtime version. If set to `null`, the default runtime version specified for each + runtime is used. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can be of any data type and is exactly what the + UDF code returns. + """ + return _process('run_udf', data=data, udf=udf, runtime=runtime, version=version, context=context)
    + + + +
    +[docs] +@openeo_process +def run_udf_externally(data, url, context=UNSET) -> ProcessBuilder: + """ + Run an externally hosted UDF container + + :param data: The data to be passed to the UDF. + :param url: Absolute URL to a remote UDF service. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can in principle be of any data type, but it + depends on what is returned by the UDF code. Please see the implemented UDF interface for details. + """ + return _process('run_udf_externally', data=data, url=url, context=context)
    + + + +
    +[docs] +@openeo_process +def sar_backscatter(data, coefficient=UNSET, elevation_model=UNSET, mask=UNSET, contributing_area=UNSET, local_incidence_angle=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + Computes backscatter from SAR input + + :param data: The source data cube containing SAR input. + :param coefficient: Select the radiometric correction coefficient. The following options are available: * + `beta0`: radar brightness * `sigma0-ellipsoid`: ground area computed with ellipsoid earth model * + `sigma0-terrain`: ground area computed with terrain earth model * `gamma0-ellipsoid`: ground area computed + with ellipsoid earth model in sensor line of sight * `gamma0-terrain`: ground area computed with terrain + earth model in sensor line of sight (default) * `null`: non-normalized backscatter + :param elevation_model: 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. + :param mask: 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). + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param local_incidence_angle: If set to `true`, a DEM-based local incidence angle band named + `local_incidence_angle` is added. The values are given in degrees. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options will + reduce portability. + + :return: Backscatter values corresponding to the chosen parametrization. The values are given in linear + scale. + """ + return _process('sar_backscatter', + data=data, + coefficient=coefficient, + elevation_model=elevation_model, + mask=mask, + contributing_area=contributing_area, + local_incidence_angle=local_incidence_angle, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + )
    + + + +
    +[docs] +@openeo_process +def save_ml_model(data, options=UNSET) -> ProcessBuilder: + """ + Save a ML model + + :param data: The data to store as a machine learning model. + :param options: Additional parameters to create the file(s). + + :return: Returns `false` if the process failed to store the model, `true` otherwise. + """ + return _process('save_ml_model', data=data, options=options)
    + + + +
    +[docs] +@openeo_process +def save_result(data, format, options=UNSET) -> ProcessBuilder: + """ + Save processed data + + :param data: The data to deliver in the given file format. + :param format: The file format to use. It must be one of the values that the server reports as supported + output file formats, which usually correspond to the short GDAL/OGR codes. If the format is not suitable + for storing the underlying data structure, a `FormatUnsuitable` exception will be thrown. This parameter is + *case insensitive*. + :param options: The file format parameters to be used to create the file(s). Must correspond to the + parameters that the server reports as supported parameters for the chosen `format`. The parameter names and + valid values usually correspond to the GDAL/OGR format options. + + :return: Returns `false` if the process failed to make the data available, `true` otherwise. + """ + return _process('save_result', data=data, format=format, options=options)
    + + + +
    +[docs] +@openeo_process +def sd(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Standard deviation + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed sample standard deviation. + """ + return _process('sd', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def sgn(x) -> ProcessBuilder: + """ + Signum + + :param x: A number. + + :return: The computed signum value of `x`. + """ + return _process('sgn', x=x)
    + + + +
    +[docs] +@openeo_process +def sin(x) -> ProcessBuilder: + """ + Sine + + :param x: An angle in radians. + + :return: The computed sine of `x`. + """ + return _process('sin', x=x)
    + + + +
    +[docs] +@openeo_process +def sinh(x) -> ProcessBuilder: + """ + Hyperbolic sine + + :param x: An angle in radians. + + :return: The computed hyperbolic sine of `x`. + """ + return _process('sinh', x=x)
    + + + +
    +[docs] +@openeo_process +def sort(data, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Sort data + + :param data: An array with data to sort. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The sorted array. + """ + return _process('sort', data=data, asc=asc, nodata=nodata)
    + + + +
    +[docs] +@openeo_process +def sqrt(x) -> ProcessBuilder: + """ + Square root + + :param x: A number. + + :return: The computed square root. + """ + return _process('sqrt', x=x)
    + + + +
    +[docs] +@openeo_process +def subtract(x, y) -> ProcessBuilder: + """ + Subtraction of two numbers + + :param x: The minuend. + :param y: The subtrahend. + + :return: The computed result. + """ + return _process('subtract', x=x, y=y)
    + + + +
    +[docs] +@openeo_process +def sum(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the sum by adding up numbers + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed sum of the sequence of numbers. + """ + return _process('sum', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def tan(x) -> ProcessBuilder: + """ + Tangent + + :param x: An angle in radians. + + :return: The computed tangent of `x`. + """ + return _process('tan', x=x)
    + + + +
    +[docs] +@openeo_process +def tanh(x) -> ProcessBuilder: + """ + Hyperbolic tangent + + :param x: An angle in radians. + + :return: The computed hyperbolic tangent of `x`. + """ + return _process('tanh', x=x)
    + + + +
    +[docs] +@openeo_process +def text_begins(data, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text begins with another text + + :param data: Text in which to find something at the beginning. + :param pattern: Text to find at the beginning of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` begins with `pattern`, false` otherwise. + """ + return _process('text_begins', data=data, pattern=pattern, case_sensitive=case_sensitive)
    + + + +
    +[docs] +@openeo_process +def text_concat(data, separator=UNSET) -> ProcessBuilder: + """ + Concatenate elements to a single text + + :param data: A set of elements. Numbers, boolean values and null values get converted to their (lower case) + string representation. For example: `1` (integer), `-1.5` (number), `true` / `false` (boolean values) + :param separator: A separator to put between each of the individual texts. Defaults to an empty string. + + :return: A string containing a string representation of all the array elements in the same order, with the + separator between each element. + """ + return _process('text_concat', data=data, separator=separator)
    + + + +
    +[docs] +@openeo_process +def text_contains(data, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text contains another text + + :param data: Text in which to find something in. + :param pattern: Text to find in `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` contains the `pattern`, false` otherwise. + """ + return _process('text_contains', data=data, pattern=pattern, case_sensitive=case_sensitive)
    + + + +
    +[docs] +@openeo_process +def text_ends(data, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text ends with another text + + :param data: Text in which to find something at the end. + :param pattern: Text to find at the end of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` ends with `pattern`, false` otherwise. + """ + return _process('text_ends', data=data, pattern=pattern, case_sensitive=case_sensitive)
    + + + +
    +[docs] +@openeo_process +def trim_cube(data) -> ProcessBuilder: + """ + Remove dimension labels with no-data values + + :param data: A raster data cube to trim. + + :return: A trimmed raster data cube with the same dimensions. The dimension properties name, type, + reference system and resolution remain unchanged. The number of dimension labels may decrease. + """ + return _process('trim_cube', data=data)
    + + + +
    +[docs] +@openeo_process +def unflatten_dimension(data, dimension, target_dimensions, label_separator=UNSET) -> ProcessBuilder: + """ + Split a single dimensions into multiple dimensions + + :param data: A data cube that is consistently structured so that operation can execute flawlessly (e.g. the + dimension labels need to contain the `label_separator` exactly 1 time for two target dimensions, 2 times + for three target dimensions etc.). + :param dimension: The name of the dimension to split. + :param target_dimensions: The names of the new target dimensions. New dimensions will be created with the + given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` exception if + any of the dimensions exists. The order of the array defines the order in which the dimensions and + dimension labels are added to the data cube (see the example in the process description). + :param label_separator: The string that will be used as a separator to split the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system and + resolution) for all other dimensions remain unchanged. + """ + return _process('unflatten_dimension', data=data, dimension=dimension, target_dimensions=target_dimensions, label_separator=label_separator)
    + + + +
    +[docs] +@openeo_process +def variance(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Variance + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed sample variance. + """ + return _process('variance', data=data, ignore_nodata=ignore_nodata)
    + + + +
    +[docs] +@openeo_process +def vector_buffer(geometries, distance) -> ProcessBuilder: + """ + Buffer geometries by distance + + :param geometries: Geometries to apply the buffer on. Vector properties are preserved for vector data cubes + and all GeoJSON Features. To 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`). + :param distance: The distance of the buffer in the unit of the spatial reference system. A positive + distance expands the geometries and results in outward buffering (dilation) while a negative distance + shrinks the geometries and results in inward buffering (erosion). + + :return: Returns a vector data cube with the computed new geometries. + """ + return _process('vector_buffer', geometries=geometries, distance=distance)
    + + + +
    +[docs] +@openeo_process +def vector_to_random_points(data, geometry_count=UNSET, total_count=UNSET, group=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Sample random points from geometries + + :param data: Input geometries for sample extraction. To 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`). + :param geometry_count: The maximum number of points to compute per geometry. Points in the input + geometries can be selected only once by the sampling. + :param total_count: The maximum number of points to compute overall. Throws a `CountMismatch` exception if + the specified value is less than the provided number of geometries. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a `MultiPoint` + per geometry given which keeps the original identifier if present. * Otherwise, each sampled point is + generated as a distinct `Point` geometry without identifier. + :param seed: A randomization seed to use for random sampling. If not given or `null`, no seed is used and + results may differ on subsequent use. + + :return: Returns a vector data cube with the sampled points. + """ + return _process('vector_to_random_points', data=data, geometry_count=geometry_count, total_count=total_count, group=group, seed=seed)
    + + + +
    +[docs] +@openeo_process +def vector_to_regular_points(data, distance, group=UNSET) -> ProcessBuilder: + """ + Sample regular points from geometries + + :param data: Input geometries for sample extraction. To 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`). + :param distance: Defines the minimum distance in the unit of the reference system that is required between + two samples generated *inside* a single geometry. - For **polygons**, the distance defines the cell sizes + of a regular grid that starts at the upper-left bound of each polygon. The centroid of each cell is then a + sample point. If the centroid is not enclosed in the polygon, no point is sampled. If no point can be + sampled for the geometry at all, the first coordinate of the geometry is returned as point. - For **lines** + (line strings), the sampling starts with a point at the first coordinate of the line and then walks along + the line and samples a new point each time the distance to the previous point has been reached again. - For + **points**, the point is returned as given. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a `MultiPoint` + per geometry given which keeps the original identifier if present. * Otherwise, each sampled point is + generated as a distinct `Point` geometry without identifier. + + :return: Returns a vector data cube with the sampled points. + """ + return _process('vector_to_regular_points', data=data, distance=distance, group=group)
    + + + +
    +[docs] +@openeo_process +def xor(x, y) -> ProcessBuilder: + """ + Logical XOR (exclusive or) + + :param x: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical XOR. + """ + return _process('xor', x=x, y=y)
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/_datacube.html b/_modules/openeo/rest/_datacube.html new file mode 100644 index 000000000..01f9e78bf --- /dev/null +++ b/_modules/openeo/rest/_datacube.html @@ -0,0 +1,455 @@ + + + + + + + openeo.rest._datacube — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest._datacube

    +from __future__ import annotations
    +
    +import logging
    +import pathlib
    +import re
    +import typing
    +import uuid
    +import warnings
    +from typing import Dict, List, Optional, Tuple, Union
    +
    +import requests
    +
    +from openeo.internal.graph_building import FlatGraphableMixin, PGNode, _FromNodeMixin
    +from openeo.internal.jupyter import render_component
    +from openeo.internal.processes.builder import (
    +    convert_callable_to_pgnode,
    +    get_parameter_names,
    +)
    +from openeo.internal.warnings import UserDeprecationWarning
    +from openeo.rest import OpenEoClientException
    +from openeo.util import dict_no_none, str_truncate
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    from openeo.rest.connection import Connection
    +
    +log = logging.getLogger(__name__)
    +
    +# Sentinel object to refer to "current" cube in chained cube processing expressions.
    +THIS = object()
    +
    +
    +class _ProcessGraphAbstraction(_FromNodeMixin, FlatGraphableMixin):
    +    """
    +    Base class for client-side abstractions/wrappers
    +    for structures that are represented by a openEO process graph:
    +    raster data cubes, vector cubes, ML models, ...
    +    """
    +
    +    def __init__(self, pgnode: PGNode, connection: Connection):
    +        self._pg = pgnode
    +        self._connection = connection
    +
    +    def __str__(self):
    +        return "{t}({pg})".format(t=self.__class__.__name__, pg=self._pg)
    +
    +    def flat_graph(self) -> Dict[str, dict]:
    +        """
    +        Get the process graph in internal flat dict representation.
    +
    +        .. warning:: This method is mainly intended for internal use.
    +            It is not recommended for general use and is *subject to change*.
    +
    +            Instead, it is recommended to use
    +            :py:meth:`to_json()` or :py:meth:`print_json()`
    +            to obtain a standardized, interoperable JSON representation of the process graph.
    +            See :ref:`process_graph_export` for more information.
    +        """
    +        # TODO: wrap in {"process_graph":...} by default/optionally?
    +        return self._pg.flat_graph()
    +
    +    @property
    +    def _api_version(self):
    +        return self._connection.capabilities().api_version_check
    +
    +    @property
    +    def connection(self) -> Connection:
    +        return self._connection
    +
    +    def result_node(self) -> PGNode:
    +        """
    +        Get the current result node (:py:class:`PGNode`) of the process graph.
    +
    +        .. versionadded:: 0.10.1
    +        """
    +        return self._pg
    +
    +    def from_node(self):
    +        # _FromNodeMixin API
    +        return self._pg
    +
    +    def _build_pgnode(
    +        self,
    +        process_id: str,
    +        arguments: Optional[dict] = None,
    +        namespace: Optional[str] = None,
    +        **kwargs
    +    ) -> PGNode:
    +        """
    +        Helper to build a PGNode from given argument dict and/or kwargs,
    +        and possibly resolving the `THIS` reference.
    +        """
    +        arguments = {**(arguments or {}), **kwargs}
    +        for k, v in arguments.items():
    +            if v is THIS:
    +                arguments[k] = self
    +            # TODO: also necessary to traverse lists/dictionaries?
    +        return PGNode(process_id=process_id, arguments=arguments, namespace=namespace)
    +
    +    # TODO #278 also move process graph "execution" methods here: `download`, `execute`, `execute_batch`, `create_job`, `save_udf`,  ...
    +
    +    def _repr_html_(self):
    +        process = {"process_graph": self.flat_graph()}
    +        parameters = {
    +            "id": uuid.uuid4().hex,
    +            "explicit-zoom": True,
    +            "height": "400px",
    +        }
    +        return render_component("model-builder", data=process, parameters=parameters)
    +
    +
    +
    +[docs] +class UDF: + """ + Helper class to load UDF code (e.g. from file) and embed them as "callback" or child process in a process graph. + + Usage example: + + .. code-block:: python + + udf = UDF.from_file("my-udf-code.py") + cube = cube.apply(process=udf) + + + .. versionchanged:: 0.13.0 + Added auto-detection of ``runtime``. + Specifying the ``data`` argument is not necessary anymore, and actually deprecated. + Added :py:meth:`from_file` to simplify loading UDF code from a file. + See :ref:`old_udf_api` for more background about the changes. + """ + + # TODO: eliminate dependency on `openeo.rest.connection` and move to somewhere under `openeo.internal`? + + __slots__ = ["code", "_runtime", "version", "context", "_source"] + + def __init__( + self, + code: str, + runtime: Optional[str] = None, + data=None, # TODO #181 remove `data` argument + version: Optional[str] = None, + context: Optional[dict] = None, + _source=None, + ): + """ + Construct a UDF object from given code string and other argument related to the ``run_udf`` process. + + :param code: UDF source code string (Python, R, ...) + :param runtime: optional UDF runtime identifier, will be autodetected from source code if omitted. + :param data: unused leftover from old API. Don't use this argument, it will be removed in a future release. + :param version: optional UDF runtime version string + :param context: optional additional UDF context data + :param _source: (for internal use) source identifier + """ + # TODO: automatically dedent code (when literal string) ? + self.code = code + self._runtime = runtime + self.version = version + self.context = context + self._source = _source + if data is not None: + # TODO #181 remove `data` argument + warnings.warn( + f"The `data` argument of `{self.__class__.__name__}` is deprecated, unused and will be removed in a future release.", + category=UserDeprecationWarning, + stacklevel=2, + ) + + def __repr__(self): + return f"<{type(self).__name__} runtime={self._runtime!r} code={str_truncate(self.code, width=200)!r}>" + + def get_runtime(self, connection: Optional[Connection] = None) -> str: + return self._runtime or self._guess_runtime(connection=connection) + +
    +[docs] + @classmethod + def from_file( + cls, + path: Union[str, pathlib.Path], + runtime: Optional[str] = None, + version: Optional[str] = None, + context: Optional[dict] = None, + ) -> UDF: + """ + Load a UDF from a local file. + + .. seealso:: + :py:meth:`from_url` for loading from a URL. + + :param path: path to the local file with UDF source code + :param runtime: optional UDF runtime identifier, will be auto-detected from source code if omitted. + :param version: optional UDF runtime version string + :param context: optional additional UDF context data + """ + path = pathlib.Path(path) + code = path.read_text(encoding="utf-8") + return cls( + code=code, runtime=runtime, version=version, context=context, _source=path + )
    + + +
    +[docs] + @classmethod + def from_url( + cls, + url: str, + runtime: Optional[str] = None, + version: Optional[str] = None, + context: Optional[dict] = None, + ) -> UDF: + """ + Load a UDF from a URL. + + .. seealso:: + :py:meth:`from_file` for loading from a local file. + + :param url: URL path to load the UDF source code from + :param runtime: optional UDF runtime identifier, will be auto-detected from source code if omitted. + :param version: optional UDF runtime version string + :param context: optional additional UDF context data + """ + resp = requests.get(url) + resp.raise_for_status() + code = resp.text + return cls( + code=code, runtime=runtime, version=version, context=context, _source=url + )
    + + + def _guess_runtime(self, connection: Optional[Connection] = None) -> str: + """Guess UDF runtime from UDF source (path) or source code.""" + # First, guess UDF language + language = None + if isinstance(self._source, pathlib.Path): + language = self._guess_runtime_from_suffix(self._source.suffix) + elif isinstance(self._source, str): + url_match = re.match( + r"https?://.*?(?P<suffix>\.\w+)([&#].*)?$", self._source + ) + if url_match: + language = self._guess_runtime_from_suffix(url_match.group("suffix")) + if not language: + # Guess language from UDF code + if re.search(r"^def [\w0-9_]+\(", self.code, flags=re.MULTILINE): + language = "Python" + # TODO: detection heuristics for R and other languages? + if not language: + raise OpenEoClientException("Failed to detect language of UDF code.") + runtime = language + if connection: + # Some additional best-effort validation/normalization of the runtime + # TODO: this just does some case-normalization, just drop that all together to eliminate + # the dependency on a connection object. See https://github.com/Open-EO/openeo-api/issues/510 + runtimes = {k.lower(): k for k in connection.list_udf_runtimes().keys()} + runtime = runtimes.get(runtime.lower(), runtime) + return runtime + + def _guess_runtime_from_suffix(self, suffix: str) -> Union[str]: + return { + ".py": "Python", + ".r": "R", + }.get(suffix.lower()) + +
    +[docs] + def get_run_udf_callback(self, connection: Optional[Connection] = None, data_parameter: str = "data") -> PGNode: + """ + For internal use: construct `run_udf` node to be used as callback in `apply`, `reduce_dimension`, ... + """ + arguments = dict_no_none( + data={"from_parameter": data_parameter}, + udf=self.code, + runtime=self.get_runtime(connection=connection), + version=self.version, + context=self.context, + ) + return PGNode(process_id="run_udf", arguments=arguments)
    +
    + + + +def build_child_callback( + process: Union[str, PGNode, typing.Callable, UDF], + parent_parameters: List[str], + connection: Optional[Connection] = None, +) -> dict: + """ + Build a "callback" process: a user defined process that is used by another process (such + as `apply`, `apply_dimension`, `reduce`, ....) + + :param process: process id string, PGNode or callable that uses the ProcessBuilder mechanism to build a process + :param parent_parameters: list of parameter names defined for child process + :param connection: optional connection object to improve runtime validation for UDFs + :return: + """ + # TODO: move this to more generic process graph building utility module + # TODO: autodetect the parameters defined by parent process? + # TODO: eliminate need for connection object (also see `UDF._guess_runtime`) + # TODO: when `openeo.rest` deps are gone: move this helper to somewhere under `openeo.internal` + if isinstance(process, PGNode): + # Assume this is already a valid callback process + pg = process + elif isinstance(process, str): + # Assume given reducer is a simple predefined reduce process_id + # TODO: avoid local import (workaround for circular import issue) + import openeo.processes + if process in openeo.processes.__dict__: + process_params = get_parameter_names(openeo.processes.__dict__[process]) + # TODO: switch to "Callable" handling here + else: + # Best effort guess + process_params = parent_parameters + if parent_parameters == ["x", "y"] and (len(process_params) == 1 or process_params[:1] == ["data"]): + # Special case: wrap all parent parameters in an array + arguments = {process_params[0]: [{"from_parameter": p} for p in parent_parameters]} + else: + # Only pass parameters that correspond with an arg name + common = set(process_params).intersection(parent_parameters) + arguments = {p: {"from_parameter": p} for p in common} + pg = PGNode(process_id=process, arguments=arguments) + elif isinstance(process, typing.Callable): + pg = convert_callable_to_pgnode(process, parent_parameters=parent_parameters) + elif isinstance(process, UDF): + pg = process.get_run_udf_callback(connection=connection, data_parameter=parent_parameters[0]) + elif isinstance(process, dict) and isinstance(process.get("process_graph"), PGNode): + pg = process["process_graph"] + else: + raise ValueError(process) + + return PGNode.to_process_graph_argument(pg) +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/connection.html b/_modules/openeo/rest/connection.html new file mode 100644 index 000000000..64784fc86 --- /dev/null +++ b/_modules/openeo/rest/connection.html @@ -0,0 +1,2099 @@ + + + + + + + openeo.rest.connection — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.connection

    +"""
    +This module provides a Connection object to manage and persist settings when interacting with the OpenEO API.
    +"""
    +from __future__ import annotations
    +
    +import datetime
    +import json
    +import logging
    +import os
    +import shlex
    +import sys
    +import warnings
    +from collections import OrderedDict
    +from pathlib import Path, PurePosixPath
    +from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Tuple, Union
    +
    +import requests
    +import shapely.geometry.base
    +from requests import Response
    +from requests.auth import AuthBase, HTTPBasicAuth
    +
    +import openeo
    +from openeo.capabilities import ApiVersionException, ComparableVersion
    +from openeo.config import config_log, get_config_option
    +from openeo.internal.documentation import openeo_process
    +from openeo.internal.graph_building import FlatGraphableMixin, PGNode, as_flat_graph
    +from openeo.internal.jupyter import VisualDict, VisualList
    +from openeo.internal.processes.builder import ProcessBuilderBase
    +from openeo.internal.warnings import deprecated, legacy_alias
    +from openeo.metadata import Band, BandDimension, CollectionMetadata, SpatialDimension, TemporalDimension
    +from openeo.rest import (
    +    CapabilitiesException,
    +    OpenEoApiError,
    +    OpenEoClientException,
    +    OpenEoRestError,
    +    OpenEoApiPlainError,
    +)
    +from openeo.rest._datacube import build_child_callback
    +from openeo.rest.auth.auth import BasicBearerAuth, BearerAuth, NullAuth, OidcBearerAuth
    +from openeo.rest.auth.config import AuthConfig, RefreshTokenStore
    +from openeo.rest.auth.oidc import (
    +    DefaultOidcClientGrant,
    +    GrantsChecker,
    +    OidcAuthCodePkceAuthenticator,
    +    OidcAuthenticator,
    +    OidcClientCredentialsAuthenticator,
    +    OidcClientInfo,
    +    OidcDeviceAuthenticator,
    +    OidcException,
    +    OidcProviderInfo,
    +    OidcRefreshTokenAuthenticator,
    +    OidcResourceOwnerPasswordAuthenticator,
    +)
    +from openeo.rest.datacube import DataCube, InputDate
    +from openeo.rest.graph_building import CollectionProperty
    +from openeo.rest.job import BatchJob, RESTJob
    +from openeo.rest.mlmodel import MlModel
    +from openeo.rest.rest_capabilities import RESTCapabilities
    +from openeo.rest.service import Service
    +from openeo.rest.udp import Parameter, RESTUserDefinedProcess
    +from openeo.rest.userfile import UserFile
    +from openeo.rest.vectorcube import VectorCube
    +from openeo.util import (
    +    ContextTimer,
    +    LazyLoadCache,
    +    dict_no_none,
    +    ensure_list,
    +    load_json_resource,
    +    rfc3339,
    +    str_truncate,
    +    url_join,
    +)
    +
    +_log = logging.getLogger(__name__)
    +
    +# Default timeouts for requests
    +# TODO: get default_timeout from config?
    +DEFAULT_TIMEOUT = 20 * 60
    +DEFAULT_TIMEOUT_SYNCHRONOUS_EXECUTE = 30 * 60
    +
    +
    +class RestApiConnection:
    +    """Base connection class implementing generic REST API request functionality"""
    +
    +    def __init__(
    +        self,
    +        root_url: str,
    +        auth: Optional[AuthBase] = None,
    +        session: Optional[requests.Session] = None,
    +        default_timeout: Optional[int] = None,
    +        slow_response_threshold: Optional[float] = None,
    +    ):
    +        self._root_url = root_url
    +        self.auth = auth or NullAuth()
    +        self.session = session or requests.Session()
    +        self.default_timeout = default_timeout or DEFAULT_TIMEOUT
    +        self.default_headers = {
    +            "User-Agent": "openeo-python-client/{cv} {py}/{pv} {pl}".format(
    +                cv=openeo.client_version(),
    +                py=sys.implementation.name, pv=".".join(map(str, sys.version_info[:3])),
    +                pl=sys.platform
    +            )
    +        }
    +        self.slow_response_threshold = slow_response_threshold
    +
    +    @property
    +    def root_url(self):
    +        return self._root_url
    +
    +    def build_url(self, path: str):
    +        return url_join(self._root_url, path)
    +
    +    def _merged_headers(self, headers: dict) -> dict:
    +        """Merge default headers with given headers"""
    +        result = self.default_headers.copy()
    +        if headers:
    +            result.update(headers)
    +        return result
    +
    +    def _is_external(self, url: str) -> bool:
    +        """Check if given url is external (not under root url)"""
    +        root = self.root_url.rstrip("/")
    +        return not (url == root or url.startswith(root + '/'))
    +
    +    def request(
    +        self,
    +        method: str,
    +        path: str,
    +        *,
    +        headers: Optional[dict] = None,
    +        auth: Optional[AuthBase] = None,
    +        check_error: bool = True,
    +        expected_status: Optional[Union[int, Iterable[int]]] = None,
    +        **kwargs,
    +    ):
    +        """Generic request send"""
    +        url = self.build_url(path)
    +        # Don't send default auth headers to external domains.
    +        auth = auth or (self.auth if not self._is_external(url) else None)
    +        slow_response_threshold = kwargs.pop("slow_response_threshold", self.slow_response_threshold)
    +        if _log.isEnabledFor(logging.DEBUG):
    +            _log.debug("Request `{m} {u}` with headers {h}, auth {a}, kwargs {k}".format(
    +                m=method.upper(), u=url, h=headers and headers.keys(), a=type(auth).__name__, k=list(kwargs.keys()))
    +            )
    +        with ContextTimer() as timer:
    +            resp = self.session.request(
    +                method=method,
    +                url=url,
    +                headers=self._merged_headers(headers),
    +                auth=auth,
    +                timeout=kwargs.pop("timeout", self.default_timeout),
    +                **kwargs
    +            )
    +        if slow_response_threshold and timer.elapsed() > slow_response_threshold:
    +            _log.warning("Slow response: `{m} {u}` took {e:.2f}s (>{t:.2f}s)".format(
    +                m=method.upper(), u=str_truncate(url, width=64),
    +                e=timer.elapsed(), t=slow_response_threshold
    +            ))
    +        if _log.isEnabledFor(logging.DEBUG):
    +            _log.debug("Got {r} headers {h!r}".format(r=resp, h=resp.headers))
    +        # Check for API errors and unexpected HTTP status codes as desired.
    +        status = resp.status_code
    +        expected_status = ensure_list(expected_status) if expected_status else []
    +        if check_error and status >= 400 and status not in expected_status:
    +            self._raise_api_error(resp)
    +        if expected_status and status not in expected_status:
    +            raise OpenEoRestError("Got status code {s!r} for `{m} {p}` (expected {e!r}) with body {body}".format(
    +                m=method.upper(), p=path, s=status, e=expected_status, body=resp.text)
    +            )
    +        return resp
    +
    +    def _raise_api_error(self, response: requests.Response):
    +        """Convert API error response to Python exception"""
    +        status_code = response.status_code
    +        try:
    +            # Try parsing the error info according to spec and wrap it in an exception.
    +            info = response.json()
    +            exception = OpenEoApiError(
    +                http_status_code=status_code,
    +                code=info.get("code", "unknown"),
    +                message=info.get("message", "unknown error"),
    +                id=info.get("id"),
    +                url=info.get("url"),
    +            )
    +        except Exception:
    +            # Parsing of error info went wrong: let's see if we can still extract some helpful information.
    +            text = response.text
    +            error_message = None
    +            _log.warning(f"Failed to parse API error response: [{status_code}] {text!r} (headers: {response.headers})")
    +            if status_code == 502 and "Proxy Error" in text:
    +                error_message = (
    +                    "Received 502 Proxy Error."
    +                    " This typically happens when a synchronous openEO processing request takes too long and is aborted."
    +                    " Consider using a batch job instead."
    +                )
    +            exception = OpenEoApiPlainError(message=text, http_status_code=status_code, error_message=error_message)
    +        raise exception
    +
    +    def get(self, path: str, stream: bool = False, auth: Optional[AuthBase] = None, **kwargs) -> Response:
    +        """
    +        Do GET request to REST API.
    +
    +        :param path: API path (without root url)
    +        :param stream: True if the get request should be streamed, else False
    +        :param auth: optional custom authentication to use instead of the default one
    +        :return: response: Response
    +        """
    +        return self.request("get", path=path, stream=stream, auth=auth, **kwargs)
    +
    +    def post(self, path: str, json: Optional[dict] = None, **kwargs) -> Response:
    +        """
    +        Do POST request to REST API.
    +
    +        :param path: API path (without root url)
    +        :param json: Data (as dictionary) to be posted with JSON encoding)
    +        :return: response: Response
    +        """
    +        return self.request("post", path=path, json=json, allow_redirects=False, **kwargs)
    +
    +    def delete(self, path: str, **kwargs) -> Response:
    +        """
    +        Do DELETE request to REST API.
    +
    +        :param path: API path (without root url)
    +        :return: response: Response
    +        """
    +        return self.request("delete", path=path, allow_redirects=False, **kwargs)
    +
    +    def patch(self, path: str, **kwargs) -> Response:
    +        """
    +        Do PATCH request to REST API.
    +
    +        :param path: API path (without root url)
    +        :return: response: Response
    +        """
    +        return self.request("patch", path=path, allow_redirects=False, **kwargs)
    +
    +    def put(self, path: str, headers: Optional[dict] = None, data: Optional[dict] = None, **kwargs) -> Response:
    +        """
    +        Do PUT request to REST API.
    +
    +        :param path: API path (without root url)
    +        :param headers: headers that gets added to the request.
    +        :param data: data that gets added to the request.
    +        :return: response: Response
    +        """
    +        return self.request("put", path=path, data=data, headers=headers, allow_redirects=False, **kwargs)
    +
    +    def __repr__(self):
    +        return "<{c} to {r!r} with {a}>".format(c=type(self).__name__, r=self._root_url, a=type(self.auth).__name__)
    +
    +
    +
    +[docs] +class Connection(RestApiConnection): + """ + Connection to an openEO backend. + """ + + _MINIMUM_API_VERSION = ComparableVersion("1.0.0") + + def __init__( + self, + url: str, + *, + auth: Optional[AuthBase] = None, + session: Optional[requests.Session] = None, + default_timeout: Optional[int] = None, + auth_config: Optional[AuthConfig] = None, + refresh_token_store: Optional[RefreshTokenStore] = None, + slow_response_threshold: Optional[float] = None, + oidc_auth_renewer: Optional[OidcAuthenticator] = None, + auto_validate: bool = True, + ): + """ + Constructor of Connection, authenticates user. + + :param url: String Backend root url + """ + if "://" not in url: + url = "https://" + url + self._orig_url = url + super().__init__( + root_url=self.version_discovery(url, session=session, timeout=default_timeout), + auth=auth, session=session, default_timeout=default_timeout, + slow_response_threshold=slow_response_threshold, + ) + self._capabilities_cache = LazyLoadCache() + + # Initial API version check. + self._api_version.require_at_least(self._MINIMUM_API_VERSION) + + self._auth_config = auth_config + self._refresh_token_store = refresh_token_store + self._oidc_auth_renewer = oidc_auth_renewer + self._auto_validate = auto_validate + +
    +[docs] + @classmethod + def version_discovery( + cls, url: str, session: Optional[requests.Session] = None, timeout: Optional[int] = None + ) -> str: + """ + Do automatic openEO API version discovery from given url, using a "well-known URI" strategy. + + :param url: initial backend url (not including "/.well-known/openeo") + :return: root url of highest supported backend version + """ + try: + connection = RestApiConnection(url, session=session) + well_known_url_response = connection.get("/.well-known/openeo", timeout=timeout) + assert well_known_url_response.status_code == 200 + versions = well_known_url_response.json()["versions"] + supported_versions = [v for v in versions if cls._MINIMUM_API_VERSION <= v["api_version"]] + assert supported_versions + production_versions = [v for v in supported_versions if v.get("production", True)] + highest_version = max(production_versions or supported_versions, key=lambda v: v["api_version"]) + _log.debug("Highest supported version available in backend: %s" % highest_version) + return highest_version['url'] + except Exception: + # Be very lenient about failing on the well-known URI strategy. + return url
    + + + def _get_auth_config(self) -> AuthConfig: + if self._auth_config is None: + self._auth_config = AuthConfig() + return self._auth_config + + def _get_refresh_token_store(self) -> RefreshTokenStore: + if self._refresh_token_store is None: + self._refresh_token_store = RefreshTokenStore() + return self._refresh_token_store + +
    +[docs] + def authenticate_basic(self, username: Optional[str] = None, password: Optional[str] = None) -> Connection: + """ + Authenticate a user to the backend using basic username and password. + + :param username: User name + :param password: User passphrase + """ + if not self.capabilities().supports_endpoint("/credentials/basic", method="GET"): + raise OpenEoClientException("This openEO back-end does not support basic authentication.") + if username is None: + username, password = self._get_auth_config().get_basic_auth(backend=self._orig_url) + if username is None: + raise OpenEoClientException("No username/password given or found.") + + resp = self.get( + '/credentials/basic', + # /credentials/basic is the only endpoint that expects a Basic HTTP auth + auth=HTTPBasicAuth(username, password) + ).json() + # Switch to bearer based authentication in further requests. + self.auth = BasicBearerAuth(access_token=resp["access_token"]) + return self
    + + + def _get_oidc_provider(self, provider_id: Union[str, None] = None) -> Tuple[str, OidcProviderInfo]: + """ + Get OpenID Connect discovery URL for given provider_id + + :param provider_id: id of OIDC provider as specified by backend (/credentials/oidc). + Can be None if there is just one provider. + :return: updated provider_id and provider info object + """ + oidc_info = self.get("/credentials/oidc", expected_status=200).json() + providers = OrderedDict((p["id"], p) for p in oidc_info["providers"]) + if len(providers) < 1: + raise OpenEoClientException("Backend lists no OIDC providers.") + _log.info("Found OIDC providers: {p}".format(p=list(providers.keys()))) + + # TODO: also support specifying provider through issuer URL? + provider_id_from_env = os.environ.get("OPENEO_AUTH_PROVIDER_ID") + + if provider_id: + if provider_id not in providers: + raise OpenEoClientException( + "Requested OIDC provider {r!r} not available. Should be one of {p}.".format( + r=provider_id, p=list(providers.keys()) + ) + ) + provider = providers[provider_id] + elif provider_id_from_env and provider_id_from_env in providers: + _log.info(f"Using provider_id {provider_id_from_env!r} from OPENEO_AUTH_PROVIDER_ID env var") + provider_id = provider_id_from_env + provider = providers[provider_id] + elif len(providers) == 1: + provider_id, provider = providers.popitem() + _log.info( + f"No OIDC provider given, but only one available: {provider_id!r}. Using that one." + ) + else: + # Check if there is a single provider in the config to use. + backend = self._orig_url + provider_configs = self._get_auth_config().get_oidc_provider_configs( + backend=backend + ) + intersection = set(provider_configs.keys()).intersection(providers.keys()) + if len(intersection) == 1: + provider_id = intersection.pop() + provider = providers[provider_id] + _log.info( + f"No OIDC provider given, but only one in config (for backend {backend!r}): {provider_id!r}. Using that one." + ) + else: + provider_id, provider = providers.popitem(last=False) + _log.info( + f"No OIDC provider given. Using first provider {provider_id!r} as advertised by backend." + ) + provider = OidcProviderInfo.from_dict(provider) + return provider_id, provider + + def _get_oidc_provider_and_client_info( + self, + provider_id: str, + client_id: Union[str, None], + client_secret: Union[str, None], + default_client_grant_check: Union[None, GrantsChecker] = None, + ) -> Tuple[str, OidcClientInfo]: + """ + Resolve provider_id and client info (as given or from config) + + :param provider_id: id of OIDC provider as specified by backend (/credentials/oidc). + Can be None if there is just one provider. + + :return: OIDC provider id and client info + """ + provider_id, provider = self._get_oidc_provider(provider_id) + + if client_id is None: + _log.debug("No client_id: checking config for preferred client_id") + client_id, client_secret = self._get_auth_config().get_oidc_client_configs( + backend=self._orig_url, provider_id=provider_id + ) + if client_id: + _log.info("Using client_id {c!r} from config (provider {p!r})".format(c=client_id, p=provider_id)) + if client_id is None and default_client_grant_check: + # Try "default_clients" from backend's provider info. + _log.debug("No client_id given: checking default clients in backend's provider info") + client_id = provider.get_default_client_id(grant_check=default_client_grant_check) + if client_id: + _log.info("Using default client_id {c!r} from OIDC provider {p!r} info.".format( + c=client_id, p=provider_id + )) + if client_id is None: + raise OpenEoClientException("No client_id found.") + + client_info = OidcClientInfo(client_id=client_id, client_secret=client_secret, provider=provider) + + return provider_id, client_info + + def _authenticate_oidc( + self, + authenticator: OidcAuthenticator, + *, + provider_id: str, + store_refresh_token: bool = False, + fallback_refresh_token_to_store: Optional[str] = None, + oidc_auth_renewer: Optional[OidcAuthenticator] = None, + ) -> Connection: + """ + Authenticate through OIDC and set up bearer token (based on OIDC access_token) for further requests. + """ + tokens = authenticator.get_tokens(request_refresh_token=store_refresh_token) + _log.info("Obtained tokens: {t}".format(t=[k for k, v in tokens._asdict().items() if v])) + if store_refresh_token: + refresh_token = tokens.refresh_token or fallback_refresh_token_to_store + if refresh_token: + self._get_refresh_token_store().set_refresh_token( + issuer=authenticator.provider_info.issuer, + client_id=authenticator.client_id, + refresh_token=refresh_token + ) + if not oidc_auth_renewer: + oidc_auth_renewer = OidcRefreshTokenAuthenticator( + client_info=authenticator.client_info, refresh_token=refresh_token + ) + else: + _log.warning("No OIDC refresh token to store.") + token = tokens.access_token + self.auth = OidcBearerAuth(provider_id=provider_id, access_token=token) + self._oidc_auth_renewer = oidc_auth_renewer + return self + +
    +[docs] + def authenticate_oidc_authorization_code( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + timeout: Optional[int] = None, + server_address: Optional[Tuple[str, int]] = None, + webbrowser_open: Optional[Callable] = None, + store_refresh_token=False, + ) -> Connection: + """ + OpenID Connect Authorization Code Flow (with PKCE). + + .. deprecated:: 0.19.0 + Usage of the Authorization Code flow is deprecated (because of its complexity) and will be removed. + It is recommended to use the Device Code flow with :py:meth:`authenticate_oidc_device` + or Client Credentials flow with :py:meth:`authenticate_oidc_client_credentials`. + """ + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=[DefaultOidcClientGrant.AUTH_CODE_PKCE], + ) + authenticator = OidcAuthCodePkceAuthenticator( + client_info=client_info, + webbrowser_open=webbrowser_open, timeout=timeout, server_address=server_address + ) + return self._authenticate_oidc(authenticator, provider_id=provider_id, store_refresh_token=store_refresh_token)
    + + +
    +[docs] + def authenticate_oidc_client_credentials( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + ) -> Connection: + """ + Authenticate with :ref:`OIDC Client Credentials flow <authenticate_oidc_client_credentials>` + + Client id, secret and provider id can be specified directly through the available arguments. + It is also possible to leave these arguments empty and specify them through + environment variables ``OPENEO_AUTH_CLIENT_ID``, + ``OPENEO_AUTH_CLIENT_SECRET`` and ``OPENEO_AUTH_PROVIDER_ID`` respectively + as discussed in :ref:`authenticate_oidc_client_credentials_env_vars`. + + :param client_id: client id to use + :param client_secret: client secret to use + :param provider_id: provider id to use + Fallback value can be set through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + + .. versionchanged:: 0.18.0 Allow specifying client id, secret and provider id through environment variables. + """ + # TODO: option to get client id/secret from a config file too? + if client_id is None and "OPENEO_AUTH_CLIENT_ID" in os.environ and "OPENEO_AUTH_CLIENT_SECRET" in os.environ: + client_id = os.environ.get("OPENEO_AUTH_CLIENT_ID") + client_secret = os.environ.get("OPENEO_AUTH_CLIENT_SECRET") + _log.debug(f"Getting client id ({client_id}) and secret from environment") + + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret + ) + authenticator = OidcClientCredentialsAuthenticator(client_info=client_info) + return self._authenticate_oidc( + authenticator, provider_id=provider_id, store_refresh_token=False, oidc_auth_renewer=authenticator + )
    + + +
    +[docs] + def authenticate_oidc_resource_owner_password_credentials( + self, + username: str, + password: str, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + store_refresh_token: bool = False, + ) -> Connection: + """ + OpenId Connect Resource Owner Password Credentials + """ + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret + ) + # TODO: also get username and password from config? + authenticator = OidcResourceOwnerPasswordAuthenticator( + client_info=client_info, username=username, password=password + ) + return self._authenticate_oidc(authenticator, provider_id=provider_id, store_refresh_token=store_refresh_token)
    + + +
    +[docs] + def authenticate_oidc_refresh_token( + self, + client_id: Optional[str] = None, + refresh_token: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + *, + store_refresh_token: bool = False, + ) -> Connection: + """ + Authenticate with :ref:`OIDC Refresh Token flow <authenticate_oidc_client_credentials>` + + :param client_id: client id to use + :param refresh_token: refresh token to use + :param client_secret: client secret to use + :param provider_id: provider id to use. + Fallback value can be set through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + :param store_refresh_token: whether to store the received refresh token automatically + + .. versionchanged:: 0.19.0 Support fallback provider id through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + """ + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=[DefaultOidcClientGrant.REFRESH_TOKEN], + ) + + if refresh_token is None: + refresh_token = self._get_refresh_token_store().get_refresh_token( + issuer=client_info.provider.issuer, + client_id=client_info.client_id + ) + if refresh_token is None: + raise OpenEoClientException("No refresh token given or found") + + authenticator = OidcRefreshTokenAuthenticator(client_info=client_info, refresh_token=refresh_token) + return self._authenticate_oidc( + authenticator, + provider_id=provider_id, + store_refresh_token=store_refresh_token, + fallback_refresh_token_to_store=refresh_token, + oidc_auth_renewer=authenticator, + )
    + + +
    +[docs] + def authenticate_oidc_device( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + *, + store_refresh_token: bool = False, + use_pkce: Optional[bool] = None, + max_poll_time: float = OidcDeviceAuthenticator.DEFAULT_MAX_POLL_TIME, + **kwargs, + ) -> Connection: + """ + Authenticate with the :ref:`OIDC Device Code flow <authenticate_oidc_device>` + + :param client_id: client id to use instead of the default one + :param client_secret: client secret to use instead of the default one + :param provider_id: provider id to use. + Fallback value can be set through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + :param store_refresh_token: whether to store the received refresh token automatically + :param use_pkce: Use PKCE instead of client secret. + If not set explicitly to `True` (use PKCE) or `False` (use client secret), + it will be attempted to detect the best mode automatically. + Note that PKCE for device code is not widely supported among OIDC providers. + :param max_poll_time: maximum time in seconds to keep polling for successful authentication. + + .. versionchanged:: 0.5.1 Add :py:obj:`use_pkce` argument + .. versionchanged:: 0.17.0 Add :py:obj:`max_poll_time` argument + .. versionchanged:: 0.19.0 Support fallback provider id through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + """ + _g = DefaultOidcClientGrant # alias for compactness + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=(lambda grants: _g.DEVICE_CODE in grants or _g.DEVICE_CODE_PKCE in grants), + ) + authenticator = OidcDeviceAuthenticator( + client_info=client_info, use_pkce=use_pkce, max_poll_time=max_poll_time, **kwargs + ) + return self._authenticate_oidc(authenticator, provider_id=provider_id, store_refresh_token=store_refresh_token)
    + + +
    +[docs] + def authenticate_oidc( + self, + provider_id: Optional[str] = None, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + *, + store_refresh_token: bool = True, + use_pkce: Optional[bool] = None, + display: Callable[[str], None] = print, + max_poll_time: float = OidcDeviceAuthenticator.DEFAULT_MAX_POLL_TIME, + ): + """ + Generic method to do OpenID Connect authentication. + + In the context of interactive usage, this method first tries to use refresh tokens + and falls back on device code flow. + + For non-interactive, machine-to-machine contexts, it is also possible to trigger + the usage of the "client_credentials" flow through environment variables. + Assuming you have set up a OIDC client (with a secret): + set ``OPENEO_AUTH_METHOD`` to ``client_credentials``, + set ``OPENEO_AUTH_CLIENT_ID`` to the client id, + and set ``OPENEO_AUTH_CLIENT_SECRET`` to the client secret. + + See :ref:`authenticate_oidc_automatic` for more details. + + :param provider_id: provider id to use + :param client_id: client id to use + :param client_secret: client secret to use + :param max_poll_time: maximum time in seconds to keep polling for successful authentication. + + .. versionadded:: 0.6.0 + .. versionchanged:: 0.17.0 Add :py:obj:`max_poll_time` argument + .. versionchanged:: 0.18.0 Add support for client credentials flow. + """ + # TODO: unify `os.environ.get` with `get_config_option`? + # TODO also support OPENEO_AUTH_CLIENT_ID, ... env vars for refresh token and device code auth? + + auth_method = os.environ.get("OPENEO_AUTH_METHOD") + if auth_method == "client_credentials": + _log.debug("authenticate_oidc: going for 'client_credentials' authentication") + return self.authenticate_oidc_client_credentials( + client_id=client_id, client_secret=client_secret, provider_id=provider_id + ) + elif auth_method: + raise ValueError(f"Unhandled auth method {auth_method}") + + _g = DefaultOidcClientGrant # alias for compactness + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=lambda grants: ( + _g.REFRESH_TOKEN in grants and (_g.DEVICE_CODE in grants or _g.DEVICE_CODE_PKCE in grants) + ) + ) + + # Try refresh token first. + refresh_token = self._get_refresh_token_store().get_refresh_token( + issuer=client_info.provider.issuer, + client_id=client_info.client_id + ) + if refresh_token: + try: + _log.info("Found refresh token: trying refresh token based authentication.") + authenticator = OidcRefreshTokenAuthenticator(client_info=client_info, refresh_token=refresh_token) + con = self._authenticate_oidc( + authenticator, + provider_id=provider_id, + store_refresh_token=store_refresh_token, + fallback_refresh_token_to_store=refresh_token, + ) + # TODO: pluggable/jupyter-aware display function? + print("Authenticated using refresh token.") + return con + except OidcException as e: + _log.info("Refresh token based authentication failed: {e}.".format(e=e)) + + # Fall back on device code flow + # TODO: make it possible to do other fallback flows too? + _log.info("Trying device code flow.") + authenticator = OidcDeviceAuthenticator( + client_info=client_info, use_pkce=use_pkce, display=display, max_poll_time=max_poll_time + ) + con = self._authenticate_oidc( + authenticator, + provider_id=provider_id, + store_refresh_token=store_refresh_token, + ) + print("Authenticated using device code flow.") + return con
    + + +
    +[docs] + def request( + self, + method: str, + path: str, + headers: Optional[dict] = None, + auth: Optional[AuthBase] = None, + check_error: bool = True, + expected_status: Optional[Union[int, Iterable[int]]] = None, + **kwargs, + ): + # Do request, but with retry when access token has expired and refresh token is available. + def _request(): + return super(Connection, self).request( + method=method, path=path, headers=headers, auth=auth, + check_error=check_error, expected_status=expected_status, **kwargs, + ) + + try: + # Initial request attempt + return _request() + except OpenEoApiError as api_exc: + if api_exc.http_status_code in {401, 403} and api_exc.code == "TokenInvalid": + # Auth token expired: can we refresh? + if isinstance(self.auth, OidcBearerAuth) and self._oidc_auth_renewer: + msg = f"OIDC access token expired ({api_exc.http_status_code} {api_exc.code})." + try: + self._authenticate_oidc( + authenticator=self._oidc_auth_renewer, + provider_id=self._oidc_auth_renewer.provider_info.id, + store_refresh_token=False, + oidc_auth_renewer=self._oidc_auth_renewer, + ) + _log.info(f"{msg} Obtained new access token (grant {self._oidc_auth_renewer.grant_type!r}).") + except OpenEoClientException as auth_exc: + _log.error( + f"{msg} Failed to obtain new access token (grant {self._oidc_auth_renewer.grant_type!r}): {auth_exc!r}." + ) + else: + # Retry request. + return _request() + raise
    + + +
    +[docs] + def describe_account(self) -> dict: + """ + Describes the currently authenticated user account. + """ + return self.get('/me', expected_status=200).json()
    + + +
    +[docs] + @deprecated("use :py:meth:`list_jobs` instead", version="0.4.10") + def user_jobs(self) -> List[dict]: + return self.list_jobs()
    + + +
    +[docs] + def list_collections(self) -> List[dict]: + """ + List basic metadata of all collections provided by the back-end. + + .. caution:: + + Only the basic collection metadata will be returned. + To obtain full metadata of a particular collection, + it is recommended to use :py:meth:`~openeo.rest.connection.Connection.describe_collection` instead. + + :return: list of dictionaries with basic collection metadata. + """ + # TODO: add caching #383 + data = self.get('/collections', expected_status=200).json()["collections"] + return VisualList("collections", data=data)
    + + +
    +[docs] + def list_collection_ids(self) -> List[str]: + """ + List all collection ids provided by the back-end. + + .. seealso:: + + :py:meth:`~openeo.rest.connection.Connection.describe_collection` + to get the metadata of a particular collection. + + :return: list of collection ids + """ + return [collection['id'] for collection in self.list_collections() if 'id' in collection]
    + + +
    +[docs] + def capabilities(self) -> RESTCapabilities: + """ + Loads all available capabilities. + """ + return self._capabilities_cache.get( + "capabilities", + load=lambda: RESTCapabilities(data=self.get('/', expected_status=200).json(), url=self._orig_url) + )
    + + + def list_input_formats(self) -> dict: + return self.list_file_formats().get("input", {}) + + def list_output_formats(self) -> dict: + return self.list_file_formats().get("output", {}) + + list_file_types = legacy_alias( + list_output_formats, "list_file_types", since="0.4.6" + ) + +
    +[docs] + def list_file_formats(self) -> dict: + """ + Get available input and output formats + """ + formats = self._capabilities_cache.get( + key="file_formats", + load=lambda: self.get('/file_formats', expected_status=200).json() + ) + return VisualDict("file-formats", data=formats)
    + + +
    +[docs] + def list_service_types(self) -> dict: + """ + Loads all available service types. + + :return: data_dict: Dict All available service types + """ + types = self._capabilities_cache.get( + key="service_types", + load=lambda: self.get('/service_types', expected_status=200).json() + ) + return VisualDict("service-types", data=types)
    + + +
    +[docs] + def list_udf_runtimes(self) -> dict: + """ + Loads all available UDF runtimes. + + :return: data_dict: Dict All available UDF runtimes + """ + runtimes = self._capabilities_cache.get( + key="udf_runtimes", + load=lambda: self.get('/udf_runtimes', expected_status=200).json() + ) + return VisualDict("udf-runtimes", data=runtimes)
    + + +
    +[docs] + def list_services(self) -> dict: + """ + Loads all available services of the authenticated user. + + :return: data_dict: Dict All available services + """ + # TODO return parsed service objects + services = self.get('/services', expected_status=200).json()["services"] + return VisualList("data-table", data=services, parameters={'columns': 'services'})
    + + +
    +[docs] + def describe_collection(self, collection_id: str) -> dict: + """ + Get full collection metadata for given collection id. + + .. seealso:: + + :py:meth:`~openeo.rest.connection.Connection.list_collection_ids` + to list all collection ids provided by the back-end. + + :param collection_id: collection id + :return: collection metadata. + """ + # TODO: duplication with `Connection.collection_metadata`: deprecate one or the other? + # TODO: add caching #383 + data = self.get(f"/collections/{collection_id}", expected_status=200).json() + return VisualDict("collection", data=data)
    + + +
    +[docs] + def collection_items( + self, + name, + spatial_extent: Optional[List[float]] = None, + temporal_extent: Optional[List[Union[str, datetime.datetime]]] = None, + limit: Optional[int] = None, + ) -> Iterator[dict]: + """ + Loads items for a specific image collection. + May not be available for all collections. + + This is an experimental API and is subject to change. + + :param name: String Id of the collection + :param spatial_extent: Limits the items to the given bounding box in WGS84: + 1. Lower left corner, coordinate axis 1 + 2. Lower left corner, coordinate axis 2 + 3. Upper right corner, coordinate axis 1 + 4. Upper right corner, coordinate axis 2 + + :param temporal_extent: Limits the items to the specified temporal interval. + :param limit: The amount of items per request/page. If None, the back-end decides. + The interval has to be specified as an array with exactly two elements (start, end). + Also supports open intervals by setting one of the boundaries to None, but never both. + + :return: data_list: List A list of items + """ + url = '/collections/{}/items'.format(name) + params = {} + if spatial_extent: + params["bbox"] = ",".join(str(c) for c in spatial_extent) + if temporal_extent: + params["datetime"] = "/".join(".." if t is None else rfc3339.normalize(t) for t in temporal_extent) + if limit is not None and limit > 0: + params['limit'] = limit + + return paginate(self, url, params, lambda response, page: VisualDict("items", data = response, parameters = {'show-map': True, 'heading': 'Page {} - Items'.format(page)}))
    + + + def collection_metadata(self, name) -> CollectionMetadata: + # TODO: duplication with `Connection.describe_collection`: deprecate one or the other? + return CollectionMetadata(metadata=self.describe_collection(name)) + +
    +[docs] + def list_processes(self, namespace: Optional[str] = None) -> List[dict]: + # TODO: Maybe format the result dictionary so that the process_id is the key of the dictionary. + """ + Loads all available processes of the back end. + + :param namespace: The namespace for which to list processes. + + :return: processes_dict: Dict All available processes of the back end. + """ + if namespace is None: + processes = self._capabilities_cache.get( + key=("processes", "backend"), + load=lambda: self.get('/processes', expected_status=200).json()["processes"] + ) + else: + processes = self.get('/processes/' + namespace, expected_status=200).json()["processes"] + return VisualList("processes", data=processes, parameters={'show-graph': True, 'provide-download': False})
    + + +
    +[docs] + def describe_process(self, id: str, namespace: Optional[str] = None) -> dict: + """ + Returns a single process from the back end. + + :param id: The id of the process. + :param namespace: The namespace of the process. + + :return: The process definition. + """ + + processes = self.list_processes(namespace) + for process in processes: + if process["id"] == id: + return VisualDict("process", data=process, parameters={'show-graph': True, 'provide-download': False}) + + raise OpenEoClientException("Process does not exist.")
    + + +
    +[docs] + def list_jobs(self) -> List[dict]: + """ + Lists all jobs of the authenticated user. + + :return: job_list: Dict of all jobs of the user. + """ + # TODO: Parse the result so that there get Job classes returned? + resp = self.get('/jobs', expected_status=200).json() + if resp.get("federation:missing"): + _log.warning("Partial user job listing due to missing federation components: {c}".format( + c=",".join(resp["federation:missing"]) + )) + jobs = resp["jobs"] + return VisualList("data-table", data=jobs, parameters={'columns': 'jobs'})
    + + +
    +[docs] + def assert_user_defined_process_support(self): + """ + Capabilities document based verification that back-end supports user-defined processes. + + .. versionadded:: 0.23.0 + """ + if not self.capabilities().supports_endpoint("/process_graphs"): + raise CapabilitiesException("Backend does not support user-defined processes.")
    + + +
    +[docs] + def save_user_defined_process( + self, user_defined_process_id: str, + process_graph: Union[dict, ProcessBuilderBase], + parameters: List[Union[dict, Parameter]] = None, + public: bool = False, + summary: Optional[str] = None, + description: Optional[str] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, + ) -> RESTUserDefinedProcess: + """ + Store a process graph and its metadata on the backend as a user-defined process for the authenticated user. + + :param user_defined_process_id: unique identifier for the user-defined process + :param process_graph: a process graph + :param parameters: a list of parameters + :param public: visible to other users? + :param summary: A short summary of what the process does. + :param description: Detailed description to explain the entity. CommonMark 0.29 syntax MAY be used for rich text representation. + :param returns: Description and schema of the return value. + :param categories: A list of categories. + :param examples: A list of examples. + :param links: A list of links. + :return: a RESTUserDefinedProcess instance + """ + self.assert_user_defined_process_support() + if user_defined_process_id in set(p["id"] for p in self.list_processes()): + warnings.warn("Defining user-defined process {u!r} with same id as a pre-defined process".format( + u=user_defined_process_id)) + if not parameters: + warnings.warn("Defining user-defined process {u!r} without parameters".format(u=user_defined_process_id)) + udp = RESTUserDefinedProcess(user_defined_process_id=user_defined_process_id, connection=self) + udp.store( + process_graph=process_graph, parameters=parameters, public=public, + summary=summary, description=description, + returns=returns, categories=categories, examples=examples, links=links + ) + return udp
    + + +
    +[docs] + def list_user_defined_processes(self) -> List[dict]: + """ + Lists all user-defined processes of the authenticated user. + """ + self.assert_user_defined_process_support() + data = self.get("/process_graphs", expected_status=200).json()["processes"] + return VisualList("processes", data=data, parameters={'show-graph': True, 'provide-download': False})
    + + +
    +[docs] + def user_defined_process(self, user_defined_process_id: str) -> RESTUserDefinedProcess: + """ + Get the user-defined process based on its id. The process with the given id should already exist. + + :param user_defined_process_id: the id of the user-defined process + :return: a RESTUserDefinedProcess instance + """ + return RESTUserDefinedProcess(user_defined_process_id=user_defined_process_id, connection=self)
    + + +
    +[docs] + def validate_process_graph(self, process_graph: dict) -> List[dict]: + """ + Validate a process graph without executing it. + + :param process_graph: (flat) dict representing process graph + :return: list of errors (dictionaries with "code" and "message" fields) + """ + pg_with_metadata = self._build_request_with_process_graph(process_graph)["process"] + return self.post(path="/validation", json=pg_with_metadata, expected_status=200).json()["errors"]
    + + + @property + def _api_version(self) -> ComparableVersion: + # TODO make this a public property (it's also useful outside the Connection class) + return self.capabilities().api_version_check + +
    +[docs] + def vectorcube_from_paths( + self, paths: List[str], format: str, options: dict = {} + ) -> VectorCube: + """ + Loads one or more files referenced by url or path that is accessible by the backend. + + :param paths: The files to read. + :param format: The file format to read from. It must be one of the values that the server reports as supported input file formats. + :param options: The file format parameters to be used to read the files. Must correspond to the parameters that the server reports as supported parameters for the chosen format. + + :return: A :py:class:`VectorCube`. + + .. versionadded:: 0.14.0 + """ + # TODO #457 deprecate this in favor of `load_url` and standard support for `load_uploaded_files` + graph = PGNode( + "load_uploaded_files", + arguments=dict(paths=paths, format=format, options=options), + ) + # TODO: load_uploaded_files might also return a raster data cube. Determine this based on format? + return VectorCube(graph=graph, connection=self)
    + + +
    +[docs] + def datacube_from_process(self, process_id: str, namespace: Optional[str] = None, **kwargs) -> DataCube: + """ + Load a data cube from a (custom) process. + + :param process_id: The process id. + :param namespace: optional: process namespace + :param kwargs: The arguments of the custom process + :return: A :py:class:`DataCube`, without valid metadata, as the client is not aware of this custom process. + """ + graph = PGNode(process_id, namespace=namespace, arguments=kwargs) + return DataCube(graph=graph, connection=self)
    + + +
    +[docs] + def datacube_from_flat_graph(self, flat_graph: dict, parameters: Optional[dict] = None) -> DataCube: + """ + Construct a :py:class:`DataCube` from a flat dictionary representation of a process graph. + + :param flat_graph: flat dictionary representation of a process graph + or a process dictionary with such a flat process graph under a "process_graph" field + (and optionally parameter metadata under a "parameters" field). + :return: A :py:class:`DataCube` corresponding with the operations encoded in the process graph + """ + parameters = parameters or {} + + if "process_graph" in flat_graph: + # `flat_graph` is a "process" structure + # Extract defaults from declared parameters. + for param in flat_graph.get("parameters") or []: + if "default" in param: + parameters.setdefault(param["name"], param["default"]) + + flat_graph = flat_graph["process_graph"] + + pgnode = PGNode.from_flat_graph(flat_graph=flat_graph, parameters=parameters or {}) + return DataCube(graph=pgnode, connection=self)
    + + +
    +[docs] + def datacube_from_json(self, src: Union[str, Path], parameters: Optional[dict] = None) -> DataCube: + """ + Construct a :py:class:`DataCube` from JSON resource containing (flat) process graph representation. + + :param src: raw JSON string, URL to JSON resource or path to local JSON file + :return: A :py:class:`DataCube` corresponding with the operations encoded in the process graph + """ + return self.datacube_from_flat_graph(load_json_resource(src), parameters=parameters)
    + + +
    +[docs] + @openeo_process + def load_collection( + self, + collection_id: Union[str, Parameter], + spatial_extent: Union[Dict[str, float], Parameter, None] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Union[None, List[str], Parameter] = None, + properties: Union[ + None, Dict[str, Union[str, PGNode, Callable]], List[CollectionProperty], CollectionProperty + ] = None, + max_cloud_cover: Optional[float] = None, + fetch_metadata=True, + ) -> DataCube: + """ + Load a DataCube by collection id. + + :param collection_id: image collection identifier + :param spatial_extent: limit data to specified bounding box or polygons + :param temporal_extent: limit data to specified temporal interval. + Typically, just a two-item list or tuple containing start and end date. + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + :param bands: only add the specified bands. + :param properties: limit data by collection metadata property predicates. + See :py:func:`~openeo.rest.graph_building.collection_property` for easy construction of such predicates. + :param max_cloud_cover: shortcut to set maximum cloud cover ("eo:cloud_cover" collection property) + :return: a datacube containing the requested data + + .. versionadded:: 0.13.0 + added the ``max_cloud_cover`` argument. + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + + .. versionchanged:: 0.26.0 + Add :py:func:`~openeo.rest.graph_building.collection_property` support to ``properties`` argument. + """ + return DataCube.load_collection( + collection_id=collection_id, + connection=self, + spatial_extent=spatial_extent, + temporal_extent=temporal_extent, + bands=bands, + properties=properties, + max_cloud_cover=max_cloud_cover, + fetch_metadata=fetch_metadata, + )
    + + + # TODO: remove this #100 #134 0.4.10 + imagecollection = legacy_alias( + load_collection, name="imagecollection", since="0.4.10" + ) + +
    +[docs] + @openeo_process + def load_result( + self, + id: str, + spatial_extent: Optional[Dict[str, float]] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Optional[List[str]] = None, + ) -> DataCube: + """ + 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. + + :param id: The id of a batch job with results. + :param spatial_extent: limit data to specified bounding box or polygons + :param temporal_extent: limit data to specified temporal interval. + Typically, just a two-item list or tuple containing start and end date. + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + :param bands: only add the specified bands + + :return: a :py:class:`DataCube` + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + """ + # TODO: add check that back-end supports `load_result` process? + cube = self.datacube_from_process( + process_id="load_result", + id=id, + **dict_no_none( + spatial_extent=spatial_extent, + temporal_extent=temporal_extent and DataCube._get_temporal_extent(extent=temporal_extent), + bands=bands, + ), + ) + return cube
    + + +
    +[docs] + @openeo_process + def load_stac( + self, + url: str, + spatial_extent: Optional[Dict[str, float]] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Optional[List[str]] = None, + properties: Optional[Dict[str, Union[str, PGNode, Callable]]] = None, + ) -> DataCube: + """ + Loads data from a static STAC catalog or a STAC API Collection and returns the data as a processable :py:class:`DataCube`. + A batch job result can be loaded by providing a reference to it. + + If supported by the underlying metadata and file format, the data that is added to the data cube can be + restricted with the parameters ``spatial_extent``, ``temporal_extent`` and ``bands``. + If no data is available for the given extents, a ``NoDataAvailable`` error is thrown. + + Remarks: + + * 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``. + * 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 values should be processed only after the data has been limited to the required extent + and as a consequence also to a manageable size. + + + :param url: The URL to a static STAC catalog (STAC Item, STAC Collection, or STAC Catalog) + or a specific STAC API Collection that allows to filter items and to download assets. + This includes batch job results, which itself are compliant to STAC. + For external URLs, authentication details such as API keys or tokens may need to be included in the URL. + + Batch job results can be specified in two ways: + + - For Batch job results at the same back-end, a URL pointing to the corresponding batch job results + endpoint should be provided. The URL usually ends with ``/jobs/{id}/results`` and ``{id}`` + is the corresponding batch job ID. + - For external results, a signed URL must be provided. Not all back-ends support signed URLs, + which are provided as a link with the link relation `canonical` in the batch job result metadata. + :param spatial_extent: + Limits the data to load to the specified bounding box or polygons. + + For raster data, the process loads the pixel into the data cube if the point at the pixel center intersects + with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). + + For vector data, the process loads the geometry into the data cube if the geometry is fully within the + bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). + Empty geometries may only be in the data cube if no spatial extent has been provided. + + The GeoJSON can be one of the following feature types: + + * A ``Polygon`` or ``MultiPolygon`` geometry, + * a ``Feature`` with a ``Polygon`` or ``MultiPolygon`` geometry, or + * a ``FeatureCollection`` containing at least one ``Feature`` with ``Polygon`` or ``MultiPolygon`` geometries. + + Set this parameter to ``None`` 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. + + :param temporal_extent: + Limits the data to load 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: + + 1. The first element is the start of the temporal interval. + The specified instance in time is **included** in the interval. + 2. The second element is the end of the temporal interval. + The specified instance in time is **excluded** from the interval. + + The second element must always be greater/later than the first element. + Otherwise, a `TemporalExtentEmpty` exception is thrown. + + Also supports open intervals by setting one of the boundaries to ``None``, but never both. + + Set this parameter to ``None`` 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. + + :param bands: + 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`. + + Either 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. + + The 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. + + It is recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded data. + + :param properties: + Limits the data by metadata properties to include only data in the data cube which + all given conditions return ``True`` for (AND operation). + + Specify key-value-pairs with the key being the name of the metadata property, + which can be retrieved with the openEO Data Discovery for Collections. + The value must be a condition (user-defined process) to be evaluated against a STAC API. + This parameter is not supported for static STAC. + + .. versionadded:: 0.17.0 + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + """ + # TODO #425 move this implementation to `DataCube` and just forward here (like with `load_collection`) + # TODO #425 detect actual metadata from URL + arguments = {"url": url} + # TODO #425 more normalization/validation of extent/band parameters + if spatial_extent: + arguments["spatial_extent"] = spatial_extent + if temporal_extent: + arguments["temporal_extent"] = DataCube._get_temporal_extent(extent=temporal_extent) + if bands: + arguments["bands"] = bands + if properties: + arguments["properties"] = { + prop: build_child_callback(pred, parent_parameters=["value"]) for prop, pred in properties.items() + } + cube = self.datacube_from_process(process_id="load_stac", **arguments) + return cube
    + + +
    +[docs] + def load_ml_model(self, id: Union[str, BatchJob]) -> MlModel: + """ + Loads a machine learning model from a STAC Item. + + :param id: STAC item reference, as URL, batch job (id) or user-uploaded file + :return: + + .. versionadded:: 0.10.0 + """ + return MlModel.load_ml_model(connection=self, id=id)
    + + +
    +[docs] + @openeo_process + def load_geojson( + self, + data: Union[dict, str, Path, shapely.geometry.base.BaseGeometry, Parameter], + properties: Optional[List[str]] = None, + ): + """ + Converts GeoJSON data as defined by RFC 7946 into a vector data cube. + + :param data: the geometry to load. One of: + + - GeoJSON-style data structure: e.g. a dictionary with ``"type": "Polygon"`` and ``"coordinates"`` fields + - a path to a local GeoJSON file + - a GeoJSON string + - a shapely geometry object + + :param properties: A list of properties from the GeoJSON file to construct an additional dimension from. + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + return VectorCube.load_geojson(connection=self, data=data, properties=properties)
    + + +
    +[docs] + @openeo_process + def load_url(self, url: str, format: str, options: Optional[dict] = None): + """ + Loads a file from a URL + + :param url: The URL to read from. Authentication details such as API keys or tokens may need to be included in the URL. + :param format: The file format to use when loading the data. + :param options: The file format parameters to use when reading the data. + Must correspond to the parameters that the server reports as supported parameters for the chosen ``format`` + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + if format not in self.list_input_formats(): + # TODO: make this an error? + _log.warning(f"Format {format!r} not listed in back-end input formats") + # TODO: Inspect format's gis_data_type to see if we need to load a VectorCube or classic raster DataCube + return VectorCube.load_url(connection=self, url=url, format=format, options=options)
    + + + def create_service(self, graph: dict, type: str, **kwargs) -> Service: + # TODO: type hint for graph: is it a nested or a flat one? + pg_with_metadata = self._build_request_with_process_graph(process_graph=graph, type=type, **kwargs) + self._preflight_validation(pg_with_metadata=pg_with_metadata) + response = self.post(path="/services", json=pg_with_metadata, expected_status=201) + service_id = response.headers.get("OpenEO-Identifier") + return Service(service_id, self) + +
    +[docs] + @deprecated("Use :py:meth:`openeo.rest.service.Service.delete_service` instead.", version="0.8.0") + def remove_service(self, service_id: str): + """ + Stop and remove a secondary web service. + + :param service_id: service identifier + :return: + """ + Service(service_id, self).delete_service()
    + + +
    +[docs] + @deprecated("Use :py:meth:`openeo.rest.job.BatchJob.get_results` instead.", version="0.4.10") + def job_results(self, job_id) -> dict: + """Get batch job results metadata.""" + return BatchJob(job_id=job_id, connection=self).list_results()
    + + +
    +[docs] + @deprecated("Use :py:meth:`openeo.rest.job.BatchJob.logs` instead.", version="0.4.10") + def job_logs(self, job_id, offset) -> list: + """Get batch job logs.""" + return BatchJob(job_id=job_id, connection=self).logs(offset=offset)
    + + +
    +[docs] + def list_files(self) -> List[UserFile]: + """ + Lists all user-uploaded files in the user workspace on the back-end. + + :return: List of the user-uploaded files. + """ + files = self.get('/files', expected_status=200).json()['files'] + files = [UserFile.from_metadata(metadata=f, connection=self) for f in files] + return VisualList("data-table", data=files, parameters={'columns': 'files'})
    + + +
    +[docs] + def get_file( + self, path: Union[str, PurePosixPath], metadata: Optional[dict] = None + ) -> UserFile: + """ + Gets a handle to a user-uploaded file in the user workspace on the back-end. + + :param path: The path on the user workspace. + """ + return UserFile(path=path, connection=self, metadata=metadata)
    + + +
    +[docs] + def upload_file( + self, + source: Union[Path, str], + target: Optional[Union[str, PurePosixPath]] = None, + ) -> UserFile: + """ + Uploads a file to the given target location in the user workspace on the back-end. + + If a file at the target path exists in the user workspace it will be replaced. + + :param source: A path to a file on the local file system to upload. + :param target: The desired path (which can contain a folder structure if desired) on the user workspace. + If not set: defaults to the original filename (without any folder structure) of the local file . + """ + source = Path(source) + target = target or source.name + # TODO: support other non-path sources too: bytes, open file, url, ... + with source.open("rb") as f: + resp = self.put(f"/files/{target!s}", expected_status=200, data=f) + metadata = resp.json() + return UserFile.from_metadata(metadata=metadata, connection=self)
    + + + def _build_request_with_process_graph(self, process_graph: Union[dict, FlatGraphableMixin, Any], **kwargs) -> dict: + """ + Prepare a json payload with a process graph to submit to /result, /services, /jobs, ... + :param process_graph: flat dict representing a "process graph with metadata" ({"process": {"process_graph": ...}, ...}) + """ + # TODO: make this a more general helper (like `as_flat_graph`) + result = kwargs + process_graph = as_flat_graph(process_graph) + if "process_graph" not in process_graph: + process_graph = {"process_graph": process_graph} + # TODO: also check if `process_graph` already has "process" key (i.e. is a "process graph with metadata" already) + result["process"] = process_graph + return result + + def _preflight_validation(self, pg_with_metadata: dict, *, validate: Optional[bool] = None): + """ + Preflight validation of process graph to execute. + + :param pg_with_metadata: flat dict representation of process graph with metadata, + e.g. as produced by `_build_request_with_process_graph` + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: + """ + if validate is None: + validate = self._auto_validate + if validate and self.capabilities().supports_endpoint("/validation", "POST"): + # At present, the intention is that a failed validation does not block + # the job from running, it is only reported as a warning. + # Therefor we also want to continue when something *else* goes wrong + # *during* the validation. + try: + resp = self.post(path="/validation", json=pg_with_metadata["process"], expected_status=200) + validation_errors = resp.json()["errors"] + if validation_errors: + _log.warning( + "Preflight process graph validation raised: " + + (" ".join(f"[{e.get('code')}] {e.get('message')}" for e in validation_errors)) + ) + except Exception as e: + _log.error(f"Preflight process graph validation failed: {e}") + + # TODO: additional validation and sanity checks: e.g. is there a result node, are all process_ids valid, ...? + + # TODO: unify `download` and `execute` better: e.g. `download` always writes to disk, `execute` returns result (raw or as JSON decoded dict) +
    +[docs] + def download( + self, + graph: Union[dict, FlatGraphableMixin, str, Path], + outputfile: Union[Path, str, None] = None, + timeout: Optional[int] = None, + validate: Optional[bool] = None, + ) -> Union[None, bytes]: + """ + Downloads the result of a process graph synchronously, + and save the result to the given file or return bytes object if no outputfile is specified. + This method is useful to export binary content such as images. For json content, the execute method is recommended. + + :param graph: (flat) dict representing a process graph, or process graph as raw JSON string, + or as local file path or URL + :param outputfile: output file + :param timeout: timeout to wait for response + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + """ + pg_with_metadata = self._build_request_with_process_graph(process_graph=graph) + self._preflight_validation(pg_with_metadata=pg_with_metadata, validate=validate) + response = self.post( + path="/result", + json=pg_with_metadata, + expected_status=200, + stream=True, + timeout=timeout or DEFAULT_TIMEOUT_SYNCHRONOUS_EXECUTE, + ) + + if outputfile is not None: + with Path(outputfile).open(mode="wb") as f: + for chunk in response.iter_content(chunk_size=None): + f.write(chunk) + else: + return response.content
    + + +
    +[docs] + def execute( + self, + process_graph: Union[dict, str, Path], + timeout: Optional[int] = None, + validate: Optional[bool] = None, + ): + """ + Execute a process graph synchronously and return the result (assumed to be JSON). + + :param process_graph: (flat) dict representing a process graph, or process graph as raw JSON string, + or as local file path or URL + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: parsed JSON response + """ + pg_with_metadata = self._build_request_with_process_graph(process_graph=process_graph) + self._preflight_validation(pg_with_metadata=pg_with_metadata, validate=validate) + return self.post( + path="/result", + json=pg_with_metadata, + expected_status=200, + timeout=timeout or DEFAULT_TIMEOUT_SYNCHRONOUS_EXECUTE, + ).json() # TODO: only do JSON decoding when mimetype is actually JSON?
    + + +
    +[docs] + def create_job( + self, + process_graph: Union[dict, str, Path], + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + additional: Optional[dict] = None, + validate: Optional[bool] = None, + ) -> BatchJob: + """ + Create a new job from given process graph on the back-end. + + :param process_graph: (flat) dict representing a process graph, or process graph as raw JSON string, + or as local file path or URL + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param additional: additional job options to pass to the backend + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + :return: Created job + """ + # TODO move all this (BatchJob factory) logic to BatchJob? + + pg_with_metadata = self._build_request_with_process_graph( + process_graph=process_graph, + **dict_no_none(title=title, description=description, plan=plan, budget=budget) + ) + if additional: + # TODO: get rid of this non-standard field? https://github.com/Open-EO/openeo-api/issues/276 + pg_with_metadata["job_options"] = additional + + self._preflight_validation(pg_with_metadata=pg_with_metadata, validate=validate) + response = self.post("/jobs", json=pg_with_metadata, expected_status=201) + + job_id = None + if "openeo-identifier" in response.headers: + job_id = response.headers['openeo-identifier'].strip() + elif "location" in response.headers: + _log.warning("Backend did not explicitly respond with job id, will guess it from redirect URL.") + job_id = response.headers['location'].split("/")[-1] + if not job_id: + raise OpenEoClientException("Job creation response did not contain a valid job id") + return BatchJob(job_id=job_id, connection=self)
    + + +
    +[docs] + def job(self, job_id: str) -> BatchJob: + """ + Get the job based on the id. The job with the given id should already exist. + + Use :py:meth:`openeo.rest.connection.Connection.create_job` to create new jobs + + :param job_id: the job id of an existing job + :return: A job object. + """ + return BatchJob(job_id=job_id, connection=self)
    + + +
    +[docs] + def service(self, service_id: str) -> Service: + """ + Get the secondary web service based on the id. The service with the given id should already exist. + + Use :py:meth:`openeo.rest.connection.Connection.create_service` to create new services + + :param job_id: the service id of an existing secondary web service + :return: A service object. + """ + return Service(service_id, connection=self)
    + + +
    +[docs] + def load_disk_collection( + self, format: str, glob_pattern: str, options: Optional[dict] = None + ) -> DataCube: + """ + Loads image data from disk as a :py:class:`DataCube`. + + :param format: the file format, e.g. 'GTiff' + :param glob_pattern: a glob pattern that matches the files to load from disk + :param options: options specific to the file format + """ + return DataCube.load_disk_collection( + self, format, glob_pattern, **(options or {}) + )
    + + +
    +[docs] + def as_curl( + self, + data: Union[dict, DataCube, FlatGraphableMixin], + path="/result", + method="POST", + obfuscate_auth: bool = False, + ) -> str: + """ + Build curl command to evaluate given process graph or data cube + (including authorization and content-type headers). + + >>> print(connection.as_curl(cube)) + curl -i -X POST -H 'Content-Type: application/json' -H 'Authorization: Bearer ...' \\ + --data '{"process":{"process_graph":{...}}' \\ + https://openeo.example/openeo/1.1/result + + :param data: something that is convertable to an openEO process graph: a dictionary, + a :py:class:`~openeo.rest.datacube.DataCube` object, + a :py:class:`~openeo.processes.ProcessBuilder`, ... + :param path: endpoint to send request to: typically ``"/result"`` (default) for synchronous requests + or ``"/jobs"`` for batch jobs + :param method: HTTP method to use (typically ``"POST"``) + :param obfuscate_auth: don't show actual bearer token + + :return: curl command as a string + """ + cmd = ["curl", "-i", "-X", method] + cmd += ["-H", "Content-Type: application/json"] + if isinstance(self.auth, BearerAuth): + cmd += ["-H", f"Authorization: Bearer {'...' if obfuscate_auth else self.auth.bearer}"] + pg_with_metadata = self._build_request_with_process_graph(data) + post_json = json.dumps(pg_with_metadata, separators=(",", ":")) + cmd += ["--data", post_json] + cmd += [self.build_url(path)] + return " ".join(shlex.quote(c) for c in cmd)
    + + +
    +[docs] + def version_info(self): + """List version of the openEO client, API, back-end, etc.""" + capabilities = self.capabilities() + return { + "client": openeo.client_version(), + "api": capabilities.api_version(), + "backend": dict_no_none({ + "root_url": self.root_url, + "version": capabilities.get("backend_version"), + "processing:software": capabilities.get("processing:software"), + }), + }
    +
    + + + +
    +[docs] +def connect( + url: Optional[str] = None, + *, + auth_type: Optional[str] = None, + auth_options: Optional[dict] = None, + session: Optional[requests.Session] = None, + default_timeout: Optional[int] = None, + auto_validate: bool = True, +) -> Connection: + """ + This method is the entry point to OpenEO. + You typically create one connection object in your script or application + and re-use it for all calls to that backend. + + If the backend requires authentication, you can pass authentication data directly to this function, + but it could be easier to authenticate as follows: + + >>> # For basic authentication + >>> conn = connect(url).authenticate_basic(username="john", password="foo") + >>> # For OpenID Connect authentication + >>> conn = connect(url).authenticate_oidc(client_id="myclient") + + :param url: The http url of the OpenEO back-end. + :param auth_type: Which authentication to use: None, "basic" or "oidc" (for OpenID Connect) + :param auth_options: Options/arguments specific to the authentication type + :param default_timeout: default timeout (in seconds) for requests + :param auto_validate: toggle to automatically validate process graphs before execution + + .. versionadded:: 0.24.0 + added ``auto_validate`` argument + """ + + def _config_log(message): + _log.info(message) + config_log(message) + + if url is None: + default_backend = get_config_option("connection.default_backend") + if default_backend: + url = default_backend + _config_log(f"Using default back-end URL {url!r} (from config)") + default_backend_auto_auth = get_config_option("connection.default_backend.auto_authenticate") + if default_backend_auto_auth and default_backend_auto_auth.lower() in {"basic", "oidc"}: + auth_type = default_backend_auto_auth.lower() + _config_log(f"Doing auto-authentication {auth_type!r} (from config)") + + if auth_type is None: + auto_authenticate = get_config_option("connection.auto_authenticate") + if auto_authenticate and auto_authenticate.lower() in {"basic", "oidc"}: + auth_type = auto_authenticate.lower() + _config_log(f"Doing auto-authentication {auth_type!r} (from config)") + + if not url: + raise OpenEoClientException("No openEO back-end URL given or known to connect to.") + connection = Connection(url, session=session, default_timeout=default_timeout, auto_validate=auto_validate) + + auth_type = auth_type.lower() if isinstance(auth_type, str) else auth_type + if auth_type in {None, False, 'null', 'none'}: + pass + elif auth_type == "basic": + connection.authenticate_basic(**(auth_options or {})) + elif auth_type in {"oidc", "openid"}: + connection.authenticate_oidc(**(auth_options or {})) + else: + raise ValueError("Unknown auth type {a!r}".format(a=auth_type)) + return connection
    + + + +@deprecated("Use :py:func:`openeo.connect` instead", version="0.0.9") +def session(userid=None, endpoint: str = "https://openeo.org/openeo") -> Connection: + """ + This method is the entry point to OpenEO. You typically create one session object in your script or application, per back-end. + and re-use it for all calls to that backend. + If the backend requires authentication, you should set pass your credentials. + + :param endpoint: The http url of an OpenEO endpoint. + :rtype: openeo.sessions.Session + """ + return connect(url=endpoint) + + +def paginate(con: Connection, url: str, params: Optional[dict] = None, callback: Callable = lambda resp, page: resp): + # TODO: make this a method `get_paginated` on `RestApiConnection`? + # TODO: is it necessary to have `callback`? It's only used just before yielding, + # so it's probably cleaner (even for the caller) to to move it outside. + page = 1 + while True: + response = con.get(url, params=params).json() + yield callback(response, page) + next_links = [link for link in response.get("links", []) if link.get("rel") == "next" and "href" in link] + if not next_links: + break + url = next_links[0]["href"] + page += 1 + params = {} +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/conversions.html b/_modules/openeo/rest/conversions.html new file mode 100644 index 000000000..bee5b65a1 --- /dev/null +++ b/_modules/openeo/rest/conversions.html @@ -0,0 +1,261 @@ + + + + + + + openeo.rest.conversions — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.conversions

    +"""
    +Helpers for data conversions between Python ecosystem data types and openEO data structures.
    +"""
    +
    +from __future__ import annotations
    +
    +import typing
    +
    +import numpy as np
    +import pandas
    +
    +from openeo.internal.warnings import deprecated
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    import xarray
    +
    +    from openeo.udf import XarrayDataCube
    +
    +
    +
    +[docs] +class InvalidTimeSeriesException(ValueError): + pass
    + + + +
    +[docs] +def timeseries_json_to_pandas(timeseries: dict, index: str = "date", auto_collapse=True) -> pandas.DataFrame: + """ + Convert a timeseries JSON object as returned by the `aggregate_spatial` process to a pandas DataFrame object + + This timeseries data has three dimensions in general: date, polygon index and band index. + One of these will be used as index of the resulting dataframe (as specified by the `index` argument), + and the other two will be used as multilevel columns. + When there is just a single polygon or band in play, the dataframe will be simplified + by removing the corresponding dimension if `auto_collapse` is enabled (on by default). + + :param timeseries: dictionary as returned by `aggregate_spatial` + :param index: which dimension should be used for the DataFrame index: 'date' or 'polygon' + :param auto_collapse: whether single band or single polygon cases should be simplified automatically + + :return: pandas DataFrame or Series + """ + # The input timeseries dictionary is assumed to have this structure: + # {dict mapping date -> [list with one item per polygon: [list with one float/None per band or empty list]]} + # TODO is this format of `aggregate_spatial` standardized across backends? Or can we detect the structure? + # TODO: option to pass a path to a JSON file as input? + + # Some quick checks + if len(timeseries) == 0: + raise InvalidTimeSeriesException("Empty data set") + polygon_counts = set(len(polygon_data) for polygon_data in timeseries.values()) + if polygon_counts == {0}: + raise InvalidTimeSeriesException("No polygon data for each date") + elif 0 in polygon_counts: + # TODO: still support this use case? + raise InvalidTimeSeriesException("No polygon data for some dates ({p})".format(p=polygon_counts)) + elif len(polygon_counts) > 1: + raise InvalidTimeSeriesException("Inconsistent polygon counts: {p}".format(p=polygon_counts)) + # Count the number of bands in the timeseries, so we can provide a fallback array for missing data + band_counts = set(len(band_data) for polygon_data in timeseries.values() for band_data in polygon_data) + if band_counts == {0}: + raise InvalidTimeSeriesException("Zero bands everywhere") + band_counts.discard(0) + if len(band_counts) != 1: + raise InvalidTimeSeriesException("Inconsistent band counts: {b}".format(b=band_counts)) + band_count = band_counts.pop() + band_data_fallback = [np.nan] * band_count + # Load the timeseries data in a pandas Series with multi-index ["date", "polygon", "band"] + s = pandas.DataFrame.from_records( + ( + (date, polygon_index, band_index, value) + for (date, polygon_data) in timeseries.items() + for polygon_index, band_data in enumerate(polygon_data) + for band_index, value in enumerate(band_data or band_data_fallback) + ), + columns=["date", "polygon", "band", "value"], + index=["date", "polygon", "band"] + )["value"].rename(None) + # TODO convert date to real date index? + + if auto_collapse: + if s.index.levshape[2] == 1: + # Single band case + s.index = s.index.droplevel("band") + if s.index.levshape[1] == 1: + # Single polygon case + s.index = s.index.droplevel("polygon") + + # Reshape as desired + if index == "date": + if len(s.index.names) > 1: + return s.unstack("date").T + else: + return s + elif index == "polygon": + return s.unstack("polygon").T + else: + raise ValueError(index)
    + + + +
    +[docs] +@deprecated("Use :py:meth:`XarrayDataCube.from_file` instead.", version="0.7.0") +def datacube_from_file(filename, fmt="netcdf") -> XarrayDataCube: + from openeo.udf.xarraydatacube import XarrayDataCube + return XarrayDataCube.from_file(path=filename, fmt=fmt)
    + + + +
    +[docs] +@deprecated("Use :py:meth:`XarrayDataCube.save_to_file` instead.", version="0.7.0") +def datacube_to_file(datacube: XarrayDataCube, filename, fmt="netcdf"): + return datacube.save_to_file(path=filename, fmt=fmt)
    + + + +@deprecated("Use :py:meth:`XarrayIO.to_json_file` instead", version="0.7.0") +def _save_DataArray_to_JSON(filename, array: xarray.DataArray): + from openeo.udf.xarraydatacube import XarrayIO + return XarrayIO.to_json_file(array=array, path=filename) + + +@deprecated("Use :py:meth:`XarrayIO.to_netcdf_file` instead", version="0.7.0") +def _save_DataArray_to_NetCDF(filename, array: xarray.DataArray): + from openeo.udf.xarraydatacube import XarrayIO + return XarrayIO.to_netcdf_file(array=array, path=filename) + + +
    +[docs] +@deprecated("Use :py:meth:`XarrayDataCube.plot` instead.", version="0.7.0") +def datacube_plot(datacube: XarrayDataCube, *args, **kwargs): + datacube.plot(*args, **kwargs)
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/datacube.html b/_modules/openeo/rest/datacube.html new file mode 100644 index 000000000..3dbe018fd --- /dev/null +++ b/_modules/openeo/rest/datacube.html @@ -0,0 +1,2895 @@ + + + + + + + openeo.rest.datacube — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.datacube

    +"""
    +The main module for creating earth observation processes. It aims to easily build complex process chains, that can
    +be evaluated by an openEO backend.
    +
    +.. data:: THIS
    +
    +    Symbolic reference to the current data cube, to be used as argument in :py:meth:`DataCube.process()` calls
    +
    +"""
    +from __future__ import annotations
    +
    +import datetime
    +import logging
    +import pathlib
    +import typing
    +import warnings
    +from builtins import staticmethod
    +from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union
    +
    +import numpy as np
    +import shapely.geometry
    +import shapely.geometry.base
    +from shapely.geometry import MultiPolygon, Polygon, mapping
    +
    +from openeo.api.process import Parameter
    +from openeo.dates import get_temporal_extent
    +from openeo.internal.documentation import openeo_process
    +from openeo.internal.graph_building import PGNode, ReduceNode, _FromNodeMixin
    +from openeo.internal.jupyter import in_jupyter_context
    +from openeo.internal.processes.builder import ProcessBuilderBase, convert_callable_to_pgnode, get_parameter_names
    +from openeo.internal.warnings import UserDeprecationWarning, deprecated, legacy_alias
    +from openeo.metadata import Band, BandDimension, CollectionMetadata, SpatialDimension, TemporalDimension
    +from openeo.processes import ProcessBuilder
    +from openeo.rest import BandMathException, OpenEoClientException, OperatorException
    +from openeo.rest._datacube import THIS, UDF, _ProcessGraphAbstraction, build_child_callback
    +from openeo.rest.graph_building import CollectionProperty
    +from openeo.rest.job import BatchJob, RESTJob
    +from openeo.rest.mlmodel import MlModel
    +from openeo.rest.service import Service
    +from openeo.rest.udp import RESTUserDefinedProcess
    +from openeo.rest.vectorcube import VectorCube
    +from openeo.util import dict_no_none, guess_format, normalize_crs, rfc3339
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    import xarray
    +
    +    from openeo.rest.connection import Connection
    +    from openeo.udf import XarrayDataCube
    +
    +
    +log = logging.getLogger(__name__)
    +
    +
    +# Type annotation aliases
    +InputDate = Union[str, datetime.date, Parameter, PGNode, ProcessBuilderBase, None]
    +
    +
    +
    +[docs] +class DataCube(_ProcessGraphAbstraction): + """ + Class representing a openEO (raster) data cube. + + The data cube is represented by its corresponding openeo "process graph" + and this process graph can be "grown" to a desired workflow by calling the appropriate methods. + """ + + # TODO: set this based on back-end or user preference? + _DEFAULT_RASTER_FORMAT = "GTiff" + +
    +[docs] + def __init__(self, graph: PGNode, connection: Connection, metadata: Optional[CollectionMetadata] = None): + super().__init__(pgnode=graph, connection=connection) + self.metadata: Optional[CollectionMetadata] = metadata
    + + +
    +[docs] + def process( + self, + process_id: str, + arguments: Optional[dict] = None, + metadata: Optional[CollectionMetadata] = None, + namespace: Optional[str] = None, + **kwargs, + ) -> DataCube: + """ + Generic helper to create a new DataCube by applying a process. + + :param process_id: process id of the process. + :param arguments: argument dictionary for the process. + :param metadata: optional: metadata to override original cube metadata (e.g. when reducing dimensions) + :param namespace: optional: process namespace + :return: new DataCube instance + """ + pg = self._build_pgnode(process_id=process_id, arguments=arguments, namespace=namespace, **kwargs) + return DataCube(graph=pg, connection=self._connection, metadata=metadata or self.metadata)
    + + + graph_add_node = legacy_alias(process, "graph_add_node", since="0.1.1") + +
    +[docs] + def process_with_node(self, pg: PGNode, metadata: Optional[CollectionMetadata] = None) -> DataCube: + """ + Generic helper to create a new DataCube by applying a process (given as process graph node) + + :param pg: process graph node (containing process id and arguments) + :param metadata: optional: metadata to override original cube metadata (e.g. when reducing dimensions) + :return: new DataCube instance + """ + # TODO: deep copy `self.metadata` instead of using same instance? + # TODO: cover more cases where metadata has to be altered + # TODO: deprecate `process_with_node``: little added value over just calling DataCube() directly + return DataCube(graph=pg, connection=self._connection, metadata=metadata or self.metadata)
    + + + def _do_metadata_normalization(self) -> bool: + """Do metadata-based normalization/validation of dimension names, band names, ...""" + return isinstance(self.metadata, CollectionMetadata) + + def _assert_valid_dimension_name(self, name: str) -> str: + if self._do_metadata_normalization(): + self.metadata.assert_valid_dimension(name) + return name + +
    +[docs] + @classmethod + @openeo_process + def load_collection( + cls, + collection_id: Union[str, Parameter], + connection: Connection = None, + spatial_extent: Union[Dict[str, float], Parameter, None] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Union[None, List[str], Parameter] = None, + fetch_metadata: bool = True, + properties: Union[ + None, Dict[str, Union[str, PGNode, typing.Callable]], List[CollectionProperty], CollectionProperty + ] = None, + max_cloud_cover: Optional[float] = None, + ) -> DataCube: + """ + Create a new Raster Data cube. + + :param collection_id: image collection identifier + :param connection: The connection to use to connect with the backend. + :param spatial_extent: limit data to specified bounding box or polygons + :param temporal_extent: limit data to specified temporal interval. + Typically, just a two-item list or tuple containing start and end date. + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + :param bands: only add the specified bands. + :param properties: limit data by metadata property predicates. + See :py:func:`~openeo.rest.graph_building.collection_property` for easy construction of such predicates. + :param max_cloud_cover: shortcut to set maximum cloud cover ("eo:cloud_cover" collection property) + :return: new DataCube containing the collection + + .. versionchanged:: 0.13.0 + added the ``max_cloud_cover`` argument. + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + + .. versionchanged:: 0.26.0 + Add :py:func:`~openeo.rest.graph_building.collection_property` support to ``properties`` argument. + """ + if temporal_extent: + temporal_extent = cls._get_temporal_extent(extent=temporal_extent) + + if isinstance(spatial_extent, Parameter): + if spatial_extent.schema.get("type") != "object": + warnings.warn( + "Unexpected parameterized `spatial_extent` in `load_collection`:" + f" expected schema with type 'object' but got {spatial_extent.schema!r}." + ) + arguments = { + 'id': collection_id, + # TODO: spatial_extent could also be a "geojson" subtype object, so we might want to allow (and convert) shapely shapes as well here. + 'spatial_extent': spatial_extent, + 'temporal_extent': temporal_extent, + } + if isinstance(collection_id, Parameter): + fetch_metadata = False + metadata: Optional[CollectionMetadata] = ( + connection.collection_metadata(collection_id) if fetch_metadata else None + ) + if bands: + if isinstance(bands, str): + bands = [bands] + elif isinstance(bands, Parameter): + metadata = None + if metadata: + bands = [b if isinstance(b, str) else metadata.band_dimension.band_name(b) for b in bands] + metadata = metadata.filter_bands(bands) + arguments['bands'] = bands + + if isinstance(properties, list): + # TODO: warn about items that are not CollectionProperty objects instead of silently dropping them. + properties = {p.name: p.from_node() for p in properties if isinstance(p, CollectionProperty)} + if isinstance(properties, CollectionProperty): + properties = {properties.name: properties.from_node()} + elif properties is None: + properties = {} + if max_cloud_cover: + properties["eo:cloud_cover"] = lambda v: v <= max_cloud_cover + if properties: + summaries = metadata and metadata.get("summaries") or {} + undefined_properties = set(properties.keys()).difference(summaries.keys()) + if undefined_properties: + warnings.warn( + f"{collection_id} property filtering with properties that are undefined " + f"in the collection metadata (summaries): {', '.join(undefined_properties)}.", + stacklevel=2, + ) + arguments["properties"] = { + prop: build_child_callback(pred, parent_parameters=["value"]) for prop, pred in properties.items() + } + + pg = PGNode( + process_id='load_collection', + arguments=arguments + ) + return cls(graph=pg, connection=connection, metadata=metadata)
    + + + create_collection = legacy_alias( + load_collection, name="create_collection", since="0.4.6" + ) + +
    +[docs] + @classmethod + def load_disk_collection(cls, connection: Connection, file_format: str, glob_pattern: str, **options) -> DataCube: + """ + Loads image data from disk as a DataCube. + This is backed by a non-standard process ('load_disk_data'). This will eventually be replaced by standard options such as + https://processes.openeo.org/#load_uploaded_files + + + :param connection: The connection to use to connect with the backend. + :param file_format: the file format, e.g. 'GTiff' + :param glob_pattern: a glob pattern that matches the files to load from disk + :param options: options specific to the file format + :return: the data as a DataCube + """ + pg = PGNode( + process_id='load_disk_data', + arguments={ + 'format': file_format, + 'glob_pattern': glob_pattern, + 'options': options + } + ) + return cls(graph=pg, connection=connection)
    + + + @classmethod + def _get_temporal_extent( + cls, + *args, + start_date: InputDate = None, + end_date: InputDate = None, + extent: Union[Sequence[InputDate], Parameter, str, None] = None, + ) -> Union[List[Union[str, Parameter, PGNode, None]], Parameter]: + """Parameter aware temporal_extent normalizer""" + # TODO: move this outside of DataCube class + # TODO: return extent as tuple instead of list + if len(args) == 1 and isinstance(args[0], Parameter): + assert start_date is None and end_date is None and extent is None + return args[0] + elif len(args) == 0 and isinstance(extent, Parameter): + assert start_date is None and end_date is None + # TODO: warn about unexpected parameter schema + return extent + else: + def convertor(d: Any) -> Any: + # TODO: can this be generalized through _FromNodeMixin? + if isinstance(d, Parameter) or isinstance(d, PGNode): + # TODO: warn about unexpected parameter schema + return d + elif isinstance(d, ProcessBuilderBase): + return d.pgnode + else: + return rfc3339.normalize(d) + + return list( + get_temporal_extent(*args, start_date=start_date, end_date=end_date, extent=extent, convertor=convertor) + ) + +
    +[docs] + @openeo_process + def filter_temporal( + self, + *args, + start_date: InputDate = None, + end_date: InputDate = None, + extent: Union[Sequence[InputDate], Parameter, str, None] = None, + ) -> DataCube: + """ + Limit the DataCube to a certain date range, which can be specified in several ways: + + >>> cube.filter_temporal("2019-07-01", "2019-08-01") + >>> cube.filter_temporal(["2019-07-01", "2019-08-01"]) + >>> cube.filter_temporal(extent=["2019-07-01", "2019-08-01"]) + >>> cube.filter_temporal(start_date="2019-07-01", end_date="2019-08-01"]) + + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + + :param start_date: start date of the filter (inclusive), as a string or date object + :param end_date: end date of the filter (exclusive), as a string or date object + :param extent: temporal extent. + Typically, specified as a two-item list or tuple containing start and end date. + + .. versionchanged:: 0.23.0 + Arguments ``start_date``, ``end_date`` and ``extent``: + add support for year/month shorthand notation as discussed at :ref:`date-shorthand-handling`. + """ + return self.process( + process_id='filter_temporal', + arguments={ + 'data': THIS, + 'extent': self._get_temporal_extent(*args, start_date=start_date, end_date=end_date, extent=extent) + } + )
    + + +
    +[docs] + @openeo_process + def filter_bbox( + self, + *args, + west: Optional[float] = None, + south: Optional[float] = None, + east: Optional[float] = None, + north: Optional[float] = None, + crs: Optional[Union[int, str]] = None, + base: Optional[float] = None, + height: Optional[float] = None, + bbox: Optional[Sequence[float]] = None, + ) -> DataCube: + """ + Limits the data cube to the specified bounding box. + + The bounding box can be specified in multiple ways. + + - With keyword arguments:: + + >>> cube.filter_bbox(west=3, south=51, east=4, north=52, crs=4326) + + - With a (west, south, east, north) list or tuple + (note that EPSG:4326 is the default CRS, so it's not necessary to specify it explicitly):: + + >>> cube.filter_bbox([3, 51, 4, 52]) + >>> cube.filter_bbox(bbox=[3, 51, 4, 52]) + + - With a bbox dictionary:: + + >>> bbox = {"west": 3, "south": 51, "east": 4, "north": 52, "crs": 4326} + >>> cube.filter_bbox(bbox) + >>> cube.filter_bbox(bbox=bbox) + >>> cube.filter_bbox(**bbox) + + - With a shapely geometry (of which the bounding box will be used):: + + >>> cube.filter_bbox(geometry) + >>> cube.filter_bbox(bbox=geometry) + + - Passing a parameter:: + + >>> bbox_param = Parameter(name="my_bbox", schema="object") + >>> cube.filter_bbox(bbox_param) + >>> cube.filter_bbox(bbox=bbox_param) + + - With a CRS other than EPSG 4326:: + + >>> cube.filter_bbox( + ... west=652000, east=672000, north=5161000, south=5181000, + ... crs=32632 + ... ) + + - Deprecated: positional arguments are also supported, + but follow a non-standard order for legacy reasons:: + + >>> west, east, north, south = 3, 4, 52, 51 + >>> cube.filter_bbox(west, east, north, south) + + :param crs: value describing the coordinate reference system. + Typically just an int (interpreted as EPSG code, e.g. ``4326``) + or a string (handled as authority string, e.g. ``"EPSG:4326"``). + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + """ + if args and any(k is not None for k in (west, south, east, north, bbox)): + raise ValueError("Don't mix positional arguments with keyword arguments.") + if bbox and any(k is not None for k in (west, south, east, north)): + raise ValueError("Don't mix `bbox` with `west`/`south`/`east`/`north` keyword arguments.") + + if args: + if 4 <= len(args) <= 5: + # Handle old-style west-east-north-south order + # TODO remove handling of this legacy order? + warnings.warn("Deprecated argument order usage: `filter_bbox(west, east, north, south)`." + " Use keyword arguments or tuple/list argument instead.") + west, east, north, south = args[:4] + if len(args) > 4: + crs = normalize_crs(args[4]) + elif len(args) == 1 and (isinstance(args[0], (list, tuple)) and len(args[0]) == 4 + or isinstance(args[0], (dict, shapely.geometry.base.BaseGeometry, Parameter))): + bbox = args[0] + else: + raise ValueError(args) + + if isinstance(bbox, Parameter): + if bbox.schema.get("type") != "object": + warnings.warn( + "Unexpected parameterized `extent` in `filter_bbox`:" + f" expected schema with type 'object' but got {bbox.schema!r}." + ) + extent = bbox + else: + if bbox: + if isinstance(bbox, shapely.geometry.base.BaseGeometry): + west, south, east, north = bbox.bounds + elif isinstance(bbox, (list, tuple)) and len(bbox) == 4: + west, south, east, north = bbox[:4] + elif isinstance(bbox, dict): + west, south, east, north = (bbox[k] for k in ["west", "south", "east", "north"]) + if "crs" in bbox: + crs = bbox["crs"] + else: + raise ValueError(bbox) + + extent = {'west': west, 'east': east, 'north': north, 'south': south} + extent.update(dict_no_none(crs=crs, base=base, height=height)) + + return self.process( + process_id='filter_bbox', + arguments={ + 'data': THIS, + 'extent': extent + } + )
    + + +
    +[docs] + @openeo_process + def filter_spatial(self, geometries) -> DataCube: + """ + Limits the data cube over the spatial dimensions to the specified geometries. + + - For polygons, the filter retains a pixel in the data cube if the point at the pixel center intersects with + at least one of the polygons (as defined in the Simple Features standard by the OGC). + - For points, the process considers the closest pixel center. + - For lines (line strings), the process considers all the pixels whose centers are closest to at least one + point on the line. + + More specifically, pixels outside of the bounding box of the given geometry will not be available after filtering. + All pixels inside the bounding box that are not retained will be set to null (no data). + + :param geometries: One or more geometries used for filtering, specified as GeoJSON in EPSG:4326. + :return: A data cube restricted to the specified geometries. The dimensions and dimension properties (name, + type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions have less + (or the same) dimension labels. + """ + valid_geojson_types = [ + "Point", "MultiPoint", "LineString", "MultiLineString", + "Polygon", "MultiPolygon", "GeometryCollection", "FeatureCollection" + ] + geometries = self._get_geometry_argument(geometries, valid_geojson_types=valid_geojson_types, crs=None) + return self.process( + process_id='filter_spatial', + arguments={ + 'data': THIS, + 'geometries': geometries + } + )
    + + +
    +[docs] + @openeo_process + def filter_bands(self, bands: Union[List[Union[str, int]], str]) -> DataCube: + """ + Filter the data cube by the given bands + + :param bands: list of band names, common names or band indices. Single band name can also be given as string. + :return: a DataCube instance + """ + if isinstance(bands, str): + bands = [bands] + if self._do_metadata_normalization(): + bands = [self.metadata.band_dimension.band_name(b) for b in bands] + cube = self.process( + process_id="filter_bands", + arguments={"data": THIS, "bands": bands}, + metadata=self.metadata.filter_bands(bands) if self.metadata else None, + ) + return cube
    + + + band_filter = legacy_alias(filter_bands, "band_filter", since="0.1.0") + +
    +[docs] + def band(self, band: Union[str, int]) -> DataCube: + """ + Filter out a single band + + :param band: band name, band common name or band index. + :return: a DataCube instance + """ + if self._do_metadata_normalization(): + band = self.metadata.band_dimension.band_index(band) + return self.reduce_bands( + reducer=PGNode( + process_id="array_element", + arguments={"data": {"from_parameter": "data"}, "index": band}, + ) + )
    + + +
    +[docs] + @openeo_process + def resample_spatial( + self, resolution: Union[float, Tuple[float, float]], projection: Union[int, str] = None, + method: str = 'near', align: str = 'upper-left' + ) -> DataCube: + return self.process('resample_spatial', { + 'data': THIS, + 'resolution': resolution, + 'projection': projection, + 'method': method, + 'align': align + })
    + + +
    +[docs] + def resample_cube_spatial(self, target: DataCube, method: str = "near") -> DataCube: + """ + Resamples the spatial dimensions (x,y) from a source data cube to align with the corresponding + dimensions of the given target data cube. + Returns a new data cube with the resampled dimensions. + + To resample a data cube to a specific resolution or projection regardless of an existing target + data cube, refer to :py:meth:`resample_spatial`. + + :param target: A data cube that describes the spatial target resolution. + :param method: Resampling method to use. + :return: + """ + return self.process("resample_cube_spatial", {"data": self, "target": target, "method": method})
    + + +
    +[docs] + @openeo_process + def resample_cube_temporal( + self, target: DataCube, dimension: Optional[str] = None, valid_within: Optional[int] = None + ) -> DataCube: + """ + 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. + + By 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``. + + The rare case of ties is resolved by choosing the earlier timestamps. + + :param target: A data cube that describes the temporal target resolution. + :param dimension: The name of the temporal dimension to resample. + :param valid_within: + :return: + + .. versionadded:: 0.10.0 + """ + return self.process( + "resample_cube_temporal", + dict_no_none({"data": self, "target": target, "dimension": dimension, "valid_within": valid_within}) + )
    + + + def _operator_binary(self, operator: str, other: Union[DataCube, int, float], reverse=False) -> DataCube: + """Generic handling of (mathematical) binary operator""" + band_math_mode = self._in_bandmath_mode() + if band_math_mode: + if isinstance(other, (int, float)): + return self._bandmath_operator_binary_scalar(operator, other, reverse=reverse) + elif isinstance(other, DataCube): + return self._bandmath_operator_binary_cubes(operator, other) + else: + if isinstance(other, DataCube): + return self._merge_operator_binary_cubes(operator, other) + elif isinstance(other, (int, float)): + # "`apply` math" mode + return self._apply_operator( + operator=operator, other=other, reverse=reverse + ) + raise OperatorException( + f"Unsupported operator {operator!r} with `other` type {type(other)!r} (band math mode={band_math_mode})" + ) + + def _operator_unary(self, operator: str, **kwargs) -> DataCube: + band_math_mode = self._in_bandmath_mode() + if band_math_mode: + return self._bandmath_operator_unary(operator, **kwargs) + else: + return self._apply_operator(operator=operator, extra_arguments=kwargs) + + def _apply_operator( + self, + operator: str, + other: Optional[Union[int, float]] = None, + reverse: Optional[bool] = None, + extra_arguments: Optional[dict] = None, + ) -> DataCube: + """ + Apply a unary or binary operator/process, + by appending to existing `apply` node, or starting a new one. + + :param operator: process id of operator + :param other: for binary operators: "other" argument + :param reverse: for binary operators: "self" and "other" should be swapped (reflected operator mode) + """ + if self.result_node().process_id == "apply": + # Append to existing `apply` node + orig_apply = self.result_node() + data = orig_apply.arguments["data"] + x = {"from_node": orig_apply.arguments["process"]["process_graph"]} + context = orig_apply.arguments.get("context") + else: + # Start new `apply` node. + data = self + x = {"from_parameter": "x"} + context = None + # Build args for child callback. + args = {"x": x, **(extra_arguments or {})} + if other is not None: + # Binary operator mode + args["y"] = other + if reverse: + args["x"], args["y"] = args["y"], args["x"] + child_pg = PGNode(process_id=operator, arguments=args) + return self.process_with_node( + PGNode( + process_id="apply", + arguments=dict_no_none( + data=data, + process={"process_graph": child_pg}, + context=context, + ), + ) + ) + +
    +[docs] + @openeo_process(mode="operator") + def add(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("add", other, reverse=reverse)
    + + +
    +[docs] + @openeo_process(mode="operator") + def subtract(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("subtract", other, reverse=reverse)
    + + +
    +[docs] + @openeo_process(mode="operator") + def divide(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("divide", other, reverse=reverse)
    + + +
    +[docs] + @openeo_process(mode="operator") + def multiply(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("multiply", other, reverse=reverse)
    + + +
    +[docs] + @openeo_process + def normalized_difference(self, other: DataCube) -> DataCube: + # This DataCube method is only a convenience function when in band math mode + assert self._in_bandmath_mode() + assert other._in_bandmath_mode() + return self._operator_binary("normalized_difference", other)
    + + +
    +[docs] + @openeo_process(process_id="or", mode="operator") + def logical_or(self, other: DataCube) -> DataCube: + """ + Apply element-wise logical `or` operation + + :param other: + :return: logical_or(this, other) + """ + return self._operator_binary("or", other)
    + + +
    +[docs] + @openeo_process(process_id="and", mode="operator") + def logical_and(self, other: DataCube) -> DataCube: + """ + Apply element-wise logical `and` operation + + :param other: + :return: logical_and(this, other) + """ + return self._operator_binary("and", other)
    + + + @openeo_process(process_id="not", mode="operator") + def __invert__(self) -> DataCube: + return self._operator_unary("not") + + @openeo_process(process_id="neq", mode="operator") + def __ne__(self, other: Union[DataCube, int, float]) -> DataCube: + return self._operator_binary("neq", other) + + @openeo_process(process_id="eq", mode="operator") + def __eq__(self, other: Union[DataCube, int, float]) -> DataCube: + """ + Pixelwise comparison of this data cube with another cube or constant. + + :param other: Another data cube, or a constant + :return: + """ + return self._operator_binary("eq", other) + + @openeo_process(process_id="gt", mode="operator") + def __gt__(self, other: Union[DataCube, int, float]) -> DataCube: + """ + Pairwise comparison of the bands in this data cube with the bands in the 'other' data cube. + + :param other: + :return: this > other + """ + return self._operator_binary("gt", other) + + @openeo_process(process_id="ge", mode="operator") + def __ge__(self, other: Union[DataCube, int, float]) -> DataCube: + return self._operator_binary("gte", other) + + @openeo_process(process_id="lt", mode="operator") + def __lt__(self, other: Union[DataCube, int, float]) -> DataCube: + """ + Pairwise comparison of the bands in this data cube with the bands in the 'other' data cube. + The number of bands in both data cubes has to be the same. + + :param other: + :return: this < other + """ + return self._operator_binary("lt", other) + + @openeo_process(process_id="le", mode="operator") + def __le__(self, other: Union[DataCube, int, float]) -> DataCube: + return self._operator_binary("lte", other) + + @openeo_process(process_id="add", mode="operator") + def __add__(self, other) -> DataCube: + return self.add(other) + + @openeo_process(process_id="add", mode="operator") + def __radd__(self, other) -> DataCube: + return self.add(other, reverse=True) + + @openeo_process(process_id="subtract", mode="operator") + def __sub__(self, other) -> DataCube: + return self.subtract(other) + + @openeo_process(process_id="subtract", mode="operator") + def __rsub__(self, other) -> DataCube: + return self.subtract(other, reverse=True) + + @openeo_process(process_id="multiply", mode="operator") + def __neg__(self) -> DataCube: + return self.multiply(-1) + + @openeo_process(process_id="multiply", mode="operator") + def __mul__(self, other) -> DataCube: + return self.multiply(other) + + @openeo_process(process_id="multiply", mode="operator") + def __rmul__(self, other) -> DataCube: + return self.multiply(other, reverse=True) + + @openeo_process(process_id="divide", mode="operator") + def __truediv__(self, other) -> DataCube: + return self.divide(other) + + @openeo_process(process_id="divide", mode="operator") + def __rtruediv__(self, other) -> DataCube: + return self.divide(other, reverse=True) + + @openeo_process(process_id="power", mode="operator") + def __rpow__(self, other) -> DataCube: + return self._power(other, reverse=True) + + @openeo_process(process_id="power", mode="operator") + def __pow__(self, other) -> DataCube: + return self._power(other, reverse=False) + + def _power(self, other, reverse=False): + node = self._get_bandmath_node() + x = node.reducer_process_graph() + y = other + if reverse: + x, y = y, x + return self.process_with_node(node.clone_with_new_reducer( + PGNode(process_id="power", base=x, p=y) + )) + +
    +[docs] + @openeo_process(process_id="power", mode="operator") + def power(self, p: float): + return self._power(other=p, reverse=False)
    + + +
    +[docs] + @openeo_process(process_id="ln", mode="operator") + def ln(self) -> DataCube: + return self._operator_unary("ln")
    + + +
    +[docs] + @openeo_process(process_id="log", mode="operator") + def logarithm(self, base: float) -> DataCube: + return self._operator_unary("log", base=base)
    + + +
    +[docs] + @openeo_process(process_id="log", mode="operator") + def log2(self) -> DataCube: + return self.logarithm(base=2)
    + + +
    +[docs] + @openeo_process(process_id="log", mode="operator") + def log10(self) -> DataCube: + return self.logarithm(base=10)
    + + + @openeo_process(process_id="or", mode="operator") + def __or__(self, other) -> DataCube: + return self.logical_or(other) + + @openeo_process(process_id="and", mode="operator") + def __and__(self, other): + return self.logical_and(other) + + def _bandmath_operator_binary_cubes( + self, operator, other: DataCube, left_arg_name="x", right_arg_name="y" + ) -> DataCube: + """Band math binary operator with cube as right hand side argument""" + left = self._get_bandmath_node() + right = other._get_bandmath_node() + if left.arguments["data"] != right.arguments["data"]: + raise BandMathException("'Band math' between bands of different data cubes is not supported yet.") + + # Build reducer's sub-processgraph + merged = PGNode( + process_id=operator, + arguments={ + left_arg_name: {"from_node": left.reducer_process_graph()}, + right_arg_name: {"from_node": right.reducer_process_graph()}, + }, + ) + return self.process_with_node(left.clone_with_new_reducer(merged)) + + def _bandmath_operator_binary_scalar(self, operator: str, other: Union[int, float], reverse=False) -> DataCube: + """Band math binary operator with scalar value (int or float) as right hand side argument""" + node = self._get_bandmath_node() + x = {'from_node': node.reducer_process_graph()} + y = other + if reverse: + x, y = y, x + return self.process_with_node(node.clone_with_new_reducer( + PGNode(operator, x=x, y=y) + )) + + def _bandmath_operator_unary(self, operator: str, **kwargs) -> DataCube: + node = self._get_bandmath_node() + return self.process_with_node(node.clone_with_new_reducer( + PGNode(operator, x={'from_node': node.reducer_process_graph()}, **kwargs) + )) + + def _in_bandmath_mode(self) -> bool: + """So-called "band math" mode: current result node is reduce_dimension along "bands" dimension.""" + # TODO #123 is it (still) necessary to make "band" math a special case? + return isinstance(self._pg, ReduceNode) and self._pg.band_math_mode + + def _get_bandmath_node(self) -> ReduceNode: + """Check we are in bandmath mode and return the node""" + if not self._in_bandmath_mode(): + raise BandMathException("Must be in band math mode already") + return self._pg + + def _merge_operator_binary_cubes( + self, operator: str, other: DataCube, left_arg_name="x", right_arg_name="y" + ) -> DataCube: + """Merge two cubes with given operator as overlap_resolver.""" + # TODO #123 reuse an existing merge_cubes process graph if it already exists? + return self.merge_cubes(other, overlap_resolver=PGNode( + process_id=operator, + arguments={ + left_arg_name: {"from_parameter": "x"}, + right_arg_name: {"from_parameter": "y"}, + } + )) + + def _get_geometry_argument( + self, + geometry: Union[ + shapely.geometry.base.BaseGeometry, + dict, + str, + pathlib.Path, + Parameter, + _FromNodeMixin, + ], + valid_geojson_types: List[str], + crs: Optional[str] = None, + ) -> Union[dict, Parameter, PGNode]: + """ + Convert input to a geometry as "geojson" subtype object. + + :param crs: value that encodes a coordinate reference system. + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + """ + if isinstance(geometry, (str, pathlib.Path)): + # Assumption: `geometry` is path to polygon is a path to vector file at backend. + # TODO #104: `read_vector` is non-standard process. + # TODO: If path exists client side: load it client side? + return PGNode(process_id="read_vector", arguments={"filename": str(geometry)}) + elif isinstance(geometry, Parameter): + return geometry + elif isinstance(geometry, _FromNodeMixin): + return geometry.from_node() + + if isinstance(geometry, shapely.geometry.base.BaseGeometry): + geometry = mapping(geometry) + if not isinstance(geometry, dict): + raise OpenEoClientException("Invalid geometry argument: {g!r}".format(g=geometry)) + + if geometry.get("type") not in valid_geojson_types: + raise OpenEoClientException("Invalid geometry type {t!r}, must be one of {s}".format( + t=geometry.get("type"), s=valid_geojson_types + )) + if crs: + # TODO: don't warn when the crs is Lon-Lat like EPSG:4326? + warnings.warn(f"Geometry with non-Lon-Lat CRS {crs!r} is only supported by specific back-ends.") + # TODO #204 alternative for non-standard CRS in GeoJSON object? + epsg_code = normalize_crs(crs) + if epsg_code is not None: + # proj did recognize the CRS + crs_name = f"EPSG:{epsg_code}" + else: + # proj did not recognise this CRS + warnings.warn(f"non-Lon-Lat CRS {crs!r} is not known to the proj library and might not be supported.") + crs_name = crs + geometry["crs"] = {"type": "name", "properties": {"name": crs_name}} + return geometry + +
    +[docs] + @openeo_process + def aggregate_spatial( + self, + geometries: Union[ + shapely.geometry.base.BaseGeometry, + dict, + str, + pathlib.Path, + Parameter, + VectorCube, + ], + reducer: Union[str, typing.Callable, PGNode], + target_dimension: Optional[str] = None, + crs: Optional[Union[int, str]] = None, + context: Optional[dict] = None, + # TODO arguments: target dimension, context + ) -> VectorCube: + """ + Aggregates statistics for one or more geometries (e.g. zonal statistics for polygons) + over the spatial dimensions. + + :param geometries: a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute <openeo.processes.max>` (:ref:`predefined openEO process function <openeo_processes_functions>`) + - ``lambda data: data.min()`` (function or lambda) + + :param target_dimension: The new dimension name to be used for storing the results. + :param crs: The spatial reference system of the provided polygon. + By default, longitude-latitude (EPSG:4326) is assumed. + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + + :param context: Additional data to be passed to the reducer process. + + .. note:: this ``crs`` argument is a non-standard/experimental feature, only supported by specific back-ends. + See https://github.com/Open-EO/openeo-processes/issues/235 for details. + """ + valid_geojson_types = [ + "Point", "MultiPoint", "LineString", "MultiLineString", + "Polygon", "MultiPolygon", "GeometryCollection", "Feature", "FeatureCollection" + ] + geometries = self._get_geometry_argument(geometries, valid_geojson_types=valid_geojson_types, crs=crs) + reducer = build_child_callback(reducer, parent_parameters=["data"]) + return VectorCube( + graph=self._build_pgnode( + process_id="aggregate_spatial", + data=THIS, + geometries=geometries, + reducer=reducer, + arguments=dict_no_none( + target_dimension=target_dimension, context=context + ), + ), + connection=self._connection, + # TODO: metadata? And correct dimension of created vector cube? #457 + )
    + + +
    +[docs] + @openeo_process + def aggregate_spatial_window( + self, + reducer: Union[str, typing.Callable, PGNode], + size: List[int], + boundary: str = "pad", + align: str = "upper-left", + context: Optional[dict] = None, + # TODO arguments: target dimension, context + ) -> DataCube: + """ + Aggregates statistics over the horizontal spatial dimensions (axes x and y) of the data cube. + + The 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. For each of these windows, the reducer process computes the result. + + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + :param size: Window size in pixels along the horizontal spatial dimensions. + The first value corresponds to the x axis, the second value corresponds to the y axis. + :param boundary: 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: + + - ``pad`` (default): pad the data cube with the no-data value null to fit the required window size. + - ``trim``: trim the data cube to fit the required window size. + + Use the parameter ``align`` to align the data to the desired corner. + + :param align: 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. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. + """ + valid_boundary_types = ["pad", "trim"] + valid_align_types = ["lower-left", "upper-left", "lower-right", "upper-right"] + if boundary not in valid_boundary_types: + raise ValueError(f"Provided boundary type not supported. Please use one of {valid_boundary_types} .") + if align not in valid_align_types: + raise ValueError(f"Provided align type not supported. Please use one of {valid_align_types} .") + if len(size) != 2: + raise ValueError(f"Provided size not supported. Please provide a list of 2 integer values.") + + reducer = build_child_callback(reducer, parent_parameters=["data"]) + arguments = { + "data": THIS, + "boundary": boundary, + "align": align, + "size": size, + "reducer": reducer, + "context": context, + } + return self.process(process_id="aggregate_spatial_window", arguments=arguments)
    + + +
    +[docs] + @openeo_process + def apply_dimension( + self, + code: Optional[str] = None, + runtime=None, + # TODO: drop None default of process (when `code` and `runtime` args can be dropped) + process: Union[str, typing.Callable, UDF, PGNode] = None, + version: Optional[str] = None, + # TODO: dimension has no default (per spec)? + dimension: str = "t", + target_dimension: Optional[str] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Applies a process to all pixel values along a dimension of a raster data cube. For example, + if the temporal dimension is specified the process will work on a time series of pixel values. + + The process to apply is specified by either `code` and `runtime` in case of a UDF, or by providing a callback function + in the `process` argument. + + The process reduce_dimension also applies a process to pixel values along a dimension, but drops + the dimension afterwards. The process apply applies a process to each pixel value in the data cube. + + The target dimension is the source dimension if not specified otherwise in the target_dimension parameter. + The pixel values in the target dimension get replaced by the computed pixel values. The name, type and + reference system are preserved. + + The dimension labels are preserved when the target dimension is the source dimension and the number of + pixel values in the source dimension is equal to the number of values computed by the process. Otherwise, + the dimension labels will be incrementing integers starting from zero, which can be changed using + rename_labels afterwards. The number of labels will equal to the number of values computed by the process. + + :param code: [**deprecated**] UDF code or process identifier (optional) + :param runtime: [**deprecated**] UDF runtime to use (optional) + :param process: the "child callback": + the name of a single process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns an array of numerical values. + For example: + + - ``"sort"`` (string) + - :py:func:`sort <openeo.processes.sort>` (:ref:`predefined openEO process function <openeo_processes_functions>`) + - ``lambda data: data.concat([42, -3])`` (function or lambda) + + + :param version: [**deprecated**] Version of the UDF runtime to use + :param dimension: The name of the source dimension to apply the process on. Fails with a DimensionNotAvailable error if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or null (the default) to use the source dimension + specified in the parameter dimension. By 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. + :param context: Additional data to be passed to the process. + + :return: A datacube with the UDF applied to the given dimension. + :raises: DimensionNotAvailable + + .. versionchanged:: 0.13.0 + arguments ``code``, ``runtime`` and ``version`` are deprecated if favor of the standard approach + of using an :py:class:`UDF <openeo.rest._datacube.UDF>` object in the ``process`` argument. + See :ref:`old_udf_api` for more background about the changes. + + """ + # TODO #137 #181 #312 remove support for code/runtime/version + if runtime or (isinstance(code, str) and "\n" in code) or version: + if process: + raise ValueError( + "Cannot specify `process` argument together with deprecated `code`/`runtime`/`version` arguments." + ) + else: + warnings.warn( + "Specifying UDF code through `code`, `runtime` and `version` arguments is deprecated. " + "Instead create an `openeo.UDF` object and pass that to the `process` argument.", + category=UserDeprecationWarning, + stacklevel=2, + ) + process = UDF(code=code, runtime=runtime, version=version, context=context) + else: + process = process or code + process = build_child_callback( + process=process, parent_parameters=["data", "context"], connection=self.connection + ) + arguments = { + "data": THIS, + "process": process, + "dimension": self._assert_valid_dimension_name(dimension), + } + if target_dimension is not None: + arguments["target_dimension"] = target_dimension + if context is not None: + arguments["context"] = context + result_cube = self.process(process_id="apply_dimension", arguments=arguments) + + return result_cube
    + + +
    +[docs] + @openeo_process + def reduce_dimension( + self, + dimension: str, + reducer: Union[str, typing.Callable, UDF, PGNode], + context: Optional[dict] = None, + process_id="reduce_dimension", + band_math_mode: bool = False, + ) -> DataCube: + """ + Add a reduce process with given reducer callback along given dimension + + :param dimension: the label of the dimension to reduce + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute <openeo.processes.max>` (:ref:`predefined openEO process function <openeo_processes_functions>`) + - ``lambda data: data.min()`` (function or lambda) + + :param context: Additional data to be passed to the process. + """ + # TODO: check if dimension is valid according to metadata? #116 + # TODO: #125 use/test case for `reduce_dimension_binary`? + reducer = build_child_callback( + process=reducer, parent_parameters=["data", "context"], connection=self.connection + ) + + return self.process_with_node( + ReduceNode( + process_id=process_id, + data=self, + reducer=reducer, + dimension=self._assert_valid_dimension_name(dimension), + context=context, + # TODO #123 is it (still) necessary to make "band" math a special case? + band_math_mode=band_math_mode, + ), + metadata=self.metadata.reduce_dimension(dimension_name=dimension) if self.metadata else None, + )
    + + +
    +[docs] + @openeo_process + def reduce_spatial( + self, + reducer: Union[str, typing.Callable, UDF, PGNode], + context: Optional[dict] = None, + ) -> "DataCube": + """ + Add a reduce process with given reducer callback along the spatial dimensions + + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute <openeo.processes.max>` (:ref:`predefined openEO process function <openeo_processes_functions>`) + - ``lambda data: data.min()`` (function or lambda) + + :param context: Additional data to be passed to the process. + """ + reducer = build_child_callback( + process=reducer, parent_parameters=["data", "context"], connection=self.connection + ) + return self.process( + process_id="reduce_spatial", + data=self, + reducer=reducer, + context=context, + metadata=self.metadata.reduce_spatial(), + )
    + + +
    +[docs] + @deprecated("Use :py:meth:`apply_polygon`.", version="0.26.0") + def chunk_polygon( + self, + chunks: Union[shapely.geometry.base.BaseGeometry, dict, str, pathlib.Path, Parameter, VectorCube], + process: Union[str, PGNode, typing.Callable, UDF], + mask_value: float = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Apply a process to spatial chunks of a data cube. + + .. warning:: experimental process: not generally supported, API subject to change. + + :param chunks: Polygons, provided as a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param process: "child callback" function, see :ref:`callbackfunctions` + :param mask_value: The value used for cells outside the polygon. + This provides a distinction between NoData cells within the polygon (due to e.g. clouds) + and masked cells outside it. If no value is provided, NoData cells are used outside the polygon. + :param context: Additional data to be passed to the process. + """ + process = build_child_callback(process, parent_parameters=["data"], connection=self.connection) + valid_geojson_types = [ + "Polygon", + "MultiPolygon", + "GeometryCollection", + "Feature", + "FeatureCollection", + ] + chunks = self._get_geometry_argument( + chunks, valid_geojson_types=valid_geojson_types + ) + mask_value = float(mask_value) if mask_value is not None else None + return self.process( + process_id="chunk_polygon", + data=THIS, + chunks=chunks, + process=process, + arguments=dict_no_none( + mask_value=mask_value, + context=context, + ), + )
    + + +
    +[docs] + @openeo_process + def apply_polygon( + self, + polygons: Union[shapely.geometry.base.BaseGeometry, dict, str, pathlib.Path, Parameter, VectorCube], + process: Union[str, PGNode, typing.Callable, UDF], + mask_value: Optional[float] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Apply a process to segments of the data cube that are defined by the given polygons. + For each polygon provided, all pixels for which the point at the pixel center intersects + with the polygon (as defined in the Simple Features standard by the OGC) are collected into sub data cubes. + If a pixel is part of multiple of the provided polygons (e.g., when the polygons overlap), + the GeometriesOverlap exception is thrown. + Each sub data cube is passed individually to the given process. + + .. warning:: experimental process: not generally supported, API subject to change. + + :param polygons: Polygons, provided as a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param process: "child callback" function, see :ref:`callbackfunctions` + :param mask_value: The value used for pixels outside the polygon. + :param context: Additional data to be passed to the process. + """ + process = build_child_callback(process, parent_parameters=["data"], connection=self.connection) + valid_geojson_types = ["Polygon", "MultiPolygon", "Feature", "FeatureCollection"] + polygons = self._get_geometry_argument(polygons, valid_geojson_types=valid_geojson_types) + mask_value = float(mask_value) if mask_value is not None else None + return self.process( + process_id="apply_polygon", + data=THIS, + polygons=polygons, + process=process, + arguments=dict_no_none( + mask_value=mask_value, + context=context, + ), + )
    + + +
    +[docs] + def reduce_bands(self, reducer: Union[str, PGNode, typing.Callable, UDF]) -> DataCube: + """ + Shortcut for :py:meth:`reduce_dimension` along the band dimension + + :param reducer: "child callback" function, see :ref:`callbackfunctions` + """ + return self.reduce_dimension( + dimension=self.metadata.band_dimension.name if self.metadata else "bands", + reducer=reducer, + band_math_mode=True, + )
    + + +
    +[docs] + def reduce_temporal(self, reducer: Union[str, PGNode, typing.Callable, UDF]) -> DataCube: + """ + Shortcut for :py:meth:`reduce_dimension` along the temporal dimension + + :param reducer: "child callback" function, see :ref:`callbackfunctions` + """ + return self.reduce_dimension( + dimension=self.metadata.temporal_dimension.name if self.metadata else "t", + reducer=reducer, + )
    + + +
    +[docs] + @deprecated( + "Use :py:meth:`reduce_bands` with :py:class:`UDF <openeo.rest._datacube.UDF>` as reducer.", + version="0.13.0", + ) + def reduce_bands_udf(self, code: str, runtime: Optional[str] = None, version: Optional[str] = None) -> DataCube: + """ + Use `reduce_dimension` process with given UDF along band/spectral dimension. + """ + # TODO #181 #312 drop this deprecated pattern + return self.reduce_bands(reducer=UDF(code=code, runtime=runtime, version=version))
    + + +
    +[docs] + @openeo_process + def add_dimension(self, name: str, label: str, type: Optional[str] = None): + """ + Adds a new named dimension to the data cube. + Afterwards, 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. + + This call does not modify the datacube in place, but returns a new datacube with the additional dimension. + + :param name: The name of the dimension to add + :param label: The dimension label. + :param type: Dimension type, allowed values: 'spatial', 'temporal', 'bands', 'other', default value is 'other' + :return: The data cube with a newly added dimension. The new dimension has exactly one dimension label. All other dimensions remain unchanged. + """ + return self.process( + process_id="add_dimension", + arguments=dict_no_none({"data": self, "name": name, "label": label, "type": type}), + metadata=self.metadata.add_dimension(name=name, label=label, type=type) if self.metadata else None, + )
    + + +
    +[docs] + @openeo_process + def drop_dimension(self, name: str): + """ + Drops a dimension from the data cube. + Dropping 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. + + :param name: The name of the dimension to drop + :return: The data cube with the given dimension dropped. + """ + return self.process( + process_id="drop_dimension", + arguments={"data": self, "name": name}, + metadata=self.metadata.drop_dimension(name=name) if self.metadata else None, + )
    + + +
    +[docs] + @deprecated( + "Use :py:meth:`reduce_temporal` with :py:class:`UDF <openeo.rest._datacube.UDF>` as reducer", + version="0.13.0", + ) + def reduce_temporal_udf(self, code: str, runtime="Python", version="latest"): + """ + Apply reduce (`reduce_dimension`) process with given UDF along temporal dimension. + + :param code: The UDF code, compatible with the given runtime and version + :param runtime: The UDF runtime + :param version: The UDF runtime version + """ + # TODO #181 #312 drop this deprecated pattern + return self.reduce_temporal(reducer=UDF(code=code, runtime=runtime, version=version))
    + + + reduce_tiles_over_time = legacy_alias( + reduce_temporal_udf, name="reduce_tiles_over_time", since="0.1.1" + ) + +
    +[docs] + @openeo_process + def apply_neighborhood( + self, + process: Union[str, PGNode, typing.Callable, UDF], + size: List[Dict], + overlap: List[dict] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Applies a focal process to a data cube. + + A 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`. + + An 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 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. + + The process must not add new dimensions, or remove entire dimensions, but the result can have different dimension labels. + + For the special case of 2D convolution, it is recommended to use ``apply_kernel()``. + + :param size: + :param overlap: + :param process: a callback function that creates a process graph, see :ref:`callbackfunctions` + :param context: Additional data to be passed to the process. + + :return: + """ + return self.process( + process_id="apply_neighborhood", + arguments=dict_no_none( + data=THIS, + process=build_child_callback(process=process, parent_parameters=["data"], connection=self.connection), + size=size, + overlap=overlap, + context=context, + ) + )
    + + +
    +[docs] + @openeo_process + def apply( + self, + process: Union[str, typing.Callable, UDF, PGNode], + context: Optional[dict] = None, + ) -> DataCube: + """ + Applies a unary process (a local operation) to each value of the specified or all dimensions in the data cube. + + :param process: the "child callback": + the name of a single process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + + The callback should correspond to a process that + receives a single numerical value + and returns a single numerical value. + For example: + + - ``"absolute"`` (string) + - :py:func:`absolute <openeo.processes.absolute>` (:ref:`predefined openEO process function <openeo_processes_functions>`) + - ``lambda x: x * 2 + 3`` (function or lambda) + + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values. The resolution, cardinality and the number of dimensions are the same as for the original data cube. + """ + return self.process( + process_id="apply", + arguments=dict_no_none( + { + "data": THIS, + "process": build_child_callback(process, parent_parameters=["x"], connection=self.connection), + "context": context, + } + ), + )
    + + + reduce_temporal_simple = legacy_alias( + reduce_temporal, "reduce_temporal_simple", since="0.13.0" + ) + +
    +[docs] + @openeo_process(process_id="min", mode="reduce_dimension") + def min_time(self) -> DataCube: + """ + Finds the minimum value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("min")
    + + +
    +[docs] + @openeo_process(process_id="max", mode="reduce_dimension") + def max_time(self) -> DataCube: + """ + Finds the maximum value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("max")
    + + +
    +[docs] + @openeo_process(process_id="mean", mode="reduce_dimension") + def mean_time(self) -> DataCube: + """ + Finds the mean value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("mean")
    + + +
    +[docs] + @openeo_process(process_id="median", mode="reduce_dimension") + def median_time(self) -> DataCube: + """ + Finds the median value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("median")
    + + +
    +[docs] + @openeo_process(process_id="count", mode="reduce_dimension") + def count_time(self) -> DataCube: + """ + Counts the number of images with a valid mask in a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("count")
    + + +
    +[docs] + @openeo_process + def aggregate_temporal( + self, + intervals: List[list], + reducer: Union[str, typing.Callable, PGNode], + labels: Optional[List[str]] = None, + dimension: Optional[str] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Computes a temporal aggregation based on an array of date and/or time intervals. + + Calendar hierarchies such as year, month, week etc. must be transformed into specific intervals by the clients. For each interval, all data along the dimension will be passed through the reducer. The computed values will be projected to the labels, so the number of labels and the number of intervals need to be equal. + + If the dimension is not set, the data cube is expected to only have one temporal dimension. + + :param intervals: Temporal left-closed intervals so that the start time is contained, but not the end time. + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute <openeo.processes.max>` (:ref:`predefined openEO process function <openeo_processes_functions>`) + - ``lambda data: data.min()`` (function or lambda) + + :param labels: Labels for the intervals. The number of labels and the number of groups need to be equal. + :param dimension: The temporal dimension for aggregation. All data along the dimension will be passed through the specified reducer. If the dimension is not set, the data cube is expected to only have one temporal dimension. + :param context: Additional data to be passed to the reducer. Not set by default. + + :return: A :py:class:`DataCube` containing a result for each time window + """ + return self.process( + process_id="aggregate_temporal", + arguments=dict_no_none( + data=THIS, + intervals=intervals, + labels=labels, + dimension=dimension, + reducer=build_child_callback(reducer, parent_parameters=["data"]), + context=context, + ), + )
    + + +
    +[docs] + @openeo_process + def aggregate_temporal_period( + self, + period: str, + reducer: Union[str, PGNode, typing.Callable], + dimension: Optional[str] = None, + context: Optional[Dict] = None, + ) -> DataCube: + """ + Computes a temporal aggregation based on calendar hierarchies such as years, months or seasons. For other calendar hierarchies aggregate_temporal can be used. + + For each interval, all data along the dimension will be passed through the reducer. + + If the dimension is not set or is set to null, the data cube is expected to only have one temporal dimension. + + The period argument specifies the time intervals to aggregate. The following pre-defined values are available: + + - hour: Hour of the day + - day: Day of the year + - week: Week of the year + - 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. + - month: Month of the year + - season: Three month periods of the calendar seasons (December - February, March - May, June - August, September - November). + - tropical-season: Six month periods of the tropical seasons (November - April, May - October). + - year: Proleptic years + - decade: Ten year periods (0-to-9 decade), from a year ending in a 0 to the next year ending in a 9. + - decade-ad: Ten year periods (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. + + + :param period: The period of the time intervals to aggregate. + :param reducer: A reducer to be applied on all values along the specified dimension. The reducer must be a callable process (or a set processes) that accepts an array and computes a single return value of the same type as the input values, for example median. + :param dimension: The temporal dimension for aggregation. All data along the dimension will be passed through the specified reducer. If the dimension is not set, the data cube is expected to only have one temporal dimension. + :param context: Additional data to be passed to the reducer. + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference system and resolution) remain unchanged. + """ + return self.process( + process_id="aggregate_temporal_period", + arguments=dict_no_none( + data=THIS, + period=period, + dimension=dimension, + reducer=build_child_callback(reducer, parent_parameters=["data"]), + context=context, + ), + )
    + + +
    +[docs] + @openeo_process + def ndvi(self, nir: str = None, red: str = None, target_band: str = None) -> DataCube: + """ + Normalized Difference Vegetation Index (NDVI) + + :param nir: (optional) name of NIR band + :param red: (optional) name of red band + :param target_band: (optional) name of the newly created band + + :return: a DataCube instance + """ + if self.metadata is None: + metadata = None + elif target_band is None: + metadata = self.metadata.reduce_dimension(self.metadata.band_dimension.name) + else: + # TODO: first drop "bands" dim and re-add it with single "ndvi" band + metadata = self.metadata.append_band(Band(name=target_band, common_name="ndvi")) + return self.process( + process_id="ndvi", + arguments=dict_no_none( + data=THIS, nir=nir, red=red, target_band=target_band + ), + metadata=metadata, + )
    + + +
    +[docs] + @openeo_process + def rename_dimension(self, source: str, target: str): + """ + Renames a dimension in the data cube while preserving all other properties. + + :param source: The current name of the dimension. Fails with a DimensionNotAvailable error if the specified dimension does not exist. + :param target: A new Name for the dimension. Fails with a DimensionExists error if a dimension with the specified name exists. + + :return: A new datacube with the dimension renamed. + """ + if self._do_metadata_normalization() and target in self.metadata.dimension_names(): + raise ValueError('Target dimension name conflicts with existing dimension: %s.' % target) + return self.process( + process_id="rename_dimension", + arguments=dict_no_none( + data=THIS, + source=self._assert_valid_dimension_name(source), + target=target, + ), + metadata=self.metadata.rename_dimension(source, target) if self.metadata else None, + )
    + + +
    +[docs] + @openeo_process + def rename_labels(self, dimension: str, target: list, source: list = None) -> DataCube: + """ + Renames the labels of the specified dimension in the data cube from source to target. + + :param dimension: Dimension name + :param target: The new names for the labels. + :param source: The names of the labels as they are currently in the data cube. + + :return: An DataCube instance + """ + return self.process( + process_id="rename_labels", + arguments=dict_no_none( + data=THIS, + dimension=self._assert_valid_dimension_name(dimension), + target=target, + source=source, + ), + metadata=self.metadata.rename_labels(dimension, target, source) if self.metadata else None, + )
    + + +
    +[docs] + @openeo_process(mode="apply") + def linear_scale_range(self, input_min, input_max, output_min, output_max) -> DataCube: + """ + Performs a linear transformation between the input and output range. + + The 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. + + Potential use case include 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 or calculating percentages (0 - 100). + + The no-data value null is passed through and therefore gets propagated. + + :param input_min: Minimum input value + :param input_max: Maximum input value + :param output_min: Minimum value of the desired output range. + :param output_max: Maximum value of the desired output range. + :return: a DataCube instance + """ + + return self.apply(lambda x: x.linear_scale_range(input_min, input_max, output_min, output_max))
    + + +
    +[docs] + @openeo_process + def mask(self, mask: DataCube = None, replacement=None) -> DataCube: + """ + Applies a mask to a raster data cube. To apply a vector mask use `mask_polygon`. + + A 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). + + :param mask: the raster mask + :param replacement: the value to replace the masked pixels with + """ + return self.process( + process_id="mask", + arguments=dict_no_none(data=self, mask=mask, replacement=replacement), + )
    + + +
    +[docs] + @openeo_process + def mask_polygon( + self, + mask: Union[shapely.geometry.base.BaseGeometry, dict, str, pathlib.Path, Parameter, VectorCube], + srs: str = None, + replacement=None, + inside: bool = None, + ) -> DataCube: + """ + Applies a polygon mask to a raster data cube. To apply a raster mask use `mask`. + + All 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. + + The pixel values are replaced with the value specified for `replacement`, + which defaults to `no data`. + + :param mask: The geometry to mask with: a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param srs: The spatial reference system of the provided polygon. + By default longitude-latitude (EPSG:4326) is assumed. + + .. note:: this ``srs`` argument is a non-standard/experimental feature, only supported by specific back-ends. + See https://github.com/Open-EO/openeo-processes/issues/235 for details. + :param replacement: the value to replace the masked pixels with + """ + valid_geojson_types = ["Polygon", "MultiPolygon", "GeometryCollection", "Feature", "FeatureCollection"] + mask = self._get_geometry_argument(mask, valid_geojson_types=valid_geojson_types, crs=srs) + return self.process( + process_id="mask_polygon", + arguments=dict_no_none( + data=THIS, + mask=mask, + replacement=replacement, + inside=inside + ) + )
    + + +
    +[docs] + @openeo_process + def merge_cubes( + self, + other: DataCube, + overlap_resolver: Union[str, PGNode, typing.Callable] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Merging two data cubes + + 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. + An 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. + + Examples for merging two data cubes: + + #. 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. + #. 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. + #. Data cubes with the dimensions x, y and t have the same dimension labels in x,y and t. There are two options: + * 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. + * 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. + #. 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. + + :param other: The data cube to merge with. + :param overlap_resolver: A reduction operator that resolves the conflict if the data overlaps. The reducer must return a value of the same data type as the input values are. The reduction operator may be a single process such as multiply or consist of multiple sub-processes. null (the default) can be specified if no overlap resolver is required. + :param context: Additional data to be passed to the process. + + :return: The merged data cube. + """ + arguments = {"cube1": self, "cube2": other} + if overlap_resolver: + arguments["overlap_resolver"] = build_child_callback(overlap_resolver, parent_parameters=["x", "y"]) + if ( + self.metadata + and self.metadata.has_band_dimension() + and isinstance(other, DataCube) + and other.metadata + and other.metadata.has_band_dimension() + ): + # Minimal client side metadata merging + merged_metadata = self.metadata + for b in other.metadata.band_dimension.bands: + if b not in merged_metadata.bands: + merged_metadata = merged_metadata.append_band(b) + else: + merged_metadata = None + # Overlapping bands without overlap resolver will give an error in the backend + if context: + arguments["context"] = context + return self.process(process_id="merge_cubes", arguments=arguments, metadata=merged_metadata)
    + + + merge = legacy_alias(merge_cubes, name="merge", since="0.4.6") + +
    +[docs] + @openeo_process + def apply_kernel( + self, kernel: Union[np.ndarray, List[List[float]]], factor=1.0, border=0, + replace_invalid=0 + ) -> DataCube: + """ + Applies a focal operation based on a weighted kernel to each value of the specified dimensions in the data cube. + + The border parameter determines how the data is extended when the kernel overlaps with the borders. + The following options are available: + + * numeric value - fill with a user-defined constant number n: nnnnnn|abcdefgh|nnnnnn (default, with n = 0) + * replicate - repeat the value from the pixel at the border: aaaaaa|abcdefgh|hhhhhh + * reflect - mirror/reflect from the border: fedcba|abcdefgh|hgfedc + * reflect_pixel - mirror/reflect from the center of the pixel at the border: gfedcb|abcdefgh|gfedcb + * wrap - repeat/wrap the image: cdefgh|abcdefgh|abcdef + + + :param kernel: The kernel to be applied on the data cube. The kernel has to be as many dimensions as the data cube has dimensions. + :param factor: A factor that is multiplied to each value computed by the focal operation. This is basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often required for some kernel-based algorithms such as the Gaussian blur. + :param border: Determines how the data is extended when the kernel overlaps with the borders. Defaults to fill the border with zeroes. + :param replace_invalid: This parameter specifies the value to replace non-numerical or infinite numerical values with. By default, those values are replaced with zeroes. + :return: A data cube with the newly computed values. The resolution, cardinality and the number of dimensions are the same as for the original data cube. + """ + return self.process('apply_kernel', { + 'data': THIS, + 'kernel': kernel.tolist() if isinstance(kernel, np.ndarray) else kernel, + 'factor': factor, + 'border': border, + 'replace_invalid': replace_invalid + })
    + + +
    +[docs] + @openeo_process + def resolution_merge( + self, high_resolution_bands: List[str], low_resolution_bands: List[str], method: str = None + ) -> DataCube: + """ + Resolution merging algorithms try to improve the spatial resolution of lower resolution bands + (e.g. Sentinel-2 20M) based on higher resolution bands. (e.g. Sentinel-2 10M). + + External references: + + `Pansharpening explained <https://bok.eo4geo.eu/IP2-1-3>`_ + + `Example publication: 'Improving the Spatial Resolution of Land Surface Phenology by Fusing Medium- and + Coarse-Resolution Inputs' <https://doi.org/10.1109/TGRS.2016.2537929>`_ + + .. warning:: experimental process: not generally supported, API subject to change. + + :param high_resolution_bands: A list of band names to use as 'high-resolution' band. 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. The 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. These bands will remain unmodified. + :param low_resolution_bands: A list of band names for which the spatial resolution should be increased. 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. The 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. These bands will be modified by the process. + :param method: The method to use. The supported algorithms can vary between back-ends. Set to `null` (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility.. + :return: A datacube with the same bands and metadata as the input, but algorithmically increased spatial resolution for the selected bands. + """ + return self.process('resolution_merge', { + 'data': THIS, + 'high_resolution_bands': high_resolution_bands, + 'low_resolution_bands': low_resolution_bands, + 'method': method, + + })
    + + +
    +[docs] + def raster_to_vector(self) -> VectorCube: + """ + Converts this raster data cube into a :py:class:`~openeo.rest.vectorcube.VectorCube`. + The bounding polygon of homogenous areas of pixels is constructed. + + .. warning:: experimental process: not generally supported, API subject to change. + + :return: a :py:class:`~openeo.rest.vectorcube.VectorCube` + """ + pg_node = PGNode(process_id="raster_to_vector", arguments={"data": self}) + return VectorCube(pg_node, connection=self._connection)
    + + + ####VIEW methods ####### + +
    +[docs] + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'mean'``.", version="0.10.0" + ) + def polygonal_mean_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a mean time series for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="mean")
    + + +
    +[docs] + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'histogram'``.", + version="0.10.0", + ) + def polygonal_histogram_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a histogram time series for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="histogram")
    + + +
    +[docs] + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'median'``.", version="0.10.0" + ) + def polygonal_median_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a median time series for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="median")
    + + +
    +[docs] + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'sd'``.", version="0.10.0" + ) + def polygonal_standarddeviation_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a time series of standard deviations for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="sd")
    + + +
    +[docs] + @openeo_process + def ard_surface_reflectance( + self, atmospheric_correction_method: str, cloud_detection_method: str, elevation_model: str = None, + atmospheric_correction_options: dict = None, cloud_detection_options: dict = None, + ) -> DataCube: + """ + Computes CARD4L compliant surface reflectance values from optical input. + + :param atmospheric_correction_method: The atmospheric correction method to use. + :param cloud_detection_method: The cloud detection method to use. + :param elevation_model: The digital elevation model to use, leave empty to allow the back-end to make a suitable choice. + :param atmospheric_correction_options: Proprietary options for the atmospheric correction method. + :param cloud_detection_options: Proprietary options for the cloud detection method. + :return: Data cube containing bottom of atmosphere reflectances with atmospheric disturbances like clouds and cloud shadows removed. The data returned is CARD4L compliant and contains metadata. + """ + return self.process('ard_surface_reflectance', { + 'data': THIS, + 'atmospheric_correction_method': atmospheric_correction_method, + 'cloud_detection_method': cloud_detection_method, + 'elevation_model': elevation_model, + 'atmospheric_correction_options': atmospheric_correction_options or {}, + 'cloud_detection_options': cloud_detection_options or {}, + })
    + + +
    +[docs] + @openeo_process + def atmospheric_correction(self, method: str = None, elevation_model: str = None, options: dict = None) -> DataCube: + """ + Applies an atmospheric correction that converts top of atmosphere reflectance values into bottom of atmosphere/top of canopy reflectance values. + + Note that multiple atmospheric methods exist, but may not be supported by all backends. The method parameter gives + you the option of requiring a specific method, but this may result in an error if the backend does not support it. + + :param method: The atmospheric correction method to use. To get reproducible results, you have to set a specific method. Set 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. + :param elevation_model: The digital elevation model to use, leave empty to allow the back-end to make a suitable choice. + :param options: Proprietary options for the atmospheric correction method. + :return: datacube with bottom of atmosphere reflectances + """ + return self.process('atmospheric_correction', { + 'data': THIS, + 'method': method, + 'elevation_model': elevation_model, + 'options': options or {}, + })
    + + +
    +[docs] + @openeo_process + def save_result( + self, + format: str = _DEFAULT_RASTER_FORMAT, + options: Optional[dict] = None, + ) -> DataCube: + formats = set(self._connection.list_output_formats().keys()) + # TODO: map format to correct casing too? + if format.lower() not in {f.lower() for f in formats}: + raise ValueError("Invalid format {f!r}. Should be one of {s}".format(f=format, s=formats)) + return self.process( + process_id="save_result", + arguments={ + "data": THIS, + "format": format, + # TODO: leave out options if unset? + "options": options or {} + } + )
    + + + def _ensure_save_result( + self, + format: Optional[str] = None, + options: Optional[dict] = None, + ) -> DataCube: + """ + Make sure there is a (final) `save_result` node in the process graph. + If there is already one: check if it is consistent with the given format/options (if any) + and add a new one otherwise. + + :param format: (optional) desired `save_result` file format + :param options: (optional) desired `save_result` file format parameters + :return: + """ + # TODO #401 Unify with VectorCube._ensure_save_result and move to generic data cube parent class (not only for raster cubes, but also vector cubes) + result_node = self.result_node() + if result_node.process_id == "save_result": + # There is already a `save_result` node: + # check if it is consistent with given format/options (if any) + args = result_node.arguments + if format is not None and format.lower() != args["format"].lower(): + raise ValueError( + f"Existing `save_result` node with different format {args['format']!r} != {format!r}" + ) + if options is not None and options != args["options"]: + raise ValueError( + f"Existing `save_result` node with different options {args['options']!r} != {options!r}" + ) + cube = self + else: + # No `save_result` node yet: automatically add it. + cube = self.save_result( + format=format or self._DEFAULT_RASTER_FORMAT, options=options + ) + return cube + +
    +[docs] + def download( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + format: Optional[str] = None, + options: Optional[dict] = None, + *, + validate: Optional[bool] = None, + ) -> Union[None, bytes]: + """ + Execute synchronously and download the raster data cube, e.g. as GeoTIFF. + + If outputfile is provided, the result is stored on disk locally, otherwise, a bytes object is returned. + The bytes object can be passed on to a suitable decoder for decoding. + + :param outputfile: Optional, an output file if the result needs to be stored on disk. + :param format: Optional, an output format supported by the backend. + :param options: Optional, file format options + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + :return: None if the result is stored to disk, or a bytes object returned by the backend. + """ + if format is None and outputfile: + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + format = guess_format(outputfile) + cube = self._ensure_save_result(format=format, options=options) + return self._connection.download(cube.flat_graph(), outputfile, validate=validate)
    + + +
    +[docs] + def validate(self) -> List[dict]: + """ + Validate a process graph without executing it. + + :return: list of errors (dictionaries with "code" and "message" fields) + """ + return self._connection.validate_process_graph(self.flat_graph())
    + + + def tiled_viewing_service(self, type: str, **kwargs) -> Service: + return self._connection.create_service(self.flat_graph(), type=type, **kwargs) + + def _get_spatial_extent_from_load_collection(self): + pg = self.flat_graph() + for node in pg: + if pg[node]["process_id"] == "load_collection": + if "spatial_extent" in pg[node]["arguments"] and all( + cd in pg[node]["arguments"]["spatial_extent"] for cd in ["east", "west", "south", "north"] + ): + return pg[node]["arguments"]["spatial_extent"] + return None + +
    +[docs] + def preview( + self, + center: Union[Iterable, None] = None, + zoom: Union[int, None] = None, + ): + """ + Creates a service with the process graph and displays a map widget. Only supports XYZ. + + :param center: (optional) Map center. Default is (0,0). + :param zoom: (optional) Zoom level of the map. Default is 1. + + :return: ipyleaflet Map object and the displayed Service + + .. warning:: experimental feature, subject to change. + .. versionadded:: 0.19.0 + """ + if "XYZ" not in self.connection.list_service_types(): + raise OpenEoClientException("Backend does not support service type 'XYZ'.") + + if not in_jupyter_context(): + raise Exception("On-demand preview only supported in Jupyter notebooks!") + try: + import ipyleaflet + except ImportError: + raise Exception( + "Additional modules must be installed for on-demand preview. Run `pip install openeo[jupyter]` or refer to the documentation." + ) + + service = self.tiled_viewing_service("XYZ") + service_metadata = service.describe_service() + + m = ipyleaflet.Map( + center=center or (0, 0), + zoom=zoom or 1, + scroll_wheel_zoom=True, + basemap=ipyleaflet.basemaps.OpenStreetMap.Mapnik, + ) + service_layer = ipyleaflet.TileLayer(url=service_metadata["url"]) + m.add(service_layer) + + if center is None and zoom is None: + spatial_extent = self._get_spatial_extent_from_load_collection() + if spatial_extent is not None: + m.fit_bounds( + [ + [spatial_extent["south"], spatial_extent["west"]], + [spatial_extent["north"], spatial_extent["east"]], + ] + ) + + class Preview: + """ + On-demand preview instance holding the associated XYZ service and ipyleaflet Map + """ + + def __init__(self, service: Service, ipyleaflet_map: ipyleaflet.Map): + self.service = service + self.map = ipyleaflet_map + + def _repr_html_(self): + from IPython.display import display + + display(self.map) + + def delete_service(self): + self.service.delete_service() + + return Preview(service, m)
    + + +
    +[docs] + def execute_batch( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + out_format: Optional[str] = None, + *, + print: typing.Callable[[str], None] = print, + max_poll_interval: float = 60, + connection_retry_interval: float = 30, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + # TODO: avoid `format_options` as keyword arguments + **format_options, + ) -> BatchJob: + """ + Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. + This method is mostly recommended if the batch job is expected to run in a reasonable amount of time. + + For very long-running jobs, you probably do not want to keep the client running. + + :param outputfile: The path of a file to which a result can be written + :param out_format: (optional) File format to use for the job result. + :param job_options: + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + """ + if "format" in format_options and not out_format: + out_format = format_options["format"] # align with 'download' call arg name + if out_format is None and outputfile: + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + out_format = guess_format(outputfile) + + job = self.create_job(out_format=out_format, job_options=job_options, validate=validate, **format_options) + return job.run_synchronous( + outputfile=outputfile, + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + )
    + + +
    +[docs] + def create_job( + self, + out_format: Optional[str] = None, + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + # TODO: avoid `format_options` as keyword arguments + **format_options, + ) -> BatchJob: + """ + Sends the datacube's process graph as a batch job to the back-end + and return a :py:class:`~openeo.rest.job.BatchJob` instance. + + Note that the batch job will just be created at the back-end, + it still needs to be started and tracked explicitly. + Use :py:meth:`execute_batch` instead to have the openEO Python client take care of that job management. + + :param out_format: output file format. + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param job_options: custom job options. + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: Created job. + """ + # TODO: add option to also automatically start the job? + # TODO: avoid using all kwargs as format_options + # TODO: centralize `create_job` for `DataCube`, `VectorCube`, `MlModel`, ... + cube = self._ensure_save_result(format=out_format, options=format_options or None) + return self._connection.create_job( + process_graph=cube.flat_graph(), + title=title, + description=description, + plan=plan, + budget=budget, + validate=validate, + additional=job_options, + )
    + + + send_job = legacy_alias(create_job, name="send_job", since="0.10.0") + +
    +[docs] + def save_user_defined_process( + self, + user_defined_process_id: str, + public: bool = False, + summary: Optional[str] = None, + description: Optional[str] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, + ) -> RESTUserDefinedProcess: + """ + Saves this process graph in the backend as a user-defined process for the authenticated user. + + :param user_defined_process_id: unique identifier for the process + :param public: visible to other users? + :param summary: A short summary of what the process does. + :param description: Detailed description to explain the entity. CommonMark 0.29 syntax MAY be used for rich text representation. + :param returns: Description and schema of the return value. + :param categories: A list of categories. + :param examples: A list of examples. + :param links: A list of links. + :return: a RESTUserDefinedProcess instance + """ + return self._connection.save_user_defined_process( + user_defined_process_id=user_defined_process_id, + process_graph=self.flat_graph(), public=public, summary=summary, description=description, + returns=returns, categories=categories, examples=examples, links=links, + )
    + + +
    +[docs] + def execute(self, *, validate: Optional[bool] = None) -> dict: + """Executes the process graph.""" + return self._connection.execute(self.flat_graph(), validate=validate)
    + + +
    +[docs] + @staticmethod + @deprecated(reason="Use :py:func:`openeo.udf.run_code.execute_local_udf` instead", version="0.7.0") + def execute_local_udf(udf: str, datacube: Union[str, 'xarray.DataArray', 'XarrayDataCube'] = None, fmt='netcdf'): + import openeo.udf.run_code + return openeo.udf.run_code.execute_local_udf(udf=udf, datacube=datacube, fmt=fmt)
    + + +
    +[docs] + @openeo_process + def ard_normalized_radar_backscatter( + self, elevation_model: str = None, contributing_area=False, + ellipsoid_incidence_angle: bool = False, noise_removal: bool = True + ) -> DataCube: + """ + Computes CARD4L compliant backscatter (gamma0) from SAR input. + This method is a variant of :py:meth:`~openeo.rest.datacube.DataCube.sar_backscatter`, + with restricted parameters to generate backscatter according to CARD4L specifications. + + Note 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. + + :param elevation_model: The digital elevation model to use. Set to None (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility. + :param contributing_area: If set to `true`, a DEM-based local contributing area band named `contributing_area` + is added. The values are given in square meters. + :param ellipsoid_incidence_angle: If set to `True`, an ellipsoidal incidence angle band named `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `True`, which removes noise. + + :return: Backscatter values expressed as gamma0. The data returned is CARD4L compliant and contains metadata. By default, the backscatter values are given in linear scale. + """ + return self.process(process_id="ard_normalized_radar_backscatter", arguments={ + "data": THIS, + "elevation_model": elevation_model, + "contributing_area": contributing_area, + "ellipsoid_incidence_angle": ellipsoid_incidence_angle, + "noise_removal": noise_removal + })
    + + +
    +[docs] + @openeo_process + def sar_backscatter( + self, + coefficient: Union[str, None] = "gamma0-terrain", + elevation_model: Union[str, None] = None, + mask: bool = False, + contributing_area: bool = False, + local_incidence_angle: bool = False, + ellipsoid_incidence_angle: bool = False, + noise_removal: bool = True, + options: Optional[dict] = None + ) -> DataCube: + """ + Computes backscatter from SAR input. + + Note 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. + + :param coefficient: Select the radiometric correction coefficient. + The following options are available: + + - `"beta0"`: radar brightness + - `"sigma0-ellipsoid"`: ground area computed with ellipsoid earth model + - `"sigma0-terrain"`: ground area computed with terrain earth model + - `"gamma0-ellipsoid"`: ground area computed with ellipsoid earth model in sensor line of sight + - `"gamma0-terrain"`: ground area computed with terrain earth model in sensor line of sight (default) + - `None`: non-normalized backscatter + :param elevation_model: The digital elevation model to use. Set to `None` (the default) to allow + the back-end to choose, which will improve portability, but reduce reproducibility. + :param mask: 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). + :param contributing_area: If set to `true`, a DEM-based local contributing area band named `contributing_area` + is added. The values are given in square meters. + :param local_incidence_angle: If set to `true`, a DEM-based local incidence angle band named + `local_incidence_angle` is added. The values are given in degrees. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes noise. + :param options: dictionary with additional (backend-specific) options. + :return: + + .. versionadded:: 0.4.9 + .. versionchanged:: 0.4.10 replace `orthorectify` and `rtc` arguments with `coefficient`. + """ + coefficient_options = [ + "beta0", "sigma0-ellipsoid", "sigma0-terrain", "gamma0-ellipsoid", "gamma0-terrain", None + ] + if coefficient not in coefficient_options: + raise OpenEoClientException("Invalid `sar_backscatter` coefficient {c!r}. Should be one of {o}".format( + c=coefficient, o=coefficient_options + )) + arguments = { + "data": THIS, + "coefficient": coefficient, + "elevation_model": elevation_model, + "mask": mask, + "contributing_area": contributing_area, + "local_incidence_angle": local_incidence_angle, + "ellipsoid_incidence_angle": ellipsoid_incidence_angle, + "noise_removal": noise_removal, + } + if options: + arguments["options"] = options + return self.process(process_id="sar_backscatter", arguments=arguments)
    + + +
    +[docs] + @openeo_process + def fit_curve(self, parameters: list, function: Union[str, PGNode, typing.Callable], dimension: str): + """ + Use non-linear least squares to fit a model function `y = f(x, parameters)` to data. + + The process throws an `InvalidValues` exception if invalid values are encountered. + Invalid values are finite numbers (see also ``is_valid()``). + + .. warning:: experimental process: not generally supported, API subject to change. + https://github.com/Open-EO/openeo-processes/pull/240 + + :param parameters: + :param function: "child callback" function, see :ref:`callbackfunctions` + :param dimension: + """ + # TODO: does this return a `DataCube`? Shouldn't it just return an array (wrapper)? + return self.process( + process_id="fit_curve", + arguments={ + "data": THIS, + "parameters": parameters, + "function": build_child_callback(function, parent_parameters=["x", "parameters"]), + "dimension": dimension, + }, + )
    + + +
    +[docs] + @openeo_process + def predict_curve( + self, parameters: list, function: Union[str, PGNode, typing.Callable], dimension: str, + labels=None + ): + """ + Predict values using a model function and pre-computed parameters. + + .. warning:: experimental process: not generally supported, API subject to change. + https://github.com/Open-EO/openeo-processes/pull/240 + + :param parameters: + :param function: "child callback" function, see :ref:`callbackfunctions` + :param dimension: + """ + return self.process( + process_id="predict_curve", + arguments={ + "data": THIS, + "parameters": parameters, + "function": build_child_callback(function, parent_parameters=["x", "parameters"]), + "dimension": dimension, + "labels": labels, + }, + )
    + + +
    +[docs] + @openeo_process(mode="reduce_dimension") + def predict_random_forest(self, model: Union[str, BatchJob, MlModel], dimension: str = "bands"): + """ + Apply ``reduce_dimension`` process with a ``predict_random_forest`` reducer. + + :param model: a reference to a trained model, one of + + - a :py:class:`~openeo.rest.mlmodel.MlModel` instance (e.g. loaded from :py:meth:`Connection.load_ml_model`) + - a :py:class:`~openeo.rest.job.BatchJob` instance of a batch job that saved a single random forest model + - a job id (``str``) of a batch job that saved a single random forest model + - a STAC item URL (``str``) to load the random forest from. + (The STAC Item must implement the `ml-model` extension.) + :param dimension: dimension along which to apply the ``reduce_dimension`` process. + + .. versionadded:: 0.10.0 + """ + if not isinstance(model, MlModel): + model = MlModel.load_ml_model(connection=self.connection, id=model) + reducer = PGNode( + process_id="predict_random_forest", data={"from_parameter": "data"}, model={"from_parameter": "context"} + ) + return self.reduce_dimension(dimension=dimension, reducer=reducer, context=model)
    + + +
    +[docs] + @openeo_process + def dimension_labels(self, dimension: str) -> DataCube: + """ + Gives all labels for a dimension in the data cube. The labels have the same order as in the data cube. + + :param dimension: The name of the dimension to get the labels for. + """ + if self._do_metadata_normalization(): + dimension_names = self.metadata.dimension_names() + if dimension_names and dimension not in dimension_names: + raise ValueError(f"Invalid dimension name {dimension!r}, should be one of {dimension_names}") + return self.process(process_id="dimension_labels", arguments={"data": THIS, "dimension": dimension})
    + + +
    +[docs] + @openeo_process + def flatten_dimensions(self, dimensions: List[str], target_dimension: str, label_separator: Optional[str] = None): + """ + Combines multiple given dimensions into a single dimension by flattening the values + and merging the dimension labels with the given `label_separator`. Non-string dimension labels will + be converted to strings. This process is the opposite of the process :py:meth:`unflatten_dimension()` + but executing both processes subsequently doesn't necessarily create a data cube that + is equal to the original data cube. + + :param dimensions: The names of the dimension to combine. + :param target_dimension: The name of a target dimension with a single dimension label to replace. + :param label_separator: The string that will be used as a separator for the concatenated dimension labels. + :return: A data cube with the new shape. + + .. warning:: experimental process: not generally supported, API subject to change. + .. versionadded:: 0.10.0 + """ + return self.process( + process_id="flatten_dimensions", + arguments=dict_no_none( + data=THIS, + dimensions=dimensions, + target_dimension=target_dimension, + label_separator=label_separator, + ), + )
    + + +
    +[docs] + @openeo_process + def unflatten_dimension(self, dimension: str, target_dimensions: List[str], label_separator: Optional[str] = None): + """ + Splits a single dimension into multiple dimensions by systematically extracting values and splitting + the dimension labels by the given `label_separator`. + This process is the opposite of the process :py:meth:`flatten_dimensions()` but executing both processes + subsequently doesn't necessarily create a data cube that is equal to the original data cube. + + :param dimension: The name of the dimension to split. + :param target_dimensions: The names of the target dimensions. + :param label_separator: The string that will be used as a separator to split the dimension labels. + :return: A data cube with the new shape. + + .. warning:: experimental process: not generally supported, API subject to change. + .. versionadded:: 0.10.0 + """ + return self.process( + process_id="unflatten_dimension", + arguments=dict_no_none( + data=THIS, + dimension=dimension, + target_dimensions=target_dimensions, + label_separator=label_separator, + ), + )
    +
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/graph_building.html b/_modules/openeo/rest/graph_building.html new file mode 100644 index 000000000..5d4a1dc44 --- /dev/null +++ b/_modules/openeo/rest/graph_building.html @@ -0,0 +1,206 @@ + + + + + + + openeo.rest.graph_building — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.graph_building

    +"""
    +Public openEO process graph building utilities
    +'''''''''''''''''''''''''''''''''''''''''''''''
    +
    +"""
    +from __future__ import annotations
    +
    +from typing import Optional
    +
    +from openeo.internal.graph_building import PGNode, _FromNodeMixin
    +from openeo.processes import ProcessBuilder
    +
    +
    +
    +[docs] +class CollectionProperty(_FromNodeMixin): + """ + Helper object to easily create simple collection metadata property filters + to be used with :py:meth:`Connection.load_collection() <openeo.rest.connection.Connection.load_collection>`. + + .. note:: This class should not be used directly by end user code. + Use the :py:func:`~openeo.rest.graph_building.collection_property` factory instead. + + .. warning:: this is an experimental feature, naming might change. + """ + + def __init__(self, name: str, _builder: Optional[ProcessBuilder] = None): + self.name = name + self._builder = _builder or ProcessBuilder(pgnode={"from_parameter": "value"}) + + def from_node(self) -> PGNode: + return self._builder.from_node() + + def __eq__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder == other) + + def __ne__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder != other) + + def __gt__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder > other) + + def __ge__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder >= other) + + def __lt__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder < other) + + def __le__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder <= other)
    + + + +
    +[docs] +def collection_property(name: str) -> CollectionProperty: + """ + Helper to easily create simple collection metadata property filters + to be used with :py:meth:`Connection.load_collection() <openeo.rest.connection.Connection.load_collection>`. + + Usage example: + + .. code-block:: python + + from openeo import collection_property + ... + + connection.load_collection( + ... + properties=[ + collection_property("eo:cloud_cover") <= 75, + collection_property("platform") == "Sentinel-2B", + ] + ) + + .. warning:: this is an experimental feature, naming might change. + + .. versionadded:: 0.26.0 + + :param name: name of the collection property to filter on + :return: an object that supports operators like ``<=``, ``==`` to easily build simple property filters. + """ + return CollectionProperty(name=name)
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/job.html b/_modules/openeo/rest/job.html new file mode 100644 index 000000000..a9d970753 --- /dev/null +++ b/_modules/openeo/rest/job.html @@ -0,0 +1,734 @@ + + + + + + + openeo.rest.job — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.job

    +from __future__ import annotations
    +
    +import datetime
    +import json
    +import logging
    +import time
    +import typing
    +from pathlib import Path
    +from typing import Dict, List, Optional, Union
    +
    +import requests
    +
    +from openeo.api.logs import LogEntry, log_level_name, normalize_log_level
    +from openeo.internal.documentation import openeo_endpoint
    +from openeo.internal.jupyter import (
    +    VisualDict,
    +    VisualList,
    +    render_component,
    +    render_error,
    +)
    +from openeo.internal.warnings import deprecated, legacy_alias
    +from openeo.rest import JobFailedException, OpenEoApiError, OpenEoClientException, OpenEoApiPlainError
    +from openeo.util import ensure_dir
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    from openeo.rest.connection import Connection
    +
    +logger = logging.getLogger(__name__)
    +
    +
    +
    +[docs] +class BatchJob: + """ + Handle for an openEO batch job, allowing it to describe, start, cancel, inspect results, etc. + + .. versionadded:: 0.11.0 + This class originally had the more cryptic name :py:class:`RESTJob`, + which is still available as legacy alias, + but :py:class:`BatchJob` is recommended since version 0.11.0. + + """ + + # TODO #425 method to bootstrap `load_stac` directly from a BatchJob object + + def __init__(self, job_id: str, connection: Connection): + self.job_id = job_id + """Unique identifier of the batch job (string).""" + + self.connection = connection + + def __repr__(self): + return '<{c} job_id={i!r}>'.format(c=self.__class__.__name__, i=self.job_id) + + def _repr_html_(self): + data = self.describe() + currency = self.connection.capabilities().currency() + return render_component('job', data=data, parameters={'currency': currency}) + +
    +[docs] + @openeo_endpoint("GET /jobs/{job_id}") + def describe(self) -> dict: + """ + Get detailed metadata about a submitted batch job + (title, process graph, status, progress, ...). + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`describe_job`. + """ + return self.connection.get(f"/jobs/{self.job_id}", expected_status=200).json()
    + + + describe_job = legacy_alias(describe, since="0.20.0", mode="soft") + +
    +[docs] + def status(self) -> str: + """ + Get the status of the batch job + + :return: batch job status, one of "created", "queued", "running", "canceled", "finished" or "error". + """ + return self.describe().get("status", "N/A")
    + + +
    +[docs] + @openeo_endpoint("DELETE /jobs/{job_id}") + def delete(self): + """ + Delete this batch job. + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`delete_job`. + """ + self.connection.delete(f"/jobs/{self.job_id}", expected_status=204)
    + + + delete_job = legacy_alias(delete, since="0.20.0", mode="soft") + +
    +[docs] + @openeo_endpoint("GET /jobs/{job_id}/estimate") + def estimate(self): + """Calculate time/cost estimate for a job.""" + data = self.connection.get( + f"/jobs/{self.job_id}/estimate", expected_status=200 + ).json() + currency = self.connection.capabilities().currency() + return VisualDict('job-estimate', data=data, parameters={'currency': currency})
    + + + estimate_job = legacy_alias(estimate, since="0.20.0", mode="soft") + +
    +[docs] + @openeo_endpoint("POST /jobs/{job_id}/results") + def start(self) -> BatchJob: + """ + Start this batch job. + + :return: Started batch job + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`start_job`. + """ + self.connection.post(f"/jobs/{self.job_id}/results", expected_status=202) + return self
    + + + start_job = legacy_alias(start, since="0.20.0", mode="soft") + +
    +[docs] + @openeo_endpoint("DELETE /jobs/{job_id}/results") + def stop(self): + """ + Stop this batch job. + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`stop_job`. + """ + self.connection.delete(f"/jobs/{self.job_id}/results", expected_status=204)
    + + + stop_job = legacy_alias(stop, since="0.20.0", mode="soft") + +
    +[docs] + def get_results_metadata_url(self, *, full: bool = False) -> str: + """Get results metadata URL""" + url = f"/jobs/{self.job_id}/results" + if full: + url = self.connection.build_url(url) + return url
    + + +
    +[docs] + @deprecated("Use :py:meth:`~BatchJob.get_results` instead.", version="0.4.10") + def list_results(self) -> dict: + """Get batch job results metadata.""" + return self.get_results().get_metadata()
    + + +
    +[docs] + def download_result(self, target: Union[str, Path] = None) -> Path: + """ + Download single job result to the target file path or into folder (current working dir by default). + + Fails if there are multiple result files. + + :param target: String or path where the file should be downloaded to. + """ + return self.get_results().download_file(target=target)
    + + +
    +[docs] + @deprecated( + "Instead use :py:meth:`BatchJob.get_results` and the more flexible download functionality of :py:class:`JobResults`", + version="0.4.10") + def download_results(self, target: Union[str, Path] = None) -> Dict[Path, dict]: + """ + Download all job result files into given folder (current working dir by default). + + The names of the files are taken directly from the backend. + + :param target: String/path, folder where to put the result files. + :return: file_list: Dict containing the downloaded file path as value and asset metadata + """ + return self.get_result().download_files(target)
    + + +
    +[docs] + @deprecated("Use :py:meth:`BatchJob.get_results` instead.", version="0.4.10") + def get_result(self): + return _Result(self)
    + + +
    +[docs] + def get_results(self) -> JobResults: + """ + Get handle to batch job results for result metadata inspection or downloading resulting assets. + + .. versionadded:: 0.4.10 + """ + return JobResults(job=self)
    + + +
    +[docs] + def logs( + self, offset: Optional[str] = None, level: Optional[Union[str, int]] = None + ) -> List[LogEntry]: + """Retrieve job logs. + + :param offset: The last identifier (property ``id`` of a LogEntry) the client has received. + + If provided, the back-ends only sends the entries that occurred after the specified identifier. + If not provided or empty, start with the first entry. + + Defaults to None. + + :param level: Minimum log level to retrieve. + + You can use either constants from Python's standard module ``logging`` + or their names (case-insensitive). + + For example: + ``logging.INFO``, ``"info"`` or ``"INFO"`` can all be used to show the messages + for level ``logging.INFO`` and above, i.e. also ``logging.WARNING`` and + ``logging.ERROR`` will be included. + + Default is to show all log levels, in other words ``logging.DEBUG``. + This is also the result when you explicitly pass log_level=None or log_level="". + + :return: A list containing the log entries for the batch job. + """ + url = f"/jobs/{self.job_id}/logs" + params = {} + if offset is not None: + params["offset"] = offset + if level is not None: + params["level"] = log_level_name(level) + response = self.connection.get(url, params=params, expected_status=200) + logs = response.json()["logs"] + + # Only filter logs when specified. + # We should still support client-side log_level filtering because not all backends + # support the minimum log level parameter. + if level is not None: + log_level = normalize_log_level(level) + logs = ( + log + for log in logs + if normalize_log_level(log.get("level")) >= log_level + ) + + entries = [LogEntry(log) for log in logs] + return VisualList("logs", data=entries)
    + + +
    +[docs] + def run_synchronous( + self, outputfile: Union[str, Path, None] = None, + print=print, max_poll_interval=60, connection_retry_interval=30 + ) -> BatchJob: + """Start the job, wait for it to finish and download result""" + self.start_and_wait( + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + ) + # TODO #135 support multi file result sets too? + if outputfile is not None: + self.download_result(outputfile) + return self
    + + +
    +[docs] + def start_and_wait( + self, print=print, max_poll_interval: int = 60, connection_retry_interval: int = 30, soft_error_max=10 + ) -> BatchJob: + """ + Start the batch job, poll its status and wait till it finishes (or fails) + + :param print: print/logging function to show progress/status + :param max_poll_interval: maximum number of seconds to sleep between status polls + :param connection_retry_interval: how long to wait when status poll failed due to connection issue + :param soft_error_max: maximum number of soft errors (e.g. temporary connection glitches) to allow + :return: + """ + # TODO rename `connection_retry_interval` to something more generic? + start_time = time.time() + + def elapsed() -> str: + return str(datetime.timedelta(seconds=time.time() - start_time)).rsplit(".")[0] + + def print_status(msg: str): + print("{t} Job {i!r}: {m}".format(t=elapsed(), i=self.job_id, m=msg)) + + # TODO: make `max_poll_interval`, `connection_retry_interval` class constants or instance properties? + print_status("send 'start'") + self.start() + + # TODO: also add `wait` method so you can track a job that already has started explicitly + # or just rename this method to `wait` and automatically do start if not started yet? + + # Start with fast polling. + poll_interval = min(5, max_poll_interval) + status = None + _soft_error_count = 0 + + def soft_error(message: str): + """Non breaking error (unless we had too much of them)""" + nonlocal _soft_error_count + _soft_error_count += 1 + if _soft_error_count > soft_error_max: + raise OpenEoClientException("Excessive soft errors") + print_status(message) + time.sleep(connection_retry_interval) + + while True: + # TODO: also allow a hard time limit on this infinite poll loop? + try: + job_info = self.describe() + except requests.ConnectionError as e: + soft_error("Connection error while polling job status: {e}".format(e=e)) + continue + except OpenEoApiPlainError as e: + if e.http_status_code in [502, 503]: + soft_error("Service availability error while polling job status: {e}".format(e=e)) + continue + else: + raise + + status = job_info.get("status", "N/A") + progress = '{p}%'.format(p=job_info["progress"]) if "progress" in job_info else "N/A" + print_status("{s} (progress {p})".format(s=status, p=progress)) + if status not in ('submitted', 'created', 'queued', 'running'): + break + + # Sleep for next poll (and adaptively make polling less frequent) + time.sleep(poll_interval) + poll_interval = min(1.25 * poll_interval, max_poll_interval) + + if status != "finished": + # TODO: allow to disable this printing logs (e.g. in non-interactive contexts)? + # TODO: render logs jupyter-aware in a notebook context? + print(f"Your batch job {self.job_id!r} failed. Error logs:") + print(self.logs(level=logging.ERROR)) + print( + f"Full logs can be inspected in an openEO (web) editor or with `connection.job({self.job_id!r}).logs()`." + ) + raise JobFailedException( + f"Batch job {self.job_id!r} didn't finish successfully. Status: {status} (after {elapsed()}).", + job=self, + ) + + return self
    +
    + + + +
    +[docs] +@deprecated(reason="Use :py:class:`BatchJob` instead", version="0.11.0") +class RESTJob(BatchJob): + """ + Legacy alias for :py:class:`BatchJob`. + """
    + + + +
    +[docs] +class ResultAsset: + """ + Result asset of a batch job (e.g. a GeoTIFF or JSON file) + + .. versionadded:: 0.4.10 + """ + + def __init__(self, job: BatchJob, name: str, href: str, metadata: dict): + self.job = job + + self.name = name + """Asset name as advertised by the backend.""" + + self.href = href + """Download URL of the asset.""" + + self.metadata = metadata + """Asset metadata provided by the backend, possibly containing keys "type" (for media type), "roles", "title", "description".""" + + def __repr__(self): + return "<ResultAsset {n!r} (type {t}) at {h!r}>".format( + n=self.name, t=self.metadata.get("type", "unknown"), h=self.href + ) + +
    +[docs] + def download(self, target: Optional[Union[Path, str]] = None, chunk_size=None) -> Path: + """ + Download asset to given location + + :param target: download target path. Can be an existing folder + (in which case the filename advertised by backend will be used) + or full file name. By default, the working directory will be used. + """ + target = Path(target or Path.cwd()) + if target.is_dir(): + target = target / self.name + ensure_dir(target.parent) + logger.info("Downloading Job result asset {n!r} from {h!s} to {t!s}".format(n=self.name, h=self.href, t=target)) + with target.open("wb") as f: + response = self._get_response(stream=True) + for block in response.iter_content(chunk_size=chunk_size): + f.write(block) + return target
    + + + def _get_response(self, stream=True) -> requests.Response: + return self.job.connection.get(self.href, stream=stream) + +
    +[docs] + def load_json(self) -> dict: + """Load asset in memory and parse as JSON.""" + if not (self.name.lower().endswith(".json") or self.metadata.get("type") == "application/json"): + logger.warning("Asset might not be JSON") + return self._get_response().json()
    + + +
    +[docs] + def load_bytes(self) -> bytes: + """Load asset in memory as raw bytes.""" + return self._get_response().content
    +
    + + + # TODO: more `load` methods e.g.: load GTiff asset directly as numpy array + + +class MultipleAssetException(OpenEoClientException): + pass + + +
    +[docs] +class JobResults: + """ + Results of a batch job: listing of one or more output files (assets) + and some metadata. + + .. versionadded:: 0.4.10 + """ + + def __init__(self, job: BatchJob): + self._job = job + self._results = None + + def __repr__(self): + return "<JobResults for job {j!r}>".format(j=self._job.job_id) + + def _repr_html_(self): + try: + response = self.get_metadata() + return render_component("batch-job-result", data = response) + except OpenEoApiError as error: + return render_error(error) + +
    +[docs] + def get_metadata(self, force=False) -> dict: + """Get batch job results metadata (parsed JSON)""" + if self._results is None or force: + self._results = self._job.connection.get( + self._job.get_results_metadata_url(), expected_status=200 + ).json() + return self._results
    + + + # TODO: provide methods for `stac_version`, `id`, `geometry`, `properties`, `links`, ...? + +
    +[docs] + def get_assets(self) -> List[ResultAsset]: + """ + Get all assets from the job results. + """ + # TODO: add arguments to filter on metadata, e.g. to only get assets of type "image/tiff" + metadata = self.get_metadata() + # API 1.0 style: dictionary mapping filenames to metadata dict (with at least a "href" field) + assets = metadata.get("assets", {}) + if not assets: + logger.warning("No assets found in job result metadata.") + return [ + ResultAsset(job=self._job, name=name, href=asset["href"], metadata=asset) + for name, asset in assets.items() + ]
    + + +
    +[docs] + def get_asset(self, name: str = None) -> ResultAsset: + """ + Get single asset by name or without name if there is only one. + """ + # TODO: also support getting a single asset by type or role? + assets = self.get_assets() + if len(assets) == 0: + raise OpenEoClientException("No assets in result.") + if name is None: + if len(assets) == 1: + return assets[0] + else: + raise MultipleAssetException("Multiple result assets for job {j}: {a}".format( + j=self._job.job_id, a=[a.name for a in assets] + )) + else: + try: + return next(a for a in assets if a.name == name) + except StopIteration: + raise OpenEoClientException( + "No asset {n!r} in: {a}".format(n=name, a=[a.name for a in assets]) + )
    + + +
    +[docs] + def download_file(self, target: Union[Path, str] = None, name: str = None) -> Path: + """ + Download single asset. Can be used when there is only one asset in the + :py:class:`JobResults`, or when the desired asset name is given explicitly. + + :param target: path to download to. Can be an existing directory + (in which case the filename advertised by backend will be used) + or full file name. By default, the working directory will be used. + :param name: asset name to download (not required when there is only one asset) + :return: path of downloaded asset + """ + try: + return self.get_asset(name=name).download(target=target) + except MultipleAssetException: + raise OpenEoClientException( + "Can not use `download_file` with multiple assets. Use `download_files` instead.")
    + + +
    +[docs] + def download_files(self, target: Union[Path, str] = None, include_stac_metadata: bool = True) -> List[Path]: + """ + Download all assets to given folder. + + :param target: path to folder to download to (must be a folder if it already exists) + :param include_stac_metadata: whether to download the job result metadata as a STAC (JSON) file. + :return: list of paths to the downloaded assets. + """ + target = Path(target or Path.cwd()) + if target.exists() and not target.is_dir(): + raise OpenEoClientException(f"Target argument {target} exists but isn't a folder.") + ensure_dir(target) + + downloaded = [a.download(target) for a in self.get_assets()] + + if include_stac_metadata: + # TODO #184: convention for metadata file name? + metadata_file = target / "job-results.json" + # TODO #184: rewrite references to locally downloaded assets? + metadata_file.write_text(json.dumps(self.get_metadata())) + downloaded.append(metadata_file) + + return downloaded
    +
    + + + +@deprecated(reason="Use :py:class:`JobResults` instead", version="0.4.10") +class _Result: + """ + Wrapper around `JobResults` to adapt old deprecated "Result" API. + + .. deprecated:: 0.4.10 + """ + + # TODO: deprecated: remove this + + def __init__(self, job): + self.results = JobResults(job=job) + + def download_file(self, target: Union[str, Path] = None) -> Path: + return self.results.download_file(target=target) + + def download_files(self, target: Union[str, Path] = None) -> Dict[Path, dict]: + target = Path(target or Path.cwd()) + if target.exists() and not target.is_dir(): + raise OpenEoClientException(f"Target argument {target} exists but isn't a folder.") + return {a.download(target): a.metadata for a in self.results.get_assets()} + + def load_json(self) -> dict: + return self.results.get_asset().load_json() + + def load_bytes(self) -> bytes: + return self.results.get_asset().load_bytes() +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/mlmodel.html b/_modules/openeo/rest/mlmodel.html new file mode 100644 index 000000000..e721fa62d --- /dev/null +++ b/_modules/openeo/rest/mlmodel.html @@ -0,0 +1,254 @@ + + + + + + + openeo.rest.mlmodel — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.mlmodel

    +from __future__ import annotations
    +
    +import logging
    +import pathlib
    +import typing
    +from typing import Optional, Union
    +
    +from openeo.internal.documentation import openeo_process
    +from openeo.internal.graph_building import PGNode
    +from openeo.rest._datacube import _ProcessGraphAbstraction
    +from openeo.rest.job import BatchJob
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    from openeo import Connection
    +
    +_log = logging.getLogger(__name__)
    +
    +
    +
    +[docs] +class MlModel(_ProcessGraphAbstraction): + """ + A machine learning model. + + It is the result of a training procedure, e.g. output of a ``fit_...`` process, + and can be used for prediction (classification or regression) with the corresponding ``predict_...`` process. + + .. versionadded:: 0.10.0 + """ + + def __init__(self, graph: PGNode, connection: Connection): + super().__init__(pgnode=graph, connection=connection) + +
    +[docs] + def save_ml_model(self, options: Optional[dict] = None): + """ + Saves a machine learning model as part of a batch job. + + :param options: Additional parameters to create the file(s). + """ + pgnode = PGNode( + process_id="save_ml_model", + arguments={"data": self, "options": options or {}} + ) + return MlModel(graph=pgnode, connection=self._connection)
    + + +
    +[docs] + @staticmethod + @openeo_process + def load_ml_model(connection: Connection, id: Union[str, BatchJob]) -> MlModel: + """ + Loads a machine learning model from a STAC Item. + + :param connection: connection object + :param id: STAC item reference, as URL, batch job (id) or user-uploaded file + :return: + + .. versionadded:: 0.10.0 + """ + if isinstance(id, BatchJob): + id = id.job_id + return MlModel(graph=PGNode(process_id="load_ml_model", id=id), connection=connection)
    + + +
    +[docs] + def execute_batch( + self, + outputfile: Union[str, pathlib.Path], + print=print, max_poll_interval=60, connection_retry_interval=30, + job_options=None, + ) -> BatchJob: + """ + Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. + This method is mostly recommended if the batch job is expected to run in a reasonable amount of time. + + For very long running jobs, you probably do not want to keep the client running. + + :param job_options: + :param outputfile: The path of a file to which a result can be written + :param out_format: (optional) Format of the job result. + :param format_options: String Parameters for the job result format + """ + job = self.create_job(job_options=job_options) + return job.run_synchronous( + # TODO #135 support multi file result sets too + outputfile=outputfile, + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + )
    + + +
    +[docs] + def create_job( + self, + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + job_options: Optional[dict] = None, + ) -> BatchJob: + """ + Sends a job to the backend and returns a ClientJob instance. + + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param job_options: A dictionary containing (custom) job options + :param format_options: String Parameters for the job result format + :return: Created job. + """ + # TODO: centralize `create_job` for `DataCube`, `VectorCube`, `MlModel`, ... + pg = self + if pg.result_node().process_id not in {"save_ml_model"}: + _log.warning("Process graph has no final `save_ml_model`. Adding it automatically.") + pg = pg.save_ml_model() + return self._connection.create_job( + process_graph=pg.flat_graph(), + title=title, + description=description, + plan=plan, + budget=budget, + additional=job_options, + )
    +
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/udp.html b/_modules/openeo/rest/udp.html new file mode 100644 index 000000000..e3f548104 --- /dev/null +++ b/_modules/openeo/rest/udp.html @@ -0,0 +1,263 @@ + + + + + + + openeo.rest.udp — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.udp

    +from __future__ import annotations
    +
    +import typing
    +from typing import List, Optional, Union
    +
    +from openeo.api.process import Parameter
    +from openeo.internal.graph_building import as_flat_graph, FlatGraphableMixin
    +from openeo.internal.jupyter import render_component
    +from openeo.internal.processes.builder import ProcessBuilderBase
    +from openeo.internal.warnings import deprecated
    +from openeo.util import dict_no_none
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    from openeo.rest.connection import Connection
    +
    +
    +
    +[docs] +def build_process_dict( + process_graph: Union[dict, FlatGraphableMixin], + process_id: Optional[str] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + parameters: Optional[List[Union[Parameter, dict]]] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, +) -> dict: + """ + Build a dictionary describing a process with metadaa (`process_graph`, `parameters`, `description`, ...) + + :param process_graph: dict or builder representing a process graph + :param process_id: identifier of the process + :param summary: short summary of what the process does + :param description: detailed description + :param parameters: list of process parameters (which have name, schema, default value, ...) + :param returns: description and schema of what the process returns + :param categories: list of categories + :param examples: list of examples, may be used for unit tests + :param links: list of links related to the process + :return: dictionary in openEO "process graph with metadata" format + """ + process = dict_no_none( + process_graph=as_flat_graph(process_graph), + id=process_id, + summary=summary, + description=description, + returns=returns, + categories=categories, + examples=examples, + links=links + ) + if parameters is not None: + process["parameters"] = [ + (p if isinstance(p, Parameter) else Parameter(**p)).to_dict() + for p in parameters + ] + return process
    + + + +
    +[docs] +class RESTUserDefinedProcess: + """ + Wrapper for a user-defined process stored (or to be stored) on an openEO back-end + """ + + def __init__(self, user_defined_process_id: str, connection: Connection): + self.user_defined_process_id = user_defined_process_id + self._connection = connection + self._connection.assert_user_defined_process_support() + + def _repr_html_(self): + process = self.describe() + return render_component('process', data=process, parameters = {'show-graph': True, 'provide-download': False}) + +
    +[docs] + def store( + self, + process_graph: Union[dict, FlatGraphableMixin], + parameters: Optional[List[Union[Parameter, dict]]] = None, + public: bool = False, + summary: Optional[str] = None, + description: Optional[str] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, + ): + """Store a process graph and its metadata on the backend as a user-defined process""" + process = build_process_dict( + process_graph=process_graph, parameters=parameters, + summary=summary, description=description, returns=returns, + categories=categories, examples=examples, links=links, + ) + + # TODO: this "public" flag is not standardized yet EP-3609, https://github.com/Open-EO/openeo-api/issues/310 + process["public"] = public + + self._connection._preflight_validation(pg_with_metadata=process) + self._connection.put( + path="/process_graphs/{}".format(self.user_defined_process_id), json=process, expected_status=200 + )
    + + +
    +[docs] + @deprecated( + "Use `store` instead. Method `update` is misleading: OpenEO API does not provide (partial) updates" + " of user-defined processes, only fully overwriting 'store' operations.", + version="0.4.11") + def update( + self, process_graph: Union[dict, ProcessBuilderBase], parameters: List[Union[Parameter, dict]] = None, + public: bool = False, summary: str = None, description: str = None + ): + self.store(process_graph=process_graph, parameters=parameters, public=public, summary=summary, + description=description)
    + + +
    +[docs] + def describe(self) -> dict: + """Get metadata of this user-defined process.""" + # TODO: parse the "parameters" to Parameter objects? + return self._connection.get(path="/process_graphs/{}".format(self.user_defined_process_id)).json()
    + + +
    +[docs] + def delete(self) -> None: + """Remove user-defined process from back-end""" + self._connection.delete(path="/process_graphs/{}".format(self.user_defined_process_id), expected_status=204)
    + + + def validate(self) -> None: + raise NotImplementedError
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/userfile.html b/_modules/openeo/rest/userfile.html new file mode 100644 index 000000000..cc9755bf7 --- /dev/null +++ b/_modules/openeo/rest/userfile.html @@ -0,0 +1,239 @@ + + + + + + + openeo.rest.userfile — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.userfile

    +from __future__ import annotations
    +
    +import typing
    +from pathlib import Path, PurePosixPath
    +from typing import Any, Dict, Optional, Union
    +
    +from openeo.util import ensure_dir
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    from openeo.rest.connection import Connection
    +
    +
    +
    +[docs] +class UserFile: + """ + Handle to a (user-uploaded) file in the user workspace on a openEO back-end. + """ + + def __init__( + self, + path: Union[str, PurePosixPath, None], + *, + connection: Connection, + metadata: Optional[dict] = None, + ): + if path: + pass + elif metadata and metadata.get("path"): + path = metadata.get("path") + else: + raise ValueError( + "File path should be specified through `path` or `metadata` argument." + ) + + self.path = PurePosixPath(path) + self.metadata = metadata or {"path": path} + self.connection = connection + +
    +[docs] + @classmethod + def from_metadata(cls, metadata: dict, connection: Connection) -> UserFile: + """Build :py:class:`UserFile` from a workspace file metadata dictionary.""" + return cls(path=None, connection=connection, metadata=metadata)
    + + + def __repr__(self): + return "<{c} file={i!r}>".format(c=self.__class__.__name__, i=self.path) + + def _get_endpoint(self) -> str: + return f"/files/{self.path!s}" + +
    +[docs] + def download(self, target: Union[Path, str] = None) -> Path: + """ + Downloads a user-uploaded file from the user workspace on the back-end + locally to the given location. + + :param target: local download target path. Can be an existing folder + (in which case the file name advertised by backend will be used) + or full file name. By default, the working directory will be used. + """ + response = self.connection.get( + self._get_endpoint(), expected_status=200, stream=True + ) + + target = Path(target or Path.cwd()) + if target.is_dir(): + target = target / self.path.name + ensure_dir(target.parent) + + with target.open(mode="wb") as f: + for chunk in response.iter_content(chunk_size=None): + f.write(chunk) + + return target
    + + +
    +[docs] + def upload(self, source: Union[Path, str]) -> UserFile: + """ + Uploads a local file to the path corresponding to this :py:class:`UserFile` in the user workspace + and returns new :py:class:`UserFile` of newly uploaded file. + + .. tip:: + Usually you'll just need + :py:meth:`Connection.upload_file() <openeo.rest.connection.Connection.upload_file>` + instead of this :py:class:`UserFile` method. + + If the file exists in the user workspace it will be replaced. + + :param source: A path to a file on the local file system to upload. + :return: new :py:class:`UserFile` instance of the newly uploaded file + """ + return self.connection.upload_file(source, target=self.path)
    + + +
    +[docs] + def delete(self): + """Delete the user-uploaded file from the user workspace on the back-end.""" + self.connection.delete(self._get_endpoint(), expected_status=204)
    + + +
    +[docs] + def to_dict(self) -> Dict[str, Any]: + """Returns the provided metadata as dict.""" + # This is used in internal/jupyter.py to detect and get the original metadata. + # TODO: make this more explicit with an internal API? + return self.metadata
    +
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/rest/vectorcube.html b/_modules/openeo/rest/vectorcube.html new file mode 100644 index 000000000..66db1e4bc --- /dev/null +++ b/_modules/openeo/rest/vectorcube.html @@ -0,0 +1,725 @@ + + + + + + + openeo.rest.vectorcube — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.rest.vectorcube

    +from __future__ import annotations
    +
    +import json
    +import pathlib
    +import typing
    +from typing import Callable, List, Optional, Tuple, Union
    +
    +import shapely.geometry.base
    +
    +from openeo.api.process import Parameter
    +from openeo.internal.documentation import openeo_process
    +from openeo.internal.graph_building import PGNode
    +from openeo.internal.warnings import legacy_alias
    +from openeo.metadata import CollectionMetadata, Dimension
    +from openeo.rest._datacube import (
    +    THIS,
    +    UDF,
    +    _ProcessGraphAbstraction,
    +    build_child_callback,
    +)
    +from openeo.rest.job import BatchJob
    +from openeo.rest.mlmodel import MlModel
    +from openeo.util import InvalidBBoxException, dict_no_none, guess_format, to_bbox_dict
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    from openeo import Connection
    +
    +
    +
    +[docs] +class VectorCube(_ProcessGraphAbstraction): + """ + A Vector Cube, or 'Vector Collection' is a data structure containing 'Features': + https://www.w3.org/TR/sdw-bp/#dfn-feature + + The features in this cube are restricted to have a geometry. Geometries can be points, lines, polygons etcetera. + A geometry is specified in a 'coordinate reference system'. https://www.w3.org/TR/sdw-bp/#dfn-coordinate-reference-system-(crs) + """ + + def __init__(self, graph: PGNode, connection: Connection, metadata: Optional[CollectionMetadata] = None): + super().__init__(pgnode=graph, connection=connection) + self.metadata = metadata + + @classmethod + def _build_metadata(cls, add_properties: bool = False) -> CollectionMetadata: + """Helper to build a (minimal) `CollectionMetadata` object.""" + # Vector cubes have at least a "geometry" dimension + dimensions = [Dimension(name="geometry", type="geometry")] + if add_properties: + dimensions.append(Dimension(name="properties", type="other")) + # TODO #464: use a more generic metadata container than "collection" metadata + return CollectionMetadata(metadata={}, dimensions=dimensions) + +
    +[docs] + def process( + self, + process_id: str, + arguments: dict = None, + metadata: Optional[CollectionMetadata] = None, + namespace: Optional[str] = None, + **kwargs, + ) -> VectorCube: + """ + Generic helper to create a new DataCube by applying a process. + + :param process_id: process id of the process. + :param args: argument dictionary for the process. + :return: new VectorCube instance + """ + pg = self._build_pgnode(process_id=process_id, arguments=arguments, namespace=namespace, **kwargs) + return VectorCube(graph=pg, connection=self._connection, metadata=metadata or self.metadata)
    + + +
    +[docs] + @classmethod + @openeo_process + def load_geojson( + cls, + connection: Connection, + data: Union[dict, str, pathlib.Path, shapely.geometry.base.BaseGeometry, Parameter], + properties: Optional[List[str]] = None, + ) -> VectorCube: + """ + Converts GeoJSON data as defined by RFC 7946 into a vector data cube. + + :param connection: the connection to use to connect with the openEO back-end. + :param data: the geometry to load. One of: + + - GeoJSON-style data structure: e.g. a dictionary with ``"type": "Polygon"`` and ``"coordinates"`` fields + - a path to a local GeoJSON file + - a GeoJSON string + - a shapely geometry object + + :param properties: A list of properties from the GeoJSON file to construct an additional dimension from. + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + # TODO: unify with `DataCube._get_geometry_argument` + # TODO #457 also support client side fetching of GeoJSON from URL? + if isinstance(data, str) and data.strip().startswith("{"): + # Assume JSON dump + geometry = json.loads(data) + elif isinstance(data, (str, pathlib.Path)): + # Assume local file + with pathlib.Path(data).open(mode="r", encoding="utf-8") as f: + geometry = json.load(f) + assert isinstance(geometry, dict) + elif isinstance(data, shapely.geometry.base.BaseGeometry): + geometry = shapely.geometry.mapping(data) + elif isinstance(data, Parameter): + geometry = data + elif isinstance(data, dict): + geometry = data + else: + raise ValueError(data) + # TODO #457 client side verification of GeoJSON construct: valid type, valid structure, presence of CRS, ...? + + pg = PGNode(process_id="load_geojson", data=geometry, properties=properties or []) + # TODO #457 always a "properties" dimension? https://github.com/Open-EO/openeo-processes/issues/448 + metadata = cls._build_metadata(add_properties=True) + return cls(graph=pg, connection=connection, metadata=metadata)
    + + +
    +[docs] + @classmethod + @openeo_process + def load_url(cls, connection: Connection, url: str, format: str, options: Optional[dict] = None) -> VectorCube: + """ + Loads a file from a URL + + :param connection: the connection to use to connect with the openEO back-end. + :param url: The URL to read from. Authentication details such as API keys or tokens may need to be included in the URL. + :param format: The file format to use when loading the data. + :param options: The file format parameters to use when reading the data. + Must correspond to the parameters that the server reports as supported parameters for the chosen ``format`` + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + pg = PGNode(process_id="load_url", arguments=dict_no_none(url=url, format=format, options=options)) + # TODO #457 always a "properties" dimension? https://github.com/Open-EO/openeo-processes/issues/448 + metadata = cls._build_metadata(add_properties=True) + return cls(graph=pg, connection=connection, metadata=metadata)
    + + +
    +[docs] + @openeo_process + def run_udf( + self, + udf: Union[str, UDF], + runtime: Optional[str] = None, + version: Optional[str] = None, + context: Optional[dict] = None, + ) -> VectorCube: + """ + Run a UDF on the vector cube. + + It is recommended to provide the UDF just as :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + (the other arguments could be used to override UDF parameters if necessary). + + :param udf: UDF code as a string or :py:class:`UDF <openeo.rest._datacube.UDF>` instance + :param runtime: UDF runtime + :param version: UDF version + :param context: UDF context + + .. warning:: EXPERIMENTAL: not generally supported, API subject to change. + + .. versionadded:: 0.10.0 + + .. versionchanged:: 0.16.0 + Added support to pass self-contained :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + """ + if isinstance(udf, UDF): + # `UDF` instance is preferred usage pattern, but allow overriding. + version = version or udf.version + context = context or udf.context + runtime = runtime or udf.get_runtime(connection=self.connection) + udf = udf.code + else: + if not runtime: + raise ValueError("Argument `runtime` must be specified") + return self.process( + process_id="run_udf", + data=self, udf=udf, runtime=runtime, + arguments=dict_no_none({"version": version, "context": context}), + )
    + + +
    +[docs] + @openeo_process + def save_result(self, format: Union[str, None] = "GeoJSON", options: dict = None): + # TODO #401: guard against duplicate save_result nodes? + return self.process( + process_id="save_result", + arguments={ + "data": self, + "format": format or "GeoJSON", + "options": options or {}, + }, + )
    + + + def _ensure_save_result( + self, + format: Optional[str] = None, + options: Optional[dict] = None, + ) -> VectorCube: + """ + Make sure there is a (final) `save_result` node in the process graph. + If there is already one: check if it is consistent with the given format/options (if any) + and add a new one otherwise. + + :param format: (optional) desired `save_result` file format + :param options: (optional) desired `save_result` file format parameters + :return: + """ + # TODO #401 Unify with DataCube._ensure_save_result and move to generic data cube parent class + result_node = self.result_node() + if result_node.process_id == "save_result": + # There is already a `save_result` node: + # check if it is consistent with given format/options (if any) + args = result_node.arguments + if format is not None and format.lower() != args["format"].lower(): + raise ValueError(f"Existing `save_result` node with different format {args['format']!r} != {format!r}") + if options is not None and options != args["options"]: + raise ValueError( + f"Existing `save_result` node with different options {args['options']!r} != {options!r}" + ) + cube = self + else: + # No `save_result` node yet: automatically add it. + cube = self.save_result(format=format or "GeoJSON", options=options) + return cube + +
    +[docs] + def execute(self, *, validate: Optional[bool] = None) -> dict: + """Executes the process graph.""" + return self._connection.execute(self.flat_graph(), validate=validate)
    + + +
    +[docs] + def download( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + format: Optional[str] = None, + options: Optional[dict] = None, + *, + validate: Optional[bool] = None, + ) -> Union[None, bytes]: + """ + Execute synchronously and download the vector cube. + + The result will be stored to the output path, when specified. + If no output path (or ``None``) is given, the raw download content will be returned as ``bytes`` object. + + :param outputfile: (optional) output file to store the result to + :param format: (optional) output format to use. + :param options: (optional) additional output format options. + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + .. versionchanged:: 0.21.0 + When not specified explicitly, output format is guessed from output file extension. + + """ + # TODO #401 make outputfile optional (See DataCube.download) + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + if format is None and outputfile: + format = guess_format(outputfile) + cube = self._ensure_save_result(format=format, options=options) + return self._connection.download(cube.flat_graph(), outputfile=outputfile, validate=validate)
    + + +
    +[docs] + def execute_batch( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + out_format: Optional[str] = None, + *, + print=print, + max_poll_interval: float = 60, + connection_retry_interval: float = 30, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + # TODO: avoid using kwargs as format options + **format_options, + ) -> BatchJob: + """ + Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. + This method is mostly recommended if the batch job is expected to run in a reasonable amount of time. + + For very long running jobs, you probably do not want to keep the client running. + + :param job_options: + :param outputfile: The path of a file to which a result can be written + :param out_format: (optional) output format to use. + :param format_options: (optional) additional output format options + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + .. versionchanged:: 0.21.0 + When not specified explicitly, output format is guessed from output file extension. + """ + if out_format is None and outputfile: + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + out_format = guess_format(outputfile) + + job = self.create_job(out_format, job_options=job_options, validate=validate, **format_options) + return job.run_synchronous( + # TODO #135 support multi file result sets too + outputfile=outputfile, + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + )
    + + +
    +[docs] + def create_job( + self, + out_format: Optional[str] = None, + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + **format_options, + ) -> BatchJob: + """ + Sends a job to the backend and returns a ClientJob instance. + + :param out_format: String Format of the job result. + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param job_options: A dictionary containing (custom) job options + :param format_options: String Parameters for the job result format + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: Created job. + """ + # TODO: avoid using all kwargs as format_options + # TODO: centralize `create_job` for `DataCube`, `VectorCube`, `MlModel`, ... + cube = self._ensure_save_result(format=out_format, options=format_options or None) + return self._connection.create_job( + process_graph=cube.flat_graph(), + title=title, + description=description, + plan=plan, + budget=budget, + additional=job_options, + validate=validate, + )
    + + + send_job = legacy_alias(create_job, name="send_job", since="0.10.0") + +
    +[docs] + @openeo_process + def filter_bands(self, bands: List[str]) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + return self.process( + process_id="filter_bands", + arguments={"data": THIS, "bands": bands}, + )
    + + +
    +[docs] + @openeo_process + def filter_bbox( + self, + *, + west: Optional[float] = None, + south: Optional[float] = None, + east: Optional[float] = None, + north: Optional[float] = None, + extent: Optional[Union[dict, List[float], Tuple[float, float, float, float], Parameter]] = None, + crs: Optional[int] = None, + ) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + if any(c is not None for c in [west, south, east, north]): + if extent is not None: + raise InvalidBBoxException("Don't specify both west/south/east/north and extent") + extent = dict_no_none(west=west, south=south, east=east, north=north) + + if isinstance(extent, Parameter): + pass + else: + extent = to_bbox_dict(extent, crs=crs) + return self.process( + process_id="filter_bbox", + arguments={"data": THIS, "extent": extent}, + )
    + + +
    +[docs] + @openeo_process + def filter_labels( + self, condition: Union[PGNode, Callable], dimension: str, context: Optional[dict] = None + ) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + condition = build_child_callback(condition, parent_parameters=["value"]) + return self.process( + process_id="filter_labels", + arguments=dict_no_none(data=THIS, condition=condition, dimension=dimension, context=context), + )
    + + +
    +[docs] + @openeo_process + def filter_vector( + self, geometries: Union["VectorCube", shapely.geometry.base.BaseGeometry, dict], relation: str = "intersects" + ) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + if not isinstance(geometries, (VectorCube, Parameter)): + geometries = self.load_geojson(connection=self.connection, data=geometries) + return self.process( + process_id="filter_vector", + arguments={"data": THIS, "geometries": geometries, "relation": relation}, + )
    + + +
    +[docs] + @openeo_process + def fit_class_random_forest( + self, + # TODO #279 #293: target type should be `VectorCube` (with adapters for GeoJSON FeatureCollection, GeoPandas, ...) + target: dict, + # TODO #293 max_variables officially has no default + max_variables: Optional[int] = None, + num_trees: int = 100, + seed: Optional[int] = None, + ) -> MlModel: + """ + Executes the fit of a random forest classification based on the user input of target and predictors. + The Random Forest classification model is based on the approach by Breiman (2001). + + .. warning:: EXPERIMENTAL: not generally supported, API subject to change. + + :param target: The training sites for the classification model as a vector data cube. This is associated with the target + variable for the Random Forest model. The geometry has to be associated with a value to predict (e.g. fractional + forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. Default value is `null`, which corresponds to the + number of predictors divided by 3. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. + + .. versionadded:: 0.16.0 + Originally added in version 0.10.0 as :py:class:`DataCube <openeo.rest.datacube.DataCube>` method, + but moved to :py:class:`VectorCube` in version 0.16.0. + """ + pgnode = PGNode( + process_id="fit_class_random_forest", + arguments=dict_no_none( + predictors=self, + # TODO #279 strictly per-spec, target should be a `vector-cube`, but due to lack of proper support we are limited to inline GeoJSON for now + target=target, + max_variables=max_variables, + num_trees=num_trees, + seed=seed, + ), + ) + model = MlModel(graph=pgnode, connection=self._connection) + return model
    + + +
    +[docs] + @openeo_process + def fit_regr_random_forest( + self, + # TODO #279 #293: target type should be `VectorCube` (with adapters for GeoJSON FeatureCollection, GeoPandas, ...) + target: dict, + # TODO #293 max_variables officially has no default + max_variables: Optional[int] = None, + num_trees: int = 100, + seed: Optional[int] = None, + ) -> MlModel: + """ + Executes the fit of a random forest regression based on training data. + The Random Forest regression model is based on the approach by Breiman (2001). + + .. warning:: EXPERIMENTAL: not generally supported, API subject to change. + + :param target: The training sites for the regression model as a vector data cube. + This is associated with the target variable for the Random Forest model. + The geometry has to associated with a value to predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. Default value is `null`, which corresponds to the + number of predictors divided by 3. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. + + .. versionadded:: 0.16.0 + Originally added in version 0.10.0 as :py:class:`DataCube <openeo.rest.datacube.DataCube>` method, + but moved to :py:class:`VectorCube` in version 0.16.0. + """ + # TODO #279 #293: `fit_class_random_forest` should be defined on VectorCube instead of DataCube + pgnode = PGNode( + process_id="fit_regr_random_forest", + arguments=dict_no_none( + predictors=self, + # TODO #279 strictly per-spec, target should be a `vector-cube`, but due to lack of proper support we are limited to inline GeoJSON for now + target=target, + max_variables=max_variables, + num_trees=num_trees, + seed=seed, + ), + ) + model = MlModel(graph=pgnode, connection=self._connection) + return model
    + + +
    +[docs] + @openeo_process + def apply_dimension( + self, + process: Union[str, typing.Callable, UDF, PGNode], + dimension: str, + target_dimension: Optional[str] = None, + context: Optional[dict] = None, + ) -> VectorCube: + """ + Applies a process to all values along a dimension of a data cube. + For example, if the temporal dimension is specified the process will work on the values of a time series. + + The process to apply is specified by providing a callback function in the `process` argument. + + :param process: the "child callback": + the name of a single process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF <openeo.rest._datacube.UDF>` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns an array of numerical values. + For example: + + - ``"sort"`` (string) + - :py:func:`sort <openeo.processes.sort>` (:ref:`predefined openEO process function <openeo_processes_functions>`) + - ``lambda data: data.concat([42, -3])`` (function or lambda) + + + :param dimension: The name of the source dimension to apply the process on. Fails with a DimensionNotAvailable error if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or null (the default) to use the source dimension + specified in the parameter dimension. By 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. + :param context: Additional data to be passed to the process. + + :return: A datacube with the UDF applied to the given dimension. + :raises: DimensionNotAvailable + + .. versionadded:: 0.22.0 + """ + process = build_child_callback( + process=process, parent_parameters=["data", "context"], connection=self.connection + ) + arguments = dict_no_none( + { + "data": THIS, + "process": process, + "dimension": dimension, + "target_dimension": target_dimension, + "context": context, + } + ) + return self.process(process_id="apply_dimension", arguments=arguments)
    +
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/udf/debug.html b/_modules/openeo/udf/debug.html new file mode 100644 index 000000000..71578ec4b --- /dev/null +++ b/_modules/openeo/udf/debug.html @@ -0,0 +1,155 @@ + + + + + + + openeo.udf.debug — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.udf.debug

    +"""
    +Debug utilities for UDFs
    +"""
    +import logging
    +import os
    +import sys
    +
    +_log = logging.getLogger(__name__)
    +_user_log = logging.getLogger(os.environ.get("OPENEO_UDF_USER_LOGGER", f"{__name__}.user"))
    +
    +
    +
    +[docs] +def inspect(data=None, message: str = "", code: str = "User", level: str = "info"): + """ + Implementation of the openEO `inspect` process for UDF contexts. + + Note that it is up to the back-end implementation to properly capture this logging + and include it in the batch job logs. + + :param data: data to log + :param message: message to send in addition to the data + :param code: A label to help identify one or more log entries + :param level: The severity level of this message. Allowed values: "error", "warning", "info", "debug" + + .. versionadded:: 0.10.1 + + .. seealso:: :ref:`udf_logging_with_inspect` + """ + extra = {"data": data, "code": code} + kwargs = {"stacklevel": 2} if sys.version_info >= (3, 8) else {} + _user_log.log(level=logging.getLevelName(level.upper()), msg=message, extra=extra, **kwargs)
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/udf/run_code.html b/_modules/openeo/udf/run_code.html new file mode 100644 index 000000000..07f614f9b --- /dev/null +++ b/_modules/openeo/udf/run_code.html @@ -0,0 +1,366 @@ + + + + + + + openeo.udf.run_code — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.udf.run_code

    +"""
    +
    +"""
    +
    +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf)
    +
    +import functools
    +import importlib
    +import inspect
    +import logging
    +import math
    +import pathlib
    +from typing import Callable, Union
    +
    +import numpy
    +import pandas
    +import shapely
    +import xarray
    +from pandas import Series
    +
    +import openeo
    +from openeo.udf import OpenEoUdfException
    +from openeo.udf.feature_collection import FeatureCollection
    +from openeo.udf.structured_data import StructuredData
    +from openeo.udf.udf_data import UdfData
    +from openeo.udf.xarraydatacube import XarrayDataCube
    +
    +_log = logging.getLogger(__name__)
    +
    +
    +def _build_default_execution_context():
    +    # TODO: is it really necessary to "pre-load" these modules? Isn't user going to import them explicitly in their script anyway?
    +    context = {
    +        "numpy": numpy, "np": numpy,
    +        "xarray": xarray,
    +        "pandas": pandas, "pd": pandas,
    +        "shapely": shapely,
    +        "math": math,
    +        "UdfData": UdfData,
    +        "XarrayDataCube": XarrayDataCube,
    +        "DataCube": XarrayDataCube,  # Legacy alias
    +        "StructuredData": StructuredData,
    +        "FeatureCollection": FeatureCollection,
    +        # "SpatialExtent": SpatialExtent,  # TODO?
    +        # "MachineLearnModel": MachineLearnModelConfig, # TODO?
    +    }
    +
    +
    +    return context
    +
    +
    +@functools.lru_cache(maxsize=100)
    +def load_module_from_string(code: str) -> dict:
    +    """
    +    Experimental: avoid loading same UDF module more than once, to make caching inside the udf work.
    +    @param code:
    +    @return:
    +    """
    +    globals = _build_default_execution_context()
    +    exec(code, globals)
    +    return globals
    +
    +
    +def _get_annotation_str(annotation: Union[str, type]) -> str:
    +    """Get parameter annotation as a string"""
    +    if isinstance(annotation, str):
    +        return annotation
    +    elif isinstance(annotation, type):
    +        mod = annotation.__module__
    +        return (mod + "." if mod != str.__module__ else "") + annotation.__name__
    +    else:
    +        return str(annotation)
    +
    +
    +def _annotation_is_pandas_series(annotation) -> bool:
    +    return annotation in {pandas.Series, _get_annotation_str(pandas.Series)}
    +
    +
    +def _annotation_is_udf_datacube(annotation) -> bool:
    +    return annotation is XarrayDataCube or _get_annotation_str(annotation) in {
    +        _get_annotation_str(XarrayDataCube),
    +        'openeo_udf.api.datacube.DataCube',  # Legacy `openeo_udf` annotation
    +    }
    +
    +def _annotation_is_data_array(annotation) -> bool:
    +    return annotation is xarray.DataArray or _get_annotation_str(annotation) in {
    +        _get_annotation_str(xarray.DataArray)
    +    }
    +
    +
    +def _annotation_is_udf_data(annotation) -> bool:
    +    return annotation is UdfData or _get_annotation_str(annotation) in {
    +        _get_annotation_str(UdfData),
    +        'openeo_udf.api.udf_data.UdfData'  # Legacy `openeo_udf` annotation
    +    }
    +
    +
    +def _apply_timeseries_xarray(array: xarray.DataArray, callback: Callable[[Series], Series]) -> xarray.DataArray:
    +    """
    +    Apply timeseries callback to given xarray data array
    +    along its time dimension (named "t" or "time")
    +
    +    :param array: array to transform
    +    :param callback: function that transforms a timeseries in another (same size)
    +    :return: transformed array
    +    """
    +    # Make time dimension the last one, and flatten the rest
    +    # to create a 1D sequence of input time series (also 1D).
    +    [time_position] = [i for (i, d) in enumerate(array.dims) if d in ["t", "time"]]
    +    input_series = numpy.moveaxis(array.values, time_position, -1)
    +    orig_shape = input_series.shape
    +    input_series = input_series.reshape((-1, input_series.shape[-1]))
    +
    +    applied = numpy.asarray([callback(s) for s in input_series])
    +
    +    # Reshape to original shape
    +    applied = applied.reshape(orig_shape)
    +    applied = numpy.moveaxis(applied, -1, time_position)
    +    assert applied.shape == array.shape
    +
    +    return xarray.DataArray(applied, coords=array.coords, dims=array.dims, name=array.name)
    +
    +
    +def apply_timeseries_generic(
    +        udf_data: UdfData,
    +        callback: Callable[[Series, dict], Series]
    +) -> UdfData:
    +    """
    +    Implements the UDF contract by calling a user provided time series transformation function.
    +
    +    :param udf_data:
    +    :param callback: callable that takes a pandas Series and context dict and returns a pandas Series.
    +        See template :py:func:`openeo.udf.udf_signatures.apply_timeseries`
    +    :return:
    +    """
    +    callback = functools.partial(callback, context=udf_data.user_context)
    +    datacubes = [
    +        XarrayDataCube(_apply_timeseries_xarray(array=cube.array, callback=callback))
    +        for cube in udf_data.get_datacube_list()
    +    ]
    +    # Insert the new tiles as list of raster collection tiles in the input object. The new tiles will
    +    # replace the original input tiles.
    +    udf_data.set_datacube_list(datacubes)
    +    return udf_data
    +
    +
    +def run_udf_code(code: str, data: UdfData) -> UdfData:
    +    # TODO: current implementation uses first match directly, first check for multiple matches?
    +    module = load_module_from_string(code)
    +    functions = ((k, v) for (k, v) in module.items() if callable(v))
    +
    +    for (fn_name, func) in functions:
    +        try:
    +            sig = inspect.signature(func)
    +        except ValueError:
    +            continue
    +        params = sig.parameters
    +        first_param = next(iter(params.values()), None)
    +
    +        if (
    +                fn_name == 'apply_timeseries'
    +                and 'series' in params and 'context' in params
    +                and _annotation_is_pandas_series(params["series"].annotation)
    +                and _annotation_is_pandas_series(sig.return_annotation)
    +        ):
    +            _log.info("Found timeseries mapping UDF `{n}` {f!r}".format(n=fn_name, f=func))
    +            return apply_timeseries_generic(data, func)
    +        elif (
    +                fn_name in ['apply_hypercube', 'apply_datacube']
    +                and 'cube' in params and 'context' in params
    +                and _annotation_is_udf_datacube(params["cube"].annotation)
    +                and _annotation_is_udf_datacube(sig.return_annotation)
    +        ):
    +            _log.info("Found datacube mapping UDF `{n}` {f!r}".format(n=fn_name, f=func))
    +            if len(data.get_datacube_list()) != 1:
    +                raise ValueError("The provided UDF expects exactly one datacube, but {c} were provided.".format(
    +                    c=len(data.get_datacube_list())
    +                ))
    +            # TODO: also support calls without user context?
    +            result_cube = func(cube=data.get_datacube_list()[0], context=data.user_context)
    +            data.set_datacube_list([result_cube])
    +            return data
    +        elif (
    +                fn_name in ['apply_datacube']
    +                and 'cube' in params and 'context' in params
    +                and _annotation_is_data_array(params["cube"].annotation)
    +                and _annotation_is_data_array(sig.return_annotation)
    +        ):
    +            _log.info("Found datacube mapping UDF `{n}` {f!r}".format(n=fn_name, f=func))
    +            if len(data.get_datacube_list()) != 1:
    +                raise ValueError("The provided UDF expects exactly one datacube, but {c} were provided.".format(
    +                    c=len(data.get_datacube_list())
    +                ))
    +            # TODO: also support calls without user context?
    +            result_cube: xarray.DataArray = func(cube=data.get_datacube_list()[0].get_array(), context=data.user_context)
    +            data.set_datacube_list([XarrayDataCube(result_cube)])
    +            return data
    +        elif len(params) == 1 and _annotation_is_udf_data(first_param.annotation):
    +            _log.info("Found generic UDF `{n}` {f!r}".format(n=fn_name, f=func))
    +            func(data)
    +            return data
    +
    +    raise OpenEoUdfException("No UDF found.")
    +
    +
    +
    +[docs] +def execute_local_udf(udf: Union[str, openeo.UDF], datacube: Union[str, xarray.DataArray, XarrayDataCube], fmt='netcdf'): + """ + Locally executes an user defined function on a previously downloaded datacube. + + :param udf: the code of the user defined function + :param datacube: the path to the downloaded data in disk or a DataCube + :param fmt: format of the file if datacube is string + :return: the resulting DataCube + """ + if isinstance(udf, openeo.UDF): + udf = udf.code + + if isinstance(datacube, (str, pathlib.Path)): + d = XarrayDataCube.from_file(path=datacube, fmt=fmt) + elif isinstance(datacube, XarrayDataCube): + d = datacube + elif isinstance(datacube, xarray.DataArray): + d = XarrayDataCube(datacube) + else: + raise ValueError(datacube) + d_array = d.get_array() + expected_order = ("t", "bands", "y", "x") + dims = [d for d in expected_order if d in d_array.dims] + + # TODO: skip going through XarrayDataCube above, we only need xarray.DataArray here anyway. + # datacube's data is to be float and x,y not provided + d = XarrayDataCube(d_array.transpose(*dims).astype(numpy.float64).drop(labels="x").drop(labels="y")) + # wrap to udf_data + udf_data = UdfData(datacube_list=[d]) + + # TODO: enrich to other types like time series, vector data,... probalby by adding named arguments + # signature: UdfData(proj, datacube_list, feature_collection_list, structured_data_list, ml_model_list, metadata) + + # run the udf through the same routine as it would have been parsed in the backend + result = run_udf_code(udf, udf_data) + return result
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/udf/structured_data.html b/_modules/openeo/udf/structured_data.html new file mode 100644 index 000000000..6c5b695e7 --- /dev/null +++ b/_modules/openeo/udf/structured_data.html @@ -0,0 +1,172 @@ + + + + + + + openeo.udf.structured_data — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.udf.structured_data

    +"""
    +
    +"""
    +
    +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf)
    +
    +from __future__ import annotations
    +
    +import builtins
    +from typing import Union
    +
    +
    +
    +[docs] +class StructuredData: + """ + This class represents structured data that is produced by an UDF and can not be represented + as a raster or vector data cube. For example: the result of a statistical + computation. + + Usage example:: + + >>> StructuredData([3, 5, 8, 13]) + >>> StructuredData({"mean": 5, "median": 8}) + >>> StructuredData([('col_1', 'col_2'), (1, 2), (2, 3)], type="table") + """ + + def __init__(self, data: Union[list, dict], description: str = None, type: str = None): + self.data = data + self.type = type or builtins.type(data).__name__ + self.description = description or self.type + + def __repr__(self): + return f"<{type(self).__name__} with {self.type}>" + + def to_dict(self) -> dict: + return dict( + data=self.data, + description=self.description, + type=self.type, + ) + + @classmethod + def from_dict(cls, data: dict) -> StructuredData: + return cls( + data=data["data"], + description=data.get("description"), + type=data.get("type") + )
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/udf/udf_data.html b/_modules/openeo/udf/udf_data.html new file mode 100644 index 000000000..d1b65d7a7 --- /dev/null +++ b/_modules/openeo/udf/udf_data.html @@ -0,0 +1,281 @@ + + + + + + + openeo.udf.udf_data — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.udf.udf_data

    +"""
    +
    +"""
    +
    +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf)
    +
    +from __future__ import annotations
    +
    +from typing import List, Optional, Union
    +
    +from openeo.udf.feature_collection import FeatureCollection
    +from openeo.udf.structured_data import StructuredData
    +from openeo.udf.xarraydatacube import XarrayDataCube
    +
    +
    +
    +[docs] +class UdfData: + """ + Container for data passed to a user defined function (UDF) + """ + + # TODO: original implementation in `openeo_udf` project had `get_datacube_by_id`, `get_feature_collection_by_id`: is it still useful to provide this? + # TODO: original implementation in `openeo_udf` project had `server_context`: is it still useful to provide this? + + def __init__( + self, + proj: dict = None, + datacube_list: Optional[List[XarrayDataCube]] = None, + feature_collection_list: Optional[List[FeatureCollection]] = None, + structured_data_list: Optional[List[StructuredData]] = None, + user_context: Optional[dict] = None, + ): + """ + The constructor of the UDF argument class that stores all data required by the + user defined function. + + :param proj: A dictionary of form {"proj type string": "projection description"} e.g. {"EPSG": 4326} + :param datacube_list: A list of data cube objects + :param feature_collection_list: A list of VectorTile objects + :param structured_data_list: A list of structured data objects + """ + self.datacube_list = datacube_list + self.feature_collection_list = feature_collection_list + self.structured_data_list = structured_data_list + self.proj = proj + self._user_context = user_context or {} + + def __repr__(self) -> str: + fields = " ".join( + f"{f}:{getattr(self, f)!r}" for f in + ["datacube_list", "feature_collection_list", "structured_data_list"] + ) + return f"<{type(self).__name__} {fields}>" + + @property + def user_context(self) -> dict: + """Return the user context that was passed to the run_udf function""" + return self._user_context + +
    +[docs] + def get_datacube_list(self) -> Union[List[XarrayDataCube], None]: + """Get the data cube list""" + return self._datacube_list
    + + +
    +[docs] + def set_datacube_list(self, datacube_list: Union[List[XarrayDataCube], None]): + """ + Set the data cube list + + :param datacube_list: A list of data cubes + """ + self._datacube_list = datacube_list
    + + + datacube_list = property(fget=get_datacube_list, fset=set_datacube_list) + +
    +[docs] + def get_feature_collection_list(self) -> Union[List[FeatureCollection], None]: + """get all feature collections as list""" + return self._feature_collection_list
    + + + def set_feature_collection_list(self, feature_collection_list: Union[List[FeatureCollection], None]): + self._feature_collection_list = feature_collection_list + + feature_collection_list = property(fget=get_feature_collection_list, fset=set_feature_collection_list) + +
    +[docs] + def get_structured_data_list(self) -> Union[List[StructuredData], None]: + """ + Get all structured data entries + + :return: A list of StructuredData objects + """ + return self._structured_data_list
    + + +
    +[docs] + def set_structured_data_list(self, structured_data_list: Union[List[StructuredData], None]): + """ + Set the list of structured data + + :param structured_data_list: A list of StructuredData objects + """ + self._structured_data_list = structured_data_list
    + + + structured_data_list = property(fget=get_structured_data_list, fset=set_structured_data_list) + +
    +[docs] + def to_dict(self) -> dict: + """ + Convert this UdfData object into a dictionary that can be converted into + a valid JSON representation + """ + return { + "datacubes": [x.to_dict() for x in self.datacube_list] \ + if self.datacube_list else None, + "feature_collection_list": [x.to_dict() for x in self.feature_collection_list] \ + if self.feature_collection_list else None, + "structured_data_list": [x.to_dict() for x in self.structured_data_list] \ + if self.structured_data_list else None, + "proj": self.proj, + "user_context": self.user_context, + }
    + + +
    +[docs] + @classmethod + def from_dict(cls, udf_dict: dict) -> UdfData: + """ + Create a udf data object from a python dictionary that was created from + the JSON definition of the UdfData class + + :param udf_dict: The dictionary that contains the udf data definition + """ + + datacubes = [XarrayDataCube.from_dict(x) for x in udf_dict.get("datacubes", [])] + feature_collection_list = [FeatureCollection.from_dict(x) for x in udf_dict.get("feature_collection_list", [])] + structured_data_list = [StructuredData.from_dict(x) for x in udf_dict.get("structured_data_list", [])] + udf_data = cls( + proj=udf_dict.get("proj"), + datacube_list=datacubes, + feature_collection_list=feature_collection_list, + structured_data_list=structured_data_list, + user_context=udf_dict.get("user_context") + ) + return udf_data
    +
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/udf/udf_signatures.html b/_modules/openeo/udf/udf_signatures.html new file mode 100644 index 000000000..cb6a89e87 --- /dev/null +++ b/_modules/openeo/udf/udf_signatures.html @@ -0,0 +1,221 @@ + + + + + + + openeo.udf.udf_signatures — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.udf.udf_signatures

    +"""
    +This module defines a number of function signatures that can be implemented by UDF's.
    +Both the name of the function and the argument types are/can be used by the backend to validate if the provided UDF
    +is compatible with the calling context of the process graph in which it is used.
    +
    +"""
    +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf)
    +
    +from pandas import Series
    +
    +from openeo.udf.udf_data import UdfData
    +from openeo.udf.xarraydatacube import XarrayDataCube
    +from openeo.metadata import CollectionMetadata
    +
    +
    +
    +[docs] +def apply_timeseries(series: Series, context: dict) -> Series: + """ + Process a timeseries of values, without changing the time instants. + + This can for instance be used for smoothing or gap-filling. + + :param series: A Pandas Series object with a date-time index. + :param context: A dictionary containing user context. + :return: A Pandas Series object with the same datetime index. + """ + # TODO: do we need geospatial coordinates for the series? + return series
    + + + +
    +[docs] +def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube: + """ + Map a :py:class:`XarrayDataCube` to another :py:class:`XarrayDataCube`. + + Depending on the context in which this function is used, the :py:class:`XarrayDataCube` dimensions + have to be retained or can be chained. + For instance, in the context of a reducing operation along a dimension, + that dimension will have to be reduced to a single value. + In the context of a 1 to 1 mapping operation, all dimensions have to be retained. + + :param cube: input data cube + :param context: A dictionary containing user context. + :return: output data cube + """ + return cube
    + + + +
    +[docs] +def apply_udf_data(data: UdfData): + """ + Generic UDF function that directly manipulates a :py:class:`UdfData` object + + :param data: :py:class:`UdfData` object to manipulate in-place + """ + pass
    + + + +
    +[docs] +def apply_metadata(metadata: CollectionMetadata, context: dict) -> CollectionMetadata: + """ + .. warning:: + This signature is not yet fully standardized and subject to change. + + Returns the expected cube metadata, after applying this UDF, based on input metadata. + The provided metadata represents the whole raster or vector cube. This function does not need to be called for every data chunk. + + When this function is not implemented by the UDF, the backend may still be able to infer correct metadata by running the + UDF, but this can result in reduced performance or errors. + + This function does not need to be provided when using the UDF in combination with processes that by design have a clear + effect on cube metadata, such as :py:meth:`~openeo.rest.datacube.DataCube.reduce_dimension()` + + :param metadata: the collection metadata of the input data cube + :param context: A dictionary containing user context. + + :return: output metadata: the expected metadata of the cube, after applying the udf + + Examples + -------- + + An example for a UDF that is applied on the 'bands' dimension, and returns a new set of bands with different labels. + + >>> def apply_metadata(metadata: CollectionMetadata, context: dict) -> CollectionMetadata: + ... return metadata.rename_labels( + ... dimension="bands", + ... target=["computed_band_1", "computed_band_2"] + ... ) + + """ + pass
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/udf/xarraydatacube.html b/_modules/openeo/udf/xarraydatacube.html new file mode 100644 index 000000000..1c6fb886d --- /dev/null +++ b/_modules/openeo/udf/xarraydatacube.html @@ -0,0 +1,522 @@ + + + + + + + openeo.udf.xarraydatacube — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.udf.xarraydatacube

    +"""
    +
    +"""
    +
    +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf)
    +
    +from __future__ import annotations
    +
    +import collections
    +import json
    +import typing
    +from pathlib import Path
    +from typing import Optional, Union
    +
    +import numpy
    +import xarray
    +
    +from openeo.udf import OpenEoUdfException
    +from openeo.util import deep_get, dict_no_none
    +
    +if typing.TYPE_CHECKING:
    +    # Imports for type checking only (circular import issue at runtime).
    +    import matplotlib.colors
    +
    +
    +
    +[docs] +class XarrayDataCube: + """ + This is a thin wrapper around :py:class:`xarray.DataArray` + providing a basic "DataCube" interface for openEO UDF usage around multi-dimensional data. + """ + + def __init__(self, array: xarray.DataArray): + if not isinstance(array, xarray.DataArray): + raise OpenEoUdfException("Argument data must be of type xarray.DataArray") + self._array = array + + def __repr__(self): + return f"<{type(self).__name__} shape:{self._array.shape}>" + +
    +[docs] + def get_array(self) -> xarray.DataArray: + """ + Get the :py:class:`xarray.DataArray` that contains the data and dimension definition + """ + return self._array
    + + + array = property(fget=get_array) + + @property + def id(self): + return self._array.name + +
    +[docs] + def to_dict(self) -> dict: + """ + Convert this hypercube into a dictionary that can be converted into + a valid JSON representation + + >>> example = { + ... "id": "test_data", + ... "data": [ + ... [[0.0, 0.1], [0.2, 0.3]], + ... [[0.0, 0.1], [0.2, 0.3]], + ... ], + ... "dimension": [ + ... {"name": "time", "coordinates": ["2001-01-01", "2001-01-02"]}, + ... {"name": "X", "coordinates": [50.0, 60.0]}, + ... {"name": "Y"}, + ... ], + ... } + """ + xd = self._array.to_dict() + return dict_no_none({ + "id": xd.get("name"), + "data": xd.get("data"), + "description": deep_get(xd, "attrs", "description", default=None), + "dimensions": [ + dict_no_none( + name=dim, + coordinates=deep_get(xd, "coords", dim, "data", default=None) + ) + for dim in xd.get("dims", []) + ] + })
    + + +
    +[docs] + @classmethod + def from_dict(cls, xdc_dict: dict) -> XarrayDataCube: + """ + Create a :py:class:`XarrayDataCube` from a Python dictionary that was created from + the JSON definition of the data cube + + :param data: The dictionary that contains the data cube definition + """ + + if "data" not in xdc_dict: + raise OpenEoUdfException("Missing data in dictionary") + + data = numpy.asarray(xdc_dict["data"]) + + if "dimensions" in xdc_dict: + dims = [dim["name"] for dim in xdc_dict["dimensions"]] + coords = {dim["name"]: dim["coordinates"] for dim in xdc_dict["dimensions"] if "coordinates" in dim} + else: + dims = None + coords = None + + x = xarray.DataArray(data, dims=dims, coords=coords, name=xdc_dict.get("id")) + + if "description" in xdc_dict: + x.attrs["description"] = xdc_dict["description"] + + return cls(array=x)
    + + + @staticmethod + def _guess_format(path: Union[str, Path]) -> str: + """Guess file format from file name.""" + suffix = Path(path).suffix.lower() + if suffix in [".nc", ".netcdf"]: + return "netcdf" + elif suffix in [".json"]: + return "json" + else: + raise ValueError("Can not guess format of {p}".format(p=path)) + +
    +[docs] + @classmethod + def from_file(cls, path: Union[str, Path], fmt=None, **kwargs) -> XarrayDataCube: + """ + Load data file as :py:class:`XarrayDataCube` in memory + + :param path: the file on disk + :param fmt: format to load from, e.g. "netcdf" or "json" + (will be auto-detected when not specified) + + :return: loaded data cube + """ + fmt = fmt or cls._guess_format(path) + if fmt.lower() == 'netcdf': + return cls(array=XarrayIO.from_netcdf_file(path=path, **kwargs)) + elif fmt.lower() == 'json': + return cls(array=XarrayIO.from_json_file(path=path)) + else: + raise ValueError("invalid format {f}".format(f=fmt))
    + + +
    +[docs] + def save_to_file(self, path: Union[str, Path], fmt=None, **kwargs): + """ + Store :py:class:`XarrayDataCube` to file + + :param path: destination file on disk + :param fmt: format to save as, e.g. "netcdf" or "json" + (will be auto-detected when not specified) + """ + fmt = fmt or self._guess_format(path) + if fmt.lower() == 'netcdf': + XarrayIO.to_netcdf_file(array=self.get_array(), path=path, **kwargs) + elif fmt.lower() == 'json': + XarrayIO.to_json_file(array=self.get_array(), path=path) + else: + raise ValueError(fmt)
    + + +
    +[docs] + def plot( + self, + title: str = None, + limits=None, + show_bandnames: bool = True, + show_dates: bool = True, + show_axeslabels: bool = False, + fontsize: float = 10., + oversample: float = 1, + cmap: Union[str, 'matplotlib.colors.Colormap'] = 'RdYlBu_r', + cbartext: str = None, + to_file: str = None, + to_show: bool = True + ): + """ + Visualize a :py:class:`XarrayDataCube` with matplotlib + + :param datacube: data to plot + :param title: title text drawn in the top left corner (default: nothing) + :param limits: range of the contour plot as a tuple(min,max) (default: None, in which case the min/max is computed from the data) + :param show_bandnames: whether to plot the column names (default: True) + :param show_dates: whether to show the dates for each row (default: True) + :param show_axeslabels: whether to show the labels on the axes (default: False) + :param fontsize: font size in pixels (default: 10) + :param oversample: one value is plotted into oversample x oversample number of pixels (default: 1 which means each value is plotted as a single pixel) + :param cmap: built-in matplotlib color map name or ColorMap object (default: RdYlBu_r which is a blue-yellow-red rainbow) + :param cbartext: text on top of the legend (default: nothing) + :param to_file: filename to save the image to (default: None, which means no file is generated) + :param to_show: whether to show the image in a matplotlib window (default: True) + + :return: None + """ + from matplotlib import pyplot + + data = self.get_array() + if limits is None: + vmin = data.min() + vmax = data.max() + else: + vmin = limits[0] + vmax = limits[1] + + # fill bands and t if missing + if 'bands' not in data.dims: + data = data.expand_dims(dim={'bands': ['band0']}) + if 't' not in data.dims: + data = data.expand_dims(dim={'t': [numpy.datetime64('today')]}) + if 'bands' not in data.coords: + data['bands'] = ['band0'] + if 't' not in data.coords: + data['t'] = [numpy.datetime64('today')] + + # align with plot + data = data.transpose('t', 'bands', 'y', 'x') + dpi = 100 + xres = len(data.x) / dpi + yres = len(data.y) / dpi + fs = fontsize / oversample + frame = 0.33 + + nrow = data.shape[0] + ncol = data.shape[1] + + fig = pyplot.figure(figsize=((ncol + frame) * xres * 1.1, (nrow + frame) * yres), dpi=int(dpi * oversample)) + gs = pyplot.GridSpec(nrow, ncol, wspace=0., hspace=0., top=nrow / (nrow + frame), bottom=0., + left=frame / (ncol + frame), right=1.) + + xmin = data.x.min() + xmax = data.x.max() + ymin = data.y.min() + ymax = data.y.max() + + # flip around if incorrect, this is in harmony with origin='lower' + if (data.x[0] > data.x[-1]): + data = data.reindex(x=list(reversed(data.x))) + if (data.y[0] > data.y[-1]): + data = data.reindex(y=list(reversed(data.y))) + + extent = (data.x[0], data.x[-1], data.y[0], data.y[-1]) + + for i in range(nrow): + for j in range(ncol): + im = data[i, j] + ax = pyplot.subplot(gs[i, j]) + ax.set_xlim(xmin, xmax) + ax.set_ylim(ymin, ymax) + img = ax.imshow(im, vmin=vmin, vmax=vmax, cmap=cmap, origin='lower', extent=extent) + ax.xaxis.set_tick_params(labelsize=fs) + ax.yaxis.set_tick_params(labelsize=fs) + if not show_axeslabels: + ax.set_axis_off() + ax.set_xticklabels([]) + ax.set_yticklabels([]) + if show_bandnames: + if i == 0: ax.text(0.5, 1.08, data.bands.values[j] + " (" + str(data.dtype) + ")", size=fs, + va="center", + ha="center", transform=ax.transAxes) + if show_dates: + if j == 0: ax.text(-0.08, 0.5, data.t.dt.strftime("%Y-%m-%d").values[i], size=fs, va="center", + ha="center", rotation=90, transform=ax.transAxes) + + if title is not None: + fig.text(0., 1., title.split('/')[-1], size=fs, va="top", ha="left", weight='bold') + + cbar_ax = fig.add_axes([0.01, 0.1, 0.04, 0.5]) + if cbartext is not None: + fig.text(0.06, 0.62, cbartext, size=fs, va="bottom", ha="center") + cbar = fig.colorbar(img, cax=cbar_ax) + cbar.ax.tick_params(labelsize=fs) + cbar.outline.set_visible(False) + cbar.ax.tick_params(size=0) + cbar.ax.yaxis.set_tick_params(pad=0) + + if to_file is not None: + pyplot.savefig(str(to_file)) + if to_show: + pyplot.show() + + pyplot.close()
    +
    + + + +class XarrayIO: + """ + Helpers to load/store :py:cass:`xarray.DataArray` objects, + with some conventions about expected dimensions/bands + """ + + @classmethod + def from_json_file(cls, path: Union[str, Path]) -> xarray.DataArray: + with Path(path).open() as f: + return cls.from_json(json.load(f)) + + @classmethod + def from_json(cls, d: dict) -> xarray.DataArray: + d['data'] = numpy.array(d['data'], dtype=numpy.dtype(d['attrs']['dtype'])) + for k, v in d['coords'].items(): + # prepare coordinate + d['coords'][k]['data'] = numpy.array(v['data'], dtype=v['attrs']['dtype']) + # remove dtype and shape, because that is included for helping the user + if d['coords'][k].get('attrs', None) is not None: + d['coords'][k]['attrs'].pop('dtype', None) + d['coords'][k]['attrs'].pop('shape', None) + + # remove dtype and shape, because that is included for helping the user + if d.get('attrs', None) is not None: + d['attrs'].pop('dtype', None) + d['attrs'].pop('shape', None) + # convert to xarray + r = xarray.DataArray.from_dict(d) + + # build dimension list in proper order + dims = list(filter(lambda i: i != 't' and i != 'bands' and i != 'x' and i != 'y', r.dims)) + if 't' in r.dims: dims += ['t'] + if 'bands' in r.dims: dims += ['bands'] + if 'x' in r.dims: dims += ['x'] + if 'y' in r.dims: dims += ['y'] + # return the resulting data array + return r.transpose(*dims) + + @classmethod + def from_netcdf_file(cls, path: Union[str, Path], engine: Optional[str] = None) -> xarray.DataArray: + # load the dataset and convert to data array + ds = xarray.open_dataset(path, engine=engine) + + # Skip non-numerical variables (like "crs") + band_vars = [k for k, v in ds.data_vars.items() if v.dtype.kind in {"b", "i", "u", "f"} and len(v.dims) > 0] + ds = ds[band_vars] + + r = ds.to_array(dim='bands') + + # Reorder dims to proper order (t-bands-x-y at the end) + expected_order = ("t", "bands", "x", "y") + dims = [d for d in r.dims if d not in expected_order] + [d for d in expected_order if d in r.dims] + + return r.transpose(*dims) + + @classmethod + def to_json_file(cls, array: xarray.DataArray, path: Union[str, Path]): + # to deserialized json + jsonarray = array.to_dict() + # add attributes that needed for re-creating xarray from json + jsonarray['attrs']['dtype'] = str(array.values.dtype) + jsonarray['attrs']['shape'] = list(array.values.shape) + for i in array.coords.values(): + jsonarray['coords'][i.name]['attrs']['dtype'] = str(i.dtype) + jsonarray['coords'][i.name]['attrs']['shape'] = list(i.shape) + # custom print so resulting json file is humanly easy to read + # TODO: make this human friendly JSON format optional and allow compact JSON too. + with Path(path).open("w") as f: + def custom_print(data_structure, indent=1): + f.write("{\n") + needs_comma = False + for key, value in data_structure.items(): + if needs_comma: + f.write(',\n') + needs_comma = True + f.write(' ' * indent + json.dumps(key) + ':') + if isinstance(value, dict): + custom_print(value, indent + 1) + else: + json.dump(value, f, default=str, separators=(',', ':')) + f.write('\n' + ' ' * (indent - 1) + "}") + + custom_print(jsonarray) + + @classmethod + def to_netcdf_file(cls, array: xarray.DataArray, path: Union[str, Path], engine: Optional[str] = None): + # temp reference to avoid modifying the original array + result = array + # rearrange in a basic way because older xarray versions have a bug and ellipsis don't work in xarray.transpose() + if result.dims[-2] == 'x' and result.dims[-1] == 'y': + l = list(result.dims[:-2]) + result = result.transpose(*(l + ['y', 'x'])) + # turn it into a dataset where each band becomes a variable + if not 'bands' in result.dims: + result = result.expand_dims(dim=collections.OrderedDict({'bands': ['band_0']})) + else: + if not 'bands' in result.coords: + labels = ['band_' + str(i) for i in range(result.shape[result.dims.index('bands')])] + result = result.assign_coords(bands=labels) + result = result.to_dataset('bands') + result.to_netcdf(path, engine=engine) +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_modules/openeo/util.html b/_modules/openeo/util.html new file mode 100644 index 000000000..65f8e427b --- /dev/null +++ b/_modules/openeo/util.html @@ -0,0 +1,826 @@ + + + + + + + openeo.util — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for openeo.util

    +"""
    +Various utilities and helpers.
    +"""
    +
    +# TODO #465 split this kitchen-sink in thematic submodules
    +
    +from __future__ import annotations
    +
    +import datetime as dt
    +import functools
    +import json
    +import logging
    +import re
    +import sys
    +import time
    +from collections import OrderedDict
    +from enum import Enum
    +from pathlib import Path
    +from typing import Any, Callable, List, Optional, Tuple, Union
    +from urllib.parse import urljoin
    +
    +import requests
    +import shapely.geometry.base
    +from deprecated import deprecated
    +
    +try:
    +    # pyproj is an optional dependency
    +    import pyproj
    +except ImportError:
    +    pyproj = None
    +
    +
    +logger = logging.getLogger(__name__)
    +
    +
    +class Rfc3339:
    +    """
    +    Formatter for dates according to RFC-3339.
    +
    +    Parses date(time)-like input and formats according to RFC-3339. Some examples:
    +
    +        >>> rfc3339.date("2020:03:17")
    +        "2020-03-17"
    +        >>> rfc3339.date(2020, 3, 17)
    +        "2020-03-17"
    +        >>> rfc3339.datetime("2020/03/17/12/34/56")
    +        "2020-03-17T12:34:56Z"
    +        >>> rfc3339.datetime([2020, 3, 17, 12, 34, 56])
    +        "2020-03-17T12:34:56Z"
    +        >>> rfc3339.datetime(2020, 3, 17)
    +        "2020-03-17T00:00:00Z"
    +        >>> rfc3339.datetime(datetime(2020, 3, 17, 12, 34, 56))
    +        "2020-03-17T12:34:56Z"
    +
    +    Or just normalize (automatically preserve date/datetime resolution):
    +
    +        >>> rfc3339.normalize("2020/03/17")
    +        "2020-03-17"
    +        >>> rfc3339.normalize("2020-03-17-12-34-56")
    +        "2020-03-17T12:34:56Z"
    +
    +    Also see https://tools.ietf.org/html/rfc3339#section-5.6
    +    """
    +    # TODO: currently we hard code timezone 'Z' for simplicity. Add real time zone support?
    +    _FMT_DATE = '%Y-%m-%d'
    +    _FMT_TIME = '%H:%M:%SZ'
    +    _FMT_DATETIME = _FMT_DATE + "T" + _FMT_TIME
    +
    +    _regex_datetime = re.compile(r"""
    +        ^(?P<Y>\d{4})[:/_-](?P<m>\d{2})[:/_-](?P<d>\d{2})[T :/_-]?
    +        (?:(?P<H>\d{2})[:/_-](?P<M>\d{2})(?:[:/_-](?P<S>\d{2}))?)?""", re.VERBOSE)
    +
    +    def __init__(self, propagate_none: bool = False):
    +        self._propagate_none = propagate_none
    +
    +    def datetime(self, x: Any, *args) -> Union[str, None]:
    +        """
    +        Format given date(time)-like object as RFC-3339 datetime string.
    +        """
    +        if args:
    +            return self.datetime((x,) + args)
    +        elif isinstance(x, dt.datetime):
    +            return self._format_datetime(x)
    +        elif isinstance(x, dt.date):
    +            return self._format_datetime(dt.datetime.combine(x, dt.time()))
    +        elif isinstance(x, str):
    +            return self._format_datetime(dt.datetime(*self._parse_datetime(x)))
    +        elif isinstance(x, (tuple, list)):
    +            return self._format_datetime(dt.datetime(*(int(v) for v in x)))
    +        elif x is None and self._propagate_none:
    +            return None
    +        raise ValueError(x)
    +
    +    def date(self, x: Any, *args) -> Union[str, None]:
    +        """
    +        Format given date-like object as RFC-3339 date string.
    +        """
    +        if args:
    +            return self.date((x,) + args)
    +        elif isinstance(x, (dt.date, dt.datetime)):
    +            return self._format_date(x)
    +        elif isinstance(x, str):
    +            return self._format_date(dt.datetime(*self._parse_datetime(x)))
    +        elif isinstance(x, (tuple, list)):
    +            return self._format_date(dt.datetime(*(int(v) for v in x)))
    +        elif x is None and self._propagate_none:
    +            return None
    +        raise ValueError(x)
    +
    +    def normalize(self, x: Any, *args) -> Union[str, None]:
    +        """
    +        Format given date(time)-like object as RFC-3339 date or date-time string depending on given resolution
    +
    +            >>> rfc3339.normalize("2020/03/17")
    +            "2020-03-17"
    +            >>> rfc3339.normalize("2020/03/17/12/34/56")
    +            "2020-03-17T12:34:56Z"
    +        """
    +        if args:
    +            return self.normalize((x,) + args)
    +        elif isinstance(x, dt.datetime):
    +            return self.datetime(x)
    +        elif isinstance(x, dt.date):
    +            return self.date(x)
    +        elif isinstance(x, str):
    +            x = self._parse_datetime(x)
    +            return self.date(x) if len(x) <= 3 else self.datetime(x)
    +        elif isinstance(x, (tuple, list)):
    +            return self.date(x) if len(x) <= 3 else self.datetime(x)
    +        elif x is None and self._propagate_none:
    +            return None
    +        raise ValueError(x)
    +
    +    def parse_date(self, x: Union[str, None]) -> Union[dt.date, None]:
    +        """Parse given string as RFC3339 date."""
    +        if isinstance(x, str):
    +            return dt.datetime.strptime(x, "%Y-%m-%d").date()
    +        elif x is None and self._propagate_none:
    +            return None
    +        raise ValueError(x)
    +
    +    def parse_datetime(
    +        self, x: Union[str, None], with_timezone: bool = False
    +    ) -> Union[dt.datetime, None]:
    +        """Parse given string as RFC3339 date-time."""
    +        if isinstance(x, str):
    +            # TODO: Also support parsing other timezones than UTC (Z)
    +            if re.search(r":\d+\.\d+", x):
    +                res = dt.datetime.strptime(x, "%Y-%m-%dT%H:%M:%S.%fZ")
    +            else:
    +                res = dt.datetime.strptime(x, "%Y-%m-%dT%H:%M:%SZ")
    +            if with_timezone:
    +                res = res.replace(tzinfo=dt.timezone.utc)
    +            return res
    +        elif x is None and self._propagate_none:
    +            return None
    +        raise ValueError(x)
    +
    +    def parse_date_or_datetime(
    +        self, x: Union[str, None], with_timezone: bool = False
    +    ) -> Union[dt.date, dt.datetime, None]:
    +        """Parse given string as RFC3339 date or date-time."""
    +        if isinstance(x, str):
    +            if len(x) > 10:
    +                return self.parse_datetime(x, with_timezone=with_timezone)
    +            else:
    +                return self.parse_date(x)
    +        elif x is None and self._propagate_none:
    +            return None
    +        raise ValueError(x)
    +
    +    @classmethod
    +    def _format_datetime(cls, d: dt.datetime) -> str:
    +        """Format given datetime as RFC-3339 date-time string."""
    +        if d.tzinfo not in {None, dt.timezone.utc}:
    +            # TODO: add support for non-UTC timezones?
    +            raise ValueError(f"No support for non-UTC timezone {d.tzinfo}")
    +        return d.strftime(cls._FMT_DATETIME)
    +
    +    @classmethod
    +    def _format_date(cls, d: dt.date) -> str:
    +        """Format given datetime as RFC-3339 date-time string."""
    +        return d.strftime(cls._FMT_DATE)
    +
    +    @classmethod
    +    def _parse_datetime(cls, s: str) -> Tuple[int]:
    +        """Try to parse string to a date(time) tuple"""
    +        try:
    +            return tuple(int(v) for v in cls._regex_datetime.match(s).groups() if v is not None)
    +        except Exception:
    +            raise ValueError("Can not parse as date: {s}".format(s=s))
    +
    +    def today(self) -> str:
    +        """Today (date) in RFC3339 format"""
    +        return self.date(dt.date.today())
    +
    +    def utcnow(self) -> str:
    +        """Current UTC datetime in RFC3339 format."""
    +        # Current time in UTC timezone (instead of naive `datetime.datetime.utcnow()`, per `datetime` documentation)
    +        now = dt.datetime.now(tz=dt.timezone.utc)
    +        return self.datetime(now)
    +
    +
    +# Default RFC3339 date-time formatter
    +rfc3339 = Rfc3339()
    +
    +
    +@deprecated("Use `rfc3339.normalize`, `rfc3339.date` or `rfc3339.datetime` instead")
    +def date_to_rfc3339(d: Any) -> str:
    +    """
    +    Convert date-like object to a RFC 3339 formatted date string
    +
    +    see https://tools.ietf.org/html/rfc3339#section-5.6
    +    """
    +    return rfc3339.normalize(d)
    +
    +
    +def dict_no_none(*args, **kwargs) -> dict:
    +    """
    +    Helper to build a dict containing given key-value pairs where the value is not None.
    +    """
    +    return {
    +        k: v
    +        for k, v in dict(*args, **kwargs).items()
    +        if v is not None
    +    }
    +
    +
    +def first_not_none(*args):
    +    """Return first item from given arguments that is not None."""
    +    for item in args:
    +        if item is not None:
    +            return item
    +    raise ValueError("No not-None values given.")
    +
    +
    +def ensure_dir(path: Union[str, Path]) -> Path:
    +    """Create directory if it doesn't exist."""
    +    path = Path(path)
    +    if not path.exists():
    +        path.mkdir(parents=True, exist_ok=True)
    +    assert path.is_dir()
    +    return path
    +
    +
    +def ensure_list(x):
    +    """Convert given data structure to a list."""
    +    try:
    +        return list(x)
    +    except TypeError:
    +        return [x]
    +
    +
    +class ContextTimer:
    +    """
    +    Context manager to measure the "wall clock" time (in seconds) inside/for a block of code.
    +
    +    Usage example:
    +
    +        with ContextTimer() as timer:
    +            # Inside code block: currently elapsed time
    +            print(timer.elapsed())
    +
    +        # Outside code block: elapsed time when block ended
    +        print(timer.elapsed())
    +
    +    """
    +
    +    __slots__ = ["start", "end"]
    +
    +    # Function that returns current time in seconds (overridable for unit tests)
    +    _clock = time.time
    +
    +    def __init__(self):
    +        self.start = None
    +        self.end = None
    +
    +    def elapsed(self) -> float:
    +        """Elapsed time (in seconds) inside or at the end of wrapped context."""
    +        if self.start is None:
    +            raise RuntimeError("Timer not started.")
    +        if self.end is not None:
    +            # Elapsed time when exiting context.
    +            return self.end - self.start
    +        else:
    +            # Currently elapsed inside context.
    +            return self._clock() - self.start
    +
    +    def __enter__(self) -> ContextTimer:
    +        self.start = self._clock()
    +        return self
    +
    +    def __exit__(self, exc_type, exc_val, exc_tb):
    +        self.end = self._clock()
    +
    +
    +class TimingLogger:
    +    """
    +    Context manager for quick and easy logging of start time, end time and elapsed time of some block of code
    +
    +    Usage example:
    +
    +    >>> with TimingLogger("Doing batch job"):
    +    ...     do_batch_job()
    +
    +    At start of the code block the current time will be logged
    +    and at end of the code block the end time and elapsed time will be logged.
    +
    +    Can also be used as a function/method decorator, for example:
    +
    +    >>> @TimingLogger("Calculation going on")
    +    ... def add(x, y):
    +    ...     return x + y
    +    """
    +
    +    # Function that returns current datetime (overridable for unit tests)
    +    _now = dt.datetime.now
    +
    +    def __init__(self, title: str = "Timing", logger: Union[logging.Logger, str, Callable] = logger):
    +        """
    +        :param title: the title to use in the logging
    +        :param logger: how the timing should be logged.
    +            Can be specified as a logging.Logger object (in which case the INFO log level will be used),
    +            as a string (name of the logging.Logger object to construct),
    +            or as callable (e.g. to use the `print` function, or the `.debug` method of an existing logger)
    +        """
    +        self.title = title
    +        if isinstance(logger, str):
    +            logger = logging.getLogger(logger)
    +        if isinstance(logger, (logging.Logger, logging.LoggerAdapter)):
    +            self._log = logger.info
    +        elif callable(logger):
    +            self._log = logger
    +        else:
    +            raise ValueError("Invalid logger {l!r}".format(l=logger))
    +
    +        self.start_time = self.end_time = self.elapsed = None
    +
    +    def __enter__(self):
    +        self.start_time = self._now()
    +        self._log("{t}: start {s}".format(t=self.title, s=self.start_time))
    +        return self
    +
    +    def __exit__(self, exc_type, exc_val, exc_tb):
    +        self.end_time = self._now()
    +        self.elapsed = self.end_time - self.start_time
    +        self._log("{t}: {s} {e}, elapsed {d}".format(
    +            t=self.title,
    +            s="fail" if exc_type else "end",
    +            e=self.end_time, d=self.elapsed
    +        ))
    +
    +    def __call__(self, f: Callable):
    +        """
    +        Use TimingLogger as function/method decorator
    +        """
    +
    +        @functools.wraps(f)
    +        def wrapper(*args, **kwargs):
    +            with self:
    +                return f(*args, **kwargs)
    +
    +        return wrapper
    +
    +
    +class DeepKeyError(LookupError):
    +    def __init__(self, key, keys):
    +        super(DeepKeyError, self).__init__("{k!r} (from deep key {s!r})".format(k=key, s=keys))
    +
    +
    +# Sentinel object for `default` argument of `deep_get`
    +_deep_get_default_undefined = object()
    +
    +
    +def deep_get(data: dict, *keys, default=_deep_get_default_undefined):
    +    """
    +    Get value deeply from nested dictionaries/lists/tuples
    +
    +    :param data: nested data structure of dicts, lists, tuples
    +    :param keys: sequence of keys/indexes to traverse
    +    :param default: default value when a key is missing.
    +        By default a DeepKeyError will be raised.
    +    :return:
    +    """
    +    for key in keys:
    +        if isinstance(data, dict) and key in data:
    +            data = data[key]
    +        elif isinstance(data, (list, tuple)) and isinstance(key, int) and 0 <= key < len(data):
    +            data = data[key]
    +        else:
    +            if default is _deep_get_default_undefined:
    +                raise DeepKeyError(key, keys)
    +            else:
    +                return default
    +    return data
    +
    +
    +def deep_set(data: dict, *keys, value):
    +    """
    +    Set a value deeply in nested dictionary
    +
    +    :param data: nested data structure of dicts, lists, tuples
    +    :param keys: sequence of keys/indexes to traverse
    +    :param value: value to set
    +    """
    +    if len(keys) == 1:
    +        data[keys[0]] = value
    +    elif len(keys) > 1:
    +        if isinstance(data, dict):
    +            deep_set(data.setdefault(keys[0], OrderedDict()), *keys[1:], value=value)
    +        elif isinstance(data, (list, tuple)):
    +            deep_set(data[keys[0]], *keys[1:], value=value)
    +        else:
    +            ValueError(data)
    +    else:
    +        raise ValueError("No keys given")
    +
    +
    +def guess_format(filename: Union[str, Path]) -> str:
    +    """
    +    Guess the output format from a given filename and return the corrected format.
    +    Any names not in the dict get passed through.
    +    """
    +    extension = str(filename).rsplit(".", 1)[-1].lower()
    +
    +    format_map = {
    +        "gtiff": "GTiff",
    +        "geotiff": "GTiff",
    +        "geotif": "GTiff",
    +        "tiff": "GTiff",
    +        "tif": "GTiff",
    +        "nc": "netCDF",
    +        "netcdf": "netCDF",
    +        "geojson": "GeoJSON",
    +    }
    +
    +    return format_map.get(extension, extension.upper())
    +
    +
    +def load_json(path: Union[Path, str]) -> dict:
    +    with Path(path).open("r", encoding="utf-8") as f:
    +        return json.load(f)
    +
    +
    +
    +[docs] +def load_json_resource(src: Union[str, Path]) -> dict: + """ + Helper to load some kind of JSON resource + + :param src: a JSON resource: a raw JSON string, + a path to (local) JSON file, or a URL to a remote JSON resource + :return: data structured parsed from JSON + """ + if isinstance(src, str) and src.strip().startswith("{"): + # Assume source is a raw JSON string + return json.loads(src) + elif isinstance(src, str) and re.match(r"^https?://", src, flags=re.I): + # URL to remote JSON resource + return requests.get(src).json() + elif isinstance(src, Path) or (isinstance(src, str) and src.endswith(".json")): + # Assume source is a local JSON file path + return load_json(src) + raise ValueError(src)
    + + + +class LazyLoadCache: + """Simple cache that allows to (lazy) load on cache miss.""" + + def __init__(self): + self._cache = {} + + def get(self, key: Union[str, tuple], load: Callable[[], Any]): + if key not in self._cache: + self._cache[key] = load() + return self._cache[key] + + +def str_truncate(text: str, width: int = 64, ellipsis: str = "...") -> str: + """Shorten a string (with an ellipsis) if it is longer than certain length.""" + width = max(0, int(width)) + if len(text) <= width: + return text + if len(ellipsis) > width: + ellipsis = ellipsis[:width] + return text[:max(0, (width - len(ellipsis)))] + ellipsis + + +def repr_truncate(obj: Any, width: int = 64, ellipsis: str = "...") -> str: + """Do `repr` rendering of an object, but truncate string if it is too long .""" + if isinstance(obj, str) and width > len(ellipsis) + 2: + # Special case: put ellipsis inside quotes + return repr(str_truncate(text=obj, width=width - 2, ellipsis=ellipsis)) + else: + # General case: just put ellipsis at end + return str_truncate(text=repr(obj), width=width, ellipsis=ellipsis) + + +def in_interactive_mode() -> bool: + """Detect if we are running in interactive mode (Jupyter/IPython/repl)""" + # Based on https://stackoverflow.com/a/64523765 + return hasattr(sys, "ps1") + + +class InvalidBBoxException(ValueError): + pass + + +
    +[docs] +class BBoxDict(dict): + """ + Dictionary based helper to easily create/work with bounding box dictionaries + (having keys "west", "south", "east", "north", and optionally "crs"). + + :param crs: value describing the coordinate reference system. + Typically just an int (interpreted as EPSG code, e.g. ``4326``) + or a string (handled as authority string, e.g. ``"EPSG:4326"``). + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + + .. versionadded:: 0.10.1 + """ + + def __init__(self, *, west: float, south: float, east: float, north: float, crs: Optional[Union[str, int]] = None): + super().__init__(west=west, south=south, east=east, north=north) + if crs is not None: + self.update(crs=normalize_crs(crs)) + + # TODO: provide west, south, east, north, crs as @properties? Read-only or read-write? + + @classmethod + def from_any(cls, x: Any, *, crs: Optional[str] = None) -> BBoxDict: + if isinstance(x, dict): + if crs and "crs" in x and crs != x["crs"]: + raise InvalidBBoxException(f"Two CRS values specified: {crs} and {x['crs']}") + return cls.from_dict({"crs": crs, **x}) + elif isinstance(x, (list, tuple)): + return cls.from_sequence(x, crs=crs) + elif isinstance(x, shapely.geometry.base.BaseGeometry): + return cls.from_sequence(x.bounds, crs=crs) + # TODO: support other input? E.g.: WKT string, GeoJson-style dictionary (Polygon, FeatureCollection, ...) + else: + raise InvalidBBoxException(f"Can not construct BBoxDict from {x!r}") + +
    +[docs] + @classmethod + def from_dict(cls, data: dict) -> BBoxDict: + """Build from dictionary with at least keys "west", "south", "east", and "north".""" + expected_fields = {"west", "south", "east", "north"} + # TODO: also support upper case fields? + # TODO: optional support for parameterized bbox fields? + missing = expected_fields.difference(data.keys()) + if missing: + raise InvalidBBoxException(f"Missing bbox fields {sorted(missing)}") + invalid = {k: data[k] for k in expected_fields if not isinstance(data[k], (int, float))} + if invalid: + raise InvalidBBoxException(f"Non-numerical bbox fields {invalid}.") + return cls(west=data["west"], south=data["south"], east=data["east"], north=data["north"], crs=data.get("crs"))
    + + +
    +[docs] + @classmethod + def from_sequence(cls, seq: Union[list, tuple], crs: Optional[str] = None) -> BBoxDict: + """Build from sequence of 4 bounds (west, south, east and north).""" + if len(seq) != 4: + raise InvalidBBoxException(f"Expected sequence with 4 items, but got {len(seq)}.") + return cls(west=seq[0], south=seq[1], east=seq[2], north=seq[3], crs=crs)
    +
    + + + +
    +[docs] +def to_bbox_dict(x: Any, *, crs: Optional[Union[str, int]] = None) -> BBoxDict: + """ + Convert given data or object to a bounding box dictionary + (having keys "west", "south", "east", "north", and optionally "crs"). + + Supports various input types/formats: + + - list/tuple (assumed to be in west-south-east-north order) + + >>> to_bbox_dict([3, 50, 4, 51]) + {'west': 3, 'south': 50, 'east': 4, 'north': 51} + + - dictionary (unnecessary items will be stripped) + + >>> to_bbox_dict({ + ... "color": "red", "shape": "triangle", + ... "west": 1, "south": 2, "east": 3, "north": 4, "crs": "EPSG:4326", + ... }) + {'west': 1, 'south': 2, 'east': 3, 'north': 4, 'crs': 'EPSG:4326'} + + - a shapely geometry + + .. versionadded:: 0.10.1 + + :param x: input data that describes west-south-east-north bounds in some way, e.g. as a dictionary, + a list, a tuple, ashapely geometry, ... + :param crs: (optional) CRS field + :return: dictionary (subclass) with keys "west", "south", "east", "north", and optionally "crs". + """ + return BBoxDict.from_any(x=x, crs=crs)
    + + + +def url_join(root_url: str, path: str): + """Join a base url and sub path properly.""" + return urljoin(root_url.rstrip("/") + "/", path.lstrip("/")) + + +def clip(x: float, min: float, max: float) -> float: + """Clip given value between minimum and maximum value""" + return min if x < min else (x if x < max else max) + + +class SimpleProgressBar: + """Simple ASCII-based progress bar helper.""" + + __slots__ = ["width", "bar", "fill", "left", "right"] + + def __init__(self, width: int = 40, *, bar: str = "#", fill: str = "-", left: str = "[", right: str = "]"): + self.width = int(width) + self.bar = bar[0] + self.fill = fill[0] + self.left = left + self.right = right + + def get(self, fraction: float) -> str: + width = self.width - len(self.left) - len(self.right) + bar = self.bar * int(round(width * clip(fraction, min=0, max=1))) + return f"{self.left}{bar:{self.fill}<{width}s}{self.right}" + + +
    +[docs] +def normalize_crs(crs: Any, *, use_pyproj: bool = True) -> Union[None, int, str]: + """ + Normalize the given value (describing a CRS or Coordinate Reference System) + to an openEO compatible EPSG code (int) or WKT2 CRS string. + + At minimum, the following input values are handled: + + - an integer value (e.g. ``4326``) is interpreted as an EPSG code + - a string that just contains an integer (e.g. ``"4326"``) + or with and additional ``"EPSG:"`` prefix (e.g. ``"EPSG:4326"``) + will also be interpreted as an EPSG value + + Additional support and behavior depends on the availability of the ``pyproj`` library: + + - When available, it will be used for parsing and validation: + everything supported by `pyproj.CRS.from_user_input <https://pyproj4.github.io/pyproj/dev/api/crs/crs.html#pyproj.crs.CRS.from_user_input>`_ is allowed. + See the ``pyproj`` docs for more details. + - Otherwise, some best effort validation is done: + EPSG looking integer or string values will be parsed as such as discussed above. + Other strings will be assumed to be WKT2 already. + Other data structures will not be accepted. + + :param crs: value that encodes a coordinate reference system, typically just an int (EPSG code) or string (authority string). + If the ``pyproj`` library is available, everything supported by it is allowed. + + :param use_pyproj: whether ``pyproj`` should be leveraged at all + (mainly useful for testing the "no pyproj available" code path) + + :return: EPSG code as int, or WKT2 string. Or None if input was empty. + + :raises ValueError: + When the given CRS data can not be parsed/converted/normalized. + + """ + if crs in (None, "", {}): + return None + + if pyproj and use_pyproj: + try: + # (if available:) let pyproj do the validation/parsing + crs_obj = pyproj.CRS.from_user_input(crs) + # Convert back to EPSG int or WKT2 string + crs = crs_obj.to_epsg() or crs_obj.to_wkt() + except pyproj.ProjError as e: + raise ValueError(f"Failed to normalize CRS data with pyproj: {crs!r}") from e + else: + # Best effort simple validation/normalization + if isinstance(crs, int) and crs > 0: + # Assume int is already valid EPSG code + pass + elif isinstance(crs, str): + # Parse as EPSG int code if it looks like that, + # otherwise: leave it as-is, assuming it is a valid WKT2 CRS string + if re.match(r"^(epsg:)?\d+$", crs.strip(), flags=re.IGNORECASE): + crs = int(crs.split(":")[-1]) + elif "GEOGCRS[" in crs: + # Very simple WKT2 CRS detection heuristic + logger.warning(f"Assuming this is a valid WK2 CRS string: {repr_truncate(crs)}") + else: + raise ValueError(f"Can not normalize CRS string {repr_truncate(crs)}") + else: + raise ValueError(f"Can not normalize CRS data {type(crs)}") + + return crs
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/_sources/api-processbuilder.rst.txt b/_sources/api-processbuilder.rst.txt new file mode 100644 index 000000000..7ebdca75c --- /dev/null +++ b/_sources/api-processbuilder.rst.txt @@ -0,0 +1,87 @@ +.. FYI this file is intended to be inlined (with "include" RST directive) + in the ProcessBuilder class doc block, + which in turn is covered with autodoc/automodule from api-processes.rst. + + +The :py:class:`ProcessBuilder ` class +is a helper class that implements +(much like the :ref:`openEO process functions `) +each openEO process as a method. +On top of that it also adds syntactic sugar to support Python operators as well +(e.g. ``+`` is translated to the ``add`` process). + +.. attention:: + As normal user, you should never create a + :py:class:`ProcessBuilder ` instance + directly. + + You should only interact with this class inside a callback + function/lambda while building a child callback process graph + as discussed at :ref:`child_callback_callable`. + + +For example, let's start from this simple usage snippet +where we want to reduce the temporal dimension +by taking the temporal mean of each timeseries: + +.. code-block:: python + + def my_reducer(data): + return data.mean() + + cube.reduce_dimension(reducer=my_reducer, dimension="t") + +Note that this ``my_reducer`` function has a ``data`` argument, +which conceptually corresponds to an array of pixel values +(along the temporal dimension). +However, it's important to understand that the ``my_reducer`` function +is actually *not evaluated when you execute your process graph* +on an openEO back-end, e.g. as a batch jobs. +Instead, ``my_reducer`` is evaluated +*while building your process graph client-side* +(at the time you execute that ``cube.reduce_dimension()`` statement to be precise). +This means that that ``data`` argument is actually not a concrete array of EO data, +but some kind of *virtual placeholder*, +a :py:class:`ProcessBuilder ` instance, +that keeps track of the operations you intend to do on the EO data. + +To make that more concrete, it helps to add type hints +which will make it easier to discover what you can do with the argument +(depending on which editor or IDE you are using): + +.. code-block:: python + + from openeo.processes import ProcessBuilder + + def my_reducer(data: ProcessBuilder) -> ProcessBuilder: + return data.mean() + + cube.reduce_dimension(reducer=my_reducer, dimension="t") + + +Because :py:class:`ProcessBuilder ` methods +return new :py:class:`ProcessBuilder ` instances, +and because it support syntactic sugar to use Python operators on it, +and because :ref:`openeo.process functions ` +also accept and return :py:class:`ProcessBuilder ` instances, +we can mix methods, functions and operators in the callback function like this: + +.. code-block:: python + + from openeo.processes import ProcessBuilder, cos + + def my_reducer(data: ProcessBuilder) -> ProcessBuilder: + return cos(data.mean()) + 1.23 + + cube.reduce_dimension(reducer=my_reducer, dimension="t") + +or compactly, using an anonymous lambda expression: + +.. code-block:: python + + from openeo.processes import cos + + cube.reduce_dimension( + reducer=lambda data: cos(data.mean())) + 1.23, + dimension="t" + ) diff --git a/_sources/api-processes.rst.txt b/_sources/api-processes.rst.txt new file mode 100644 index 000000000..a27d876c4 --- /dev/null +++ b/_sources/api-processes.rst.txt @@ -0,0 +1,69 @@ +========================= +API: ``openeo.processes`` +========================= + +The ``openeo.processes`` module contains building blocks and helpers +to construct so called "child callbacks" for openEO processes like +:py:meth:`openeo.rest.datacube.DataCube.apply` and +:py:meth:`openeo.rest.datacube.DataCube.reduce_dimension`, +as discussed at :ref:`child_callback_callable`. + +.. note:: + The contents of the ``openeo.processes`` module is automatically compiled + from the official openEO process specifications. + Developers that want to fix bugs in, or add implementations to this + module should not touch the file directly, but instead address it in the + upstream `openeo-processes `_ repository + or in the internal tooling to generate this file. + + +.. contents:: Sections: + :depth: 1 + :local: + :backlinks: top + + +.. _openeo_processes_functions: + +Functions in ``openeo.processes`` +--------------------------------- + +The ``openeo.processes`` module implements (at top-level) +a regular Python function for each openEO process +(not only the official stable ones, but also experimental ones in "proposal" state). + +These functions can be used directly as child callback, +for example as follows: + +.. code-block:: python + + from openeo.processes import absolute, max + + cube.apply(absolute) + cube.reduce_dimension(max, dimension="t") + + +Note how the signatures of the parent :py:class:`DataCube ` methods +and the callback functions match up: + +- :py:meth:`DataCube.apply() ` + expects a callback that receives a single numerical value, + which corresponds to the parameter signature of :py:func:`openeo.processes.absolute` +- :py:meth:`DataCube.reduce_dimension() ` + expects a callback that receives an array of numerical values, + which corresponds to the parameter signature :py:func:`openeo.processes.max` + + +.. automodule:: openeo.processes + :members: + :exclude-members: ProcessBuilder, process, _process + + +``ProcessBuilder`` helper class +-------------------------------- + +.. FYI the ProcessBuilder docs are provided through its doc block + with an RST "include" of "api-processbuilder.rst" + +.. automodule:: openeo.processes + :members: ProcessBuilder diff --git a/_sources/api.rst.txt b/_sources/api.rst.txt new file mode 100644 index 000000000..b47795368 --- /dev/null +++ b/_sources/api.rst.txt @@ -0,0 +1,148 @@ +============= +API (General) +============= + +High level Interface +-------------------- + +The high-level interface tries to provide an opinionated, Pythonic, API +to interact with openEO back-ends. It's aim is to hide some of the details +of using a web service, so the user can produce concise and readable code. + +Users that want to interact with openEO on a lower level, and have more control, can +use the lower level classes. + + +openeo +-------- + +.. autofunction:: openeo.connect + + +openeo.rest.datacube +----------------------- + +.. automodule:: openeo.rest.datacube + :members: DataCube + :inherited-members: + :special-members: __init__ + +.. automodule:: openeo.rest._datacube + :members: UDF + + +openeo.rest.vectorcube +------------------------ + +.. automodule:: openeo.rest.vectorcube + :members: VectorCube + :inherited-members: + + +openeo.rest.mlmodel +--------------------- + +.. automodule:: openeo.rest.mlmodel + :members: MlModel + :inherited-members: + + +openeo.metadata +---------------- + +.. automodule:: openeo.metadata + :members: CollectionMetadata, BandDimension, SpatialDimension, TemporalDimension + + +openeo.api.process +-------------------- + +.. automodule:: openeo.api.process + :members: Parameter + + +openeo.api.logs +----------------- + +.. automodule:: openeo.api.logs + :members: LogEntry, normalize_log_level + + +openeo.rest.connection +---------------------- + +.. automodule:: openeo.rest.connection + :members: Connection + + +openeo.rest.job +------------------ + +.. automodule:: openeo.rest.job + :members: BatchJob, RESTJob, JobResults, ResultAsset + + +openeo.rest.conversions +------------------------- + +.. automodule:: openeo.rest.conversions + :members: + + +openeo.rest.udp +----------------- + +.. automodule:: openeo.rest.udp + :members: RESTUserDefinedProcess, build_process_dict + + +openeo.rest.userfile +---------------------- + +.. automodule:: openeo.rest.userfile + :members: + + +openeo.udf +------------- + +.. automodule:: openeo.udf.udf_data + :members: UdfData + +.. automodule:: openeo.udf.xarraydatacube + :members: XarrayDataCube + +.. automodule:: openeo.udf.structured_data + :members: StructuredData + +.. automodule:: openeo.udf.run_code + :members: execute_local_udf + +.. automodule:: openeo.udf.debug + :members: inspect + + +openeo.util +------------- + +.. automodule:: openeo.util + :members: to_bbox_dict, BBoxDict, load_json_resource, normalize_crs + + +openeo.processes +---------------- + +.. automodule:: openeo.processes + :members: process + + +Graph building +---------------- + +Various utilities and helpers to simplify the construction of openEO process graphs. + +.. automodule:: openeo.rest.graph_building + :members: collection_property, CollectionProperty + +.. automodule:: openeo.internal.graph_building + :members: PGNode, FlatGraphableMixin diff --git a/_sources/auth.rst.txt b/_sources/auth.rst.txt new file mode 100644 index 000000000..a01713163 --- /dev/null +++ b/_sources/auth.rst.txt @@ -0,0 +1,614 @@ +.. _authentication_chapter: + +************************************* +Authentication and Account Management +************************************* + + +While a couple of openEO operations can be done +anonymously, most of the interesting parts +of the API require you to identify as a registered +user. +The openEO API specifies two ways to authenticate +as a user: + +* OpenID Connect (recommended, but not always straightforward to use) +* Basic HTTP Authentication (not recommended, but practically easier in some situations) + +To illustrate how to authenticate with the openEO Python Client Library, +we start form a back-end connection:: + + import openeo + + connection = openeo.connect("https://openeo.example.com") + +Basic HTTP Auth +=============== + +Let's start with the easiest authentication method, +based on the Basic HTTP authentication scheme. +It is however *not recommended* for various reasons, +such as its limited *security* measures. +For example, if you are connecting to a back-end with a ``http://`` URL +instead of a ``https://`` one, you should certainly not use basic HTTP auth. + +With these security related caveats out of the way, you authenticate +using your username and password like this:: + + connection.authenticate_basic("john", "j0hn123") + +Subsequent usage of the connection object ``connection`` will +use authenticated calls. +For example, show information about the authenticated user:: + + >>> connection.describe_account() + {'user_id': 'john'} + + + +OpenID Connect Based Authentication +=================================== + +OpenID Connect (often abbreviated "OIDC") is an identity layer on top of the OAuth 2.0 protocol. +An in-depth discussion of the whole architecture would lead us too far here, +but some central OpenID Connect concepts are quite useful to understand +in the context of working with openEO: + +* There is **decoupling** between: + + * the *OpenID Connect identity provider* + which handles the authentication/authorization and stores user information + (e.g. an organization Google, Github, Microsoft, your academic/research institution, ...) + * the *openEO back-end* which manages earth observation collections + and executes your algorithms + + Instead of managing the authentication procedure itself, + an openEO back-end forwards a user to the relevant OpenID Connect provider to authenticate + and request access to basic profile information (e.g. email address). + On return, when the user allowed this access, + the openEO back-end receives the profile information and uses this to identify the user. + + Note that with this approach, the back-end does not have to + take care of all the security and privacy challenges + of properly handling user registration, passwords/authentication, etc. + Also, it allows the user to securely reuse an existing account + registered with an established organisation, instead of having + to register yet another account with some web service. + +* Your openEO script or application acts as + a so called **OpenID Connect client**, with an associated **client id**. + In most cases, a default client (id) defined by the openEO back-end will be used automatically. + For some applications a custom client might be necessary, + but this is out of scope of this documentation. + +* OpenID Connect authentication can be done with different kind of "**flows**" (also called "grants") + and picking the right flow depends on your specific use case. + The most common OIDC flows using the openEO Python Client Library are: + + * :ref:`authenticate_oidc_device` + * :ref:`authenticate_oidc_client_credentials` + * :ref:`authenticate_oidc_refresh_token` + + +OpenID Connect is clearly more complex than Basic HTTP Auth. +In the sections below we will discuss the practical details of each flow. + +General options +--------------- + +* A back-end might support **multiple OpenID Connect providers**. + The openEO Python Client Library will pick the first one by default, + but another another provider can specified explicity with the ``provider_id`` argument, e.g.: + + .. code-block:: python + + connection.authenticate_oidc_device( + provider_id="gl", + ... + ) + + + +.. _authenticate_oidc_device: + +OIDC Authentication: Device Code Flow +====================================== + +The device code flow (also called device authorization grant) +is an interactive flow that requires a web browser for the authentication +with the OpenID Connect provider. +The nice things is that the browser doesn't have to run on +the same system or network as where you run your application, +you could even use a browser on your mobile phone. + +Use :py:meth:`~openeo.rest.connection.Connection.authenticate_oidc_device` to initiate the flow: + +.. code-block:: python + + connection.authenticate_oidc_device() + +This will print a message like this: + +.. code-block:: text + + Visit https://oidc.example.net/device + and enter user code 'DTNY-KLNX' to authenticate. + +Some OpenID Connect Providers use a slightly longer URL that already includes +the user code, and then you don't need to enter the user code in one of the next steps: + +.. code-block:: text + + Visit https://oidc.example.net/device?user_code=DTNY-KLNX to authenticate. + +You should now visit this URL in your browser of choice. +Usually, it is intentionally a short URL to make it feasible to type it +instead of copy-pasting it (e.g. on another device). + +Authenticate with the OpenID Connect provider and, if requested, enter the user code +shown in the message. +When the URL already contains the user code, the page won't ask for this code. + +Meanwhile, the openEO Python Client Library is actively polling the OpenID Connect +provider and when you successfully complete the authentication, +it will receive the necessary tokens for authenticated communication +with the back-end and print: + +.. code-block:: text + + Authorized successfully. + +In case of authentication failure, the openEO Python Client Library +will stop polling at some point and raise an exception. + + + + +.. _authenticate_oidc_refresh_token: + +OIDC Authentication: Refresh Token Flow +======================================== + +When OpenID Connect authentication completes successfully, +the openID Python library receives an access token +to be used when doing authenticated calls to the back-end. +The access token usually has a short lifetime to reduce +the security risk when it would be stolen or intercepted. +The openID Python library also receives a *refresh token* +that can be used, through the Refresh Token flow, +to easily request a new access token, +without having to re-authenticate, +which makes it useful for **non-interactive uses cases**. + + +However, as it needs an existing refresh token, +the Refresh Token Flow requires +**first to authenticate with one of the other flows** +(but in practice this should not be done very often +because refresh tokens usually have a relatively long lifetime). +When doing the initial authentication, +you have to explicitly enable storage of the refresh token, +through the ``store_refresh_token`` argument, e.g.: + +.. code-block:: python + + connection.authenticate_oidc_device( + ... + store_refresh_token=True + + + +The refresh token will be stored in file in private file +in your home directory and will be used automatically +when authenticating with the Refresh Token Flow, +using :py:meth:`~openeo.rest.connection.Connection.authenticate_oidc_refresh_token`: + +.. code-block:: python + + connection.authenticate_oidc_refresh_token( + client_secret=client_secret, + client_id=client_id + ) + +You can also bootstrap the refresh token file +as described in :ref:`oidc_auth_get_refresh_token` + + + +.. _authenticate_oidc_client_credentials: + +OIDC Authentication: Client Credentials Flow +============================================= + +The OIDC Client Credentials flow does not involve interactive authentication (e.g. through a web browser), +which makes it a useful option for **non-interactive use cases**. + +.. important:: + This method requires a custom **OIDC client id** and **client secret**. + It is out of scope of this general documentation to explain + how to obtain these as it depends on the openEO back-end you are using + and the OIDC provider that is in play. + + Also, your openEO back-end might not allow it, because technically + you are authenticating a *client* instead of a *user*. + + Consult the support of the openEO back-end you want to use for more information. + +In its most simple form, given your client id and secret, +you can authenticate with +:py:meth:`~openeo.rest.connection.Connection.authenticate_oidc_client_credentials` +as follows: + +.. code-block:: python + + connection.authenticate_oidc_client_credentials( + client_id=client_id, + client_secret=client_secret, + ) + +You might also have to pass a custom provider id (argument ``provider_id``) +if your OIDC client is associated with an OIDC provider that is different from the default provider. + +.. caution:: + Make sure to *keep the client secret a secret* and avoid putting it directly in your source code + or, worse, committing it to a version control system. + Instead, fetch the secret from a protected source (e.g. a protected file, a database for sensitive data, ...) + or from environment variables. + +.. _authenticate_oidc_client_credentials_env_vars: + +OIDC Client Credentials Using Environment Variables +---------------------------------------------------- + +Since version 0.18.0, the openEO Python Client Library has built-in support to get the client id, +secret (and provider id) from environment variables +``OPENEO_AUTH_CLIENT_ID``, ``OPENEO_AUTH_CLIENT_SECRET`` and ``OPENEO_AUTH_PROVIDER_ID`` respectively. +Just call :py:meth:`~openeo.rest.connection.Connection.authenticate_oidc_client_credentials` +without arguments. + +Usage example assuming a Linux (Bash) shell context: + +.. code-block:: console + + $ export OPENEO_AUTH_CLIENT_ID="my-client-id" + $ export OPENEO_AUTH_CLIENT_SECRET="Cl13n7S3cr3t!?123" + $ export OPENEO_AUTH_PROVIDER_ID="oidcprovider" + $ python + >>> import openeo + >>> connection = openeo.connect("openeo.example.com") + >>> connection.authenticate_oidc_client_credentials() + + + + +.. _authenticate_oidc_automatic: + +OIDC Authentication: Dynamic Method Selection +============================================== + +The sections above discuss various authentication options, like +the :ref:`device code flow `, +:ref:`refresh tokens ` and +:ref:`client credentials flow `, +but often you want to *dynamically* switch between these depending on the situation: +e.g. use a refresh token if you have an active one, and fallback on the device code flow otherwise. +Or you want to be able to run the same code in an interactive environment and automated in an unattended manner, +without having to switch authentication methods explicitly in code. + +That is what :py:meth:`Connection.authenticate_oidc() ` is for: + +.. code-block:: python + + connection.authenticate_oidc() # is all you need + +In a basic situation (without any particular environment variables set as discussed further), +this method will first try to authenticate with refresh tokens (if any) +and fall back on the device code flow otherwise. +Ideally, when valid refresh tokens are available, this works without interaction, +but occasionally, when the refresh tokens expire, one has to do the interactive device code flow. + +Since version 0.18.0, the openEO Python Client Library also allows to trigger the +:ref:`client credentials flow ` +from :py:meth:`~openeo.rest.connection.Connection.authenticate_oidc` +by setting environment variable ``OPENEO_AUTH_METHOD`` +and the other :ref:`client credentials environment variables `. +For example: + +.. code-block:: shell + + $ export OPENEO_AUTH_METHOD="client_credentials" + $ export OPENEO_AUTH_CLIENT_ID="my-client-id" + $ export OPENEO_AUTH_CLIENT_SECRET="Cl13n7S3cr3t!?123" + $ export OPENEO_AUTH_PROVIDER_ID="oidcprovider" + $ python + >>> import openeo + >>> connection = openeo.connect("openeo.example.com") + >>> connection.authenticate_oidc() + + + + + + + + + +.. _auth_configuration_files: + +Auth config files and ``openeo-auth`` helper tool +==================================================== + +The openEO Python Client Library provides some features and tools +that ease the usability and security challenges +that come with authentication (especially in case of OpenID Connect). + +Note that the code examples above contain quite some **passwords and other secrets** +that should be kept safe from prying eyes. +It is bad practice to define these kind of secrets directly +in your scripts and source code because that makes it quite hard +to responsibly share or reuse your code. +Even worse is storing these secrets in your version control system, +where it might be near impossible to remove them again. +A better solution is to keep **secrets in separate configuration or cache files**, +outside of your normal source code tree +(to avoid committing them accidentally). + + +The openEO Python Client Library supports config files to store: +user names, passwords, client IDs, client secrets, etc, +so you don't have to specify them always in your scripts and applications. + +The openEO Python Client Library (when installed properly) +provides a command line tool ``openeo-auth`` to bootstrap and manage +these configs and secrets. +It is a command line tool that provides various "subcommands" +and has built-in help:: + + $ openeo-auth -h + usage: openeo-auth [-h] [--verbose] + {paths,config-dump,token-dump,add-basic,add-oidc,oidc-auth} + ... + + Tool to manage openEO related authentication and configuration. + + optional arguments: + -h, --help show this help message and exit + + Subcommands: + {paths,config-dump,token-dump,add-basic,add-oidc,oidc-auth} + paths Show paths to config/token files. + config-dump Dump config file. + ... + + + +For example, to see the expected paths of the config files:: + + $ openeo-auth paths + openEO auth config: /home/john/.config/openeo-python-client/auth-config.json (perms: 0o600, size: 1414B) + openEO OpenID Connect refresh token store: /home/john/.local/share/openeo-python-client/refresh-tokens.json (perms: 0o600, size: 846B) + + +With the ``config-dump`` and ``token-dump`` subcommands you can dump +the current configuration and stored refresh tokens, e.g.:: + + $ openeo-auth config-dump + ### /home/john/.config/openeo-python-client/auth-config.json ############### + { + "backends": { + "https://openeo.example.com": { + "basic": { + "username": "john", + "password": "", + "date": "2020-07-24T13:40:50Z" + ... + +The sensitive information (like passwords) are redacted by default. + + + +Basic HTTP Auth config +----------------------- + +With the ``add-basic`` subcommand you can add Basic HTTP Auth credentials +for a given back-end to the config. +It will interactively ask for username and password and +try if these credentials work:: + + $ openeo-auth add-basic https://openeo.example.com/ + Enter username and press enter: john + Enter password and press enter: + Trying to authenticate with 'https://openeo.example.com' + Successfully authenticated 'john' + Saved credentials to '/home/john/.config/openeo-python-client/auth-config.json' + +Now you can authenticate in your application without having to +specify username and password explicitly:: + + connection.authenticate_basic() + +OpenID Connect configs +----------------------- + +Likewise, with the ``add-oidc`` subcommand you can add OpenID Connect +credentials to the config:: + + $ openeo-auth add-oidc https://openeo.example.com/ + Using provider ID 'example' (issuer 'https://oidc.example.net/') + Enter client_id and press enter: client-d7393fba + Enter client_secret and press enter: + Saved client information to '/home/john/.config/openeo-python-client/auth-config.json' + +Now you can user OpenID Connect based authentication in your application +without having to specify the client ID and client secret explicitly, +like one of these calls:: + + connection.authenticate_oidc_authorization_code() + connection.authenticate_oidc_client_credentials() + connection.authenticate_oidc_resource_owner_password_credentials(username=username, password=password) + connection.authenticate_oidc_device() + connection.authenticate_oidc_refresh_token() + +Note that you still have to add additional options as required, like +``provider_id``, ``server_address``, ``store_refresh_token``, etc. + + +.. _oidc_auth_get_refresh_token: + +OpenID Connect refresh tokens +````````````````````````````` + +There is also a ``oidc-auth`` subcommand to execute an OpenID Connect +authentication flow and store the resulting refresh token. +This is intended to for bootstrapping the environment or system +on which you want to run openEO scripts or applications that use +the Refresh Token Flow for authentication. +For example:: + + $ openeo-auth oidc-auth https://openeo.example.com + Using config '/home/john/.config/openeo-python-client/auth-config.json'. + Starting OpenID Connect device flow. + To authenticate: visit https://oidc.example.net/device and enter the user code 'Q7ZNsy'. + Authorized successfully. + The OpenID Connect device flow was successful. + Stored refresh token in '/home/john/.local/share/openeo-python-client/refresh-tokens.json' + + + +.. _default_url_and_auto_auth: + +Default openEO back-end URL and auto-authentication +===================================================== + +.. versionadded:: 0.10.0 + + +If you often use the same openEO back-end URL and authentication scheme, +it can be handy to put these in a configuration file as discussed at :ref:`configuration_files`. + +.. note:: + Note that :ref:`these general configuration files ` are different + from the auth config files discussed earlier under :ref:`auth_configuration_files`. + The latter are for storing authentication related secrets + and are mostly managed automatically (e.g. by the ``oidc-auth`` helper tool). + The former are not for storing secrets and are usually edited manually. + +For example, to define a default back-end and automatically use OpenID Connect authentication +add these configuration options to the :ref:`desired configuration file `:: + + [Connection] + default_backend = openeo.cloud + default_backend.auto_authenticate = oidc + +Getting an authenticated connection is now as simple as:: + + >>> import openeo + >>> connection = openeo.connect() + Loaded openEO client config from openeo-client-config.ini + Using default back-end URL 'openeo.cloud' (from config) + Doing auto-authentication 'oidc' (from config) + Authenticated using refresh token. + + +Authentication for long-running applications and non-interactive contexts +=========================================================================== + +With OpenID Connect authentication, the *access token* +(which is used in the authentication headers) +is typically short-lived (e.g. couple of minutes or hours). +This practically means that an authenticated connection could expire and become unusable +before a **long-running script or application** finishes its whole workflow. +Luckily, OpenID Connect also includes usage of *refresh tokens*, +which have a much longer expiry and allow request a new access token +to re-authenticate the connection. +Since version 0.10.1, te openEO Python Client Library will automatically +attempt to re-authenticate a connection when access token expiry is detected +and valid refresh tokens are available. + +Likewise, refresh tokens can also be used for authentication in cases +where a script or application is **run automatically in the background on regular basis** (daily, weekly, ...). +If there is a non-expired refresh token available, the script can authenticate +without user interaction. + +Guidelines and tips +-------------------- + +Some guidelines to get long-term and non-interactive authentication working for your use case: + +- If you run a workflow periodically, but the interval between runs + is larger than the expiry time of the refresh token + (e.g. a monthly job, while the refresh token expires after, say, 10 days), + you could consider setting up a *custom OIDC client* with better suited + refresh token timeout. + The practical details of this heavily depend on the OIDC Identity Provider + in play and are out of scope of this discussion. +- Obtaining a refresh token requires manual/interactive authentication, + but once it is stored on the necessary machine(s) + in the refresh token store as discussed in :ref:`auth_configuration_files`, + no further manual interaction should be necessary + during the lifetime of the refresh token. + To do so, use one of the following methods: + + - Use the ``openeo-auth oidc-auth`` cli tool, for example to authenticate + for openeo back-end openeo.example.com:: + + $ openeo-auth oidc-auth openeo.example.com + ... + Stored refresh token in '/home/john/.local/share/openeo-python-client/refresh-tokens.json' + + + - Use a Python snippet to authenticate and store the refresh token:: + + import openeo + connection = openeo.connect("openeo.example.com") + connection.authenticate_oidc_device(store_refresh_token=True) + + + To verify that (and where) the refresh token is stored, use ``openeo-auth token-dump``:: + + $ openeo-auth token-dump + ### /home/john/.local/share/openeo-python-client/refresh-tokens.json ####### + { + "https://oidc.example.net": { + "default-client": { + "date": "2022-05-11T13:13:20Z", + "refresh_token": "" + }, + ... + + + +Best Practices and Troubleshooting Tips +======================================== + +.. warning:: + + Handle (OIDC) access and refresh tokens like secret, personal passwords. + **Never share your access or refresh tokens** with other people, + publicly, or for user support reasons. + + +Clear the refresh token file +---------------------------- + +When you have authentication or permission issues and you suspect +that your (locally cached) refresh tokens are the culprit: +remove your refresh token file in one of the following ways: + +- Locate the file with the ``openeo-auth`` command line tool:: + + $ openeo-auth paths + ... + openEO OpenID Connect refresh token store: /home/john/.local/share/openeo-python-client/refresh-tokens.json (perms: 0o600, size: 846B) + + and remove it. + Or, if you know what you are doing: remove the desired section from this JSON file. + +- Remove it directly with the ``token-clear`` subcommand of the ``openeo-auth`` command line tool:: + + $ openeo-auth token-clear + +- Remove it with this Python snippet:: + + from openeo.rest.auth.config import RefreshTokenStore + RefreshTokenStore().remove() diff --git a/_sources/basics.rst.txt b/_sources/basics.rst.txt new file mode 100644 index 000000000..96ecd5f4e --- /dev/null +++ b/_sources/basics.rst.txt @@ -0,0 +1,453 @@ +================ +Getting Started +================ + + +Connect to an openEO back-end +============================== + +First, establish a connection to an openEO back-end, using its connection URL. +For example the VITO/Terrascope backend: + +.. code-block:: python + + import openeo + + connection = openeo.connect("openeo.vito.be") + +The resulting :py:class:`~openeo.rest.connection.Connection` object is your central gateway to + +- list data collections, available processes, file formats and other capabilities of the back-end +- start building your openEO algorithm from the desired data on the back-end +- execute and monitor (batch) jobs on the back-end +- etc. + +.. seealso:: + + Use the `openEO Hub `_ to explore different back-end options + and their capabilities in a web-based way. + + +Collection discovery +===================== + +The Earth observation data (the input of your openEO jobs) is organised in +`so-called collections `_, +e.g. fundamental satellite collections like "Sentinel 1" or "Sentinel 2", +or preprocessed collections like "NDVI". + +You can programmatically list the collections that are available on a back-end +and their metadata using methods on the `connection` object we just created +(like :py:meth:`~openeo.rest.connection.Connection.list_collection_ids` +or :py:meth:`~openeo.rest.connection.Connection.describe_collection` + +.. code-block:: pycon + + >>> # Get all collection ids + >>> connection.list_collection_ids() + ['SENTINEL1_GRD', 'SENTINEL2_L2A', ... + + >>> # Get metadata of a single collection + >>> connection.describe_collection("SENTINEL2_L2A") + {'id': 'SENTINEL2_L2A', 'title': 'Sentinel-2 top of canopy ...', 'stac_version': '0.9.0', ... + +Congrats, you now just did your first real openEO queries to the openEO back-end +using the openEO Python client library. + +.. tip:: + The openEO Python client library comes with **Jupyter (notebook) integration** in a couple of places. + For example, put ``connection.describe_collection("SENTINEL2_L2A")`` (without ``print()``) + as last statement in a notebook cell + and you'll get a nice graphical rendering of the collection metadata. + +.. seealso:: + + Find out more about data discovery, loading and filtering at :ref:`data_access_chapter`. + + +Authentication +============== + +In the code snippets above we did not need to log in as a user +since we just queried publicly available back-end information. +However, to run non-trivial processing queries one has to authenticate +so that permissions, resource usage, etc. can be managed properly. + +To handle authentication, openEO leverages `OpenID Connect (OIDC) `_. +It offers some interesting features (e.g. a user can securely reuse an existing account), +but is a fairly complex topic, discussed in more depth at :ref:`authentication_chapter`. + +The openEO Python client library tries to make authentication as streamlined as possible. +In most cases for example, the following snippet is enough to obtain an authenticated connection: + +.. code-block:: python + + import openeo + + connection = openeo.connect("openeo.vito.be").authenticate_oidc() + +This statement will automatically reuse a previously authenticated session, when available. +Otherwise, e.g. the first time you do this, some user interaction is required +and it will print a web link and a short *user code*, for example: + +.. code-block:: + + To authenticate: visit https://aai.egi.eu/auth/realms/egi/device and enter the user code 'SLUO-BMUD'. + +Visit this web page in a browser, log in there with an existing account and enter the user code. +If everything goes well, the ``connection`` object in the script will be authenticated +and the back-end will be able to identify you in subsequent requests. + + + +.. _basic_example_evi_map_and_timeseries: + +Example use case: EVI map and timeseries +========================================= + +A common task in earth observation is to apply a formula to a number of spectral bands +in order to compute an 'index', such as NDVI, NDWI, EVI, ... +In this tutorial we'll go through a couple of steps to extract +EVI (enhanced vegetation index) values and timeseries, +and discuss some openEO concepts along the way. + + +Loading an initial data cube +============================= + +For calculating the EVI, we need the reflectance of the +red, blue and (near) infrared spectral components. +These spectral bands are part of the well-known Sentinel-2 data set +and is available on the current back-end under collection id ``SENTINEL2_L2A``. +We load an initial small spatio-temporal slice (a data cube) as follows: + +.. code-block:: python + + sentinel2_cube = connection.load_collection( + "SENTINEL2_L2A", + spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19}, + temporal_extent = ["2021-02-01", "2021-04-30"], + bands=["B02", "B04", "B08"] + ) + +Note how we specify a the region of interest, a time range and a set of bands to load. + +.. important:: + By filtering as early as possible (directly in :py:meth:`~openeo.rest.connection.Connection.load_collection` in this case), + we make sure the back-end only loads the data we are interested in + for better performance and keeping the processing costs low. + +.. seealso:: + See the chapter :ref:`data_access_chapter` for more details on data discovery, + general data loading (:ref:`data-loading-and-filtering`) and filtering + (e.g. :ref:`temporal-extent-handling`). + + +The :py:meth:`~openeo.rest.connection.Connection.load_collection` method on the connection +object created a :py:class:`~openeo.rest.datacube.DataCube` object (variable ``sentinel2_cube``). +This :py:class:`~openeo.rest.datacube.DataCube` class of the openEO Python Client Library +provides loads of methods corresponding to various openEO processes, +e.g. for masking, filtering, aggregation, spectral index calculation, data fusion, etc. +In the next steps we will illustrate a couple of these. + + +.. important:: + It is important to highlight that we *did not load any real EO data* yet. + Instead we just created an abstract *client-side reference*, + encapsulating the collection id, the spatial extent, the temporal extent, etc. + The actual data loading will only happen at the back-end + once we explicitly trigger the execution of the data processing pipeline we are building. + + + +Band math +========= + +From this data cube, we can now select the individual bands +with the :py:meth:`DataCube.band() ` method +and rescale the digital number values to physical reflectances: + +.. code-block:: python + + blue = sentinel2_cube.band("B02") * 0.0001 + red = sentinel2_cube.band("B04") * 0.0001 + nir = sentinel2_cube.band("B08") * 0.0001 + +We now want to compute the enhanced vegetation index +and can do that directly with these band variables: + +.. code-block:: python + + evi_cube = 2.5 * (nir - red) / (nir + 6.0 * red - 7.5 * blue + 1.0) + +.. important:: + As noted before: while this looks like an actual calculation, + there is *no real data processing going on here*. + The ``evi_cube`` object at this point is just an abstract representation + of our algorithm under construction. + The mathematical operators we used here are *syntactic sugar* + for expressing this part of the algorithm in a very compact way. + + As an illustration of this, let's have peek at the *JSON representation* + of our algorithm so far, the so-called *openEO process graph*: + + .. code-block:: text + + >>> print(evi_cube.to_json(indent=None)) + {"process_graph": {"loadcollection1": {"process_id": "load_collection", ... + ... "id": "SENTINEL2_L2A", "spatial_extent": {"west": 5.15, "south": ... + ... "multiply1": { ... "y": 0.0001}}, ... + ... "multiply3": { ... {"x": 2.5, "y": {"from_node": "subtract1"}}} ... + ... + + Note how the ``load_collection`` arguments, rescaling and EVI calculation aspects + can be deciphered from this. + Rest assured, as user you normally you don't have to worry too much + about these process graph details, + the openEO Python Client library handles this behind the scenes for you. + + +Download (synchronously) +======================== + +Let's download this as a GeoTIFF file. +Because GeoTIFF does not support a temporal dimension, +we first eliminate it by taking the temporal maximum value for each pixel: + +.. code-block:: python + + evi_composite = evi_cube.max_time() + +.. note:: + + This :py:meth:`~openeo.rest.datacube.DataCube.max_time()` is not an official openEO process + but one of the many *convenience methods* in the openEO Python Client Library + to simplify common processing patterns. + It implements a ``reduce`` operation along the temporal dimension + with a ``max`` reducer/aggregator. + +Now we can download this to a local file: + +.. code-block:: python + + evi_composite.download("evi-composite.tiff") + +This download command **triggers the actual processing** on the back-end: +it sends the process graph to the back-end and waits for the result. +It is a *synchronous operation* (the :py:meth:`~openeo.rest.datacube.DataCube.download()` call +blocks until the result is fully downloaded) and because we work on a small spatio-temporal extent, +this should only take a couple of seconds. + +If we inspect the downloaded image, we see that the maximum EVI value is heavily impacted +by cloud related artefacts, which makes the result barely usable. +In the next steps we will address cloud masking. + +.. image:: _static/images/basics/evi-composite.png + + +Batch Jobs (asynchronous execution) +=================================== + +Synchronous downloads are handy for quick experimentation on small data cubes, +but if you start processing larger data cubes, you can easily +hit *computation time limits* or other constraints. +For these larger tasks, it is recommended to work with **batch jobs**, +which allow you to work asynchronously: +after you start your job, you can disconnect (stop your script or even close your computer) +and then minutes/hours later you can reconnect to check the batch job status and download results. +The openEO Python Client Library also provides helpers to keep track of a running batch job +and show a progress report. + +.. seealso:: + + See :ref:`batch-jobs-chapter` for more details. + + +Applying a cloud mask +========================= + +As mentioned above, we need to filter out cloud pixels to make the result more usable. +It is very common for earth observation data to have separate masking layers that for instance indicate +whether a pixel is covered by a (type of) cloud or not. +For Sentinel-2, one such layer is the "scene classification" layer generated by the Sen2Cor algorithm. +In this example, we will use this layer to mask out unwanted data. + +First, we load a new ``SENTINEL2_L2A`` based data cube with this specific ``SCL`` band as single band: + +.. code-block:: python + + s2_scl = connection.load_collection( + "SENTINEL2_L2A", + spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19}, + temporal_extent = ["2021-02-01", "2021-04-30"], + bands=["SCL"] + ) + +Now we can use the compact "band math" feature again to build a +binary mask with a simple comparison operation: + +.. code-block:: python + + # Select the "SCL" band from the data cube + scl_band = s2_scl.band("SCL") + # Build mask to mask out everything but class 4 (vegetation) + mask = (scl_band != 4) + +Before we can apply this mask to the EVI cube we have to resample it, +as the "SCL" layer has a "ground sample distance" of 20 meter, +while it is 10 meter for the "B02", "B04" and "B08" bands. +We can easily do the resampling by referring directly to the EVI cube. + +.. code-block:: python + + mask_resampled = mask.resample_cube_spatial(evi_cube) + + # Apply the mask to the `evi_cube` + evi_cube_masked = evi_cube.mask(mask_resampled) + + +We can now download this as a GeoTIFF, again after taking the temporal maximum: + +.. code-block:: python + + evi_cube_masked.max_time().download("evi-masked-composite.tiff") + +Now, the EVI map is a lot more valuable, as the non-vegetation locations +and observations are filtered out: + +.. image:: _static/images/basics/evi-masked-composite.png + + +Aggregated EVI timeseries +=========================== + +A common type of analysis is aggregating pixel values over one or more regions of interest +(also known as "zonal statistics) and tracking this aggregation over a period of time as a timeseries. +Let's extract the EVI timeseries for these two regions: + +.. code-block:: python + + features = {"type": "FeatureCollection", "features": [ + { + "type": "Feature", "properties": {}, + "geometry": {"type": "Polygon", "coordinates": [[ + [5.1417, 51.1785], [5.1414, 51.1772], [5.1444, 51.1768], [5.1443, 51.179], [5.1417, 51.1785] + ]]} + }, + { + "type": "Feature", "properties": {}, + "geometry": {"type": "Polygon", "coordinates": [[ + [5.156, 51.1892], [5.155, 51.1855], [5.163, 51.1855], [5.163, 51.1891], [5.156, 51.1892] + ]]} + } + ]} + + +.. note:: + + To have a self-containing example we define the geometries here as an inline GeoJSON-style dictionary. + In a real use case, your geometry will probably come from a local file or remote URL. + The openEO Python Client Library supports alternative ways of specifying the geometry + in methods like :py:meth:`~openeo.rest.datacube.DataCube.aggregate_spatial()`, e.g. + as Shapely geometry objects. + + +Building on the experience from previous sections, we first build a masked EVI cube +(covering a longer time window than before): + +.. code-block:: python + + # Load raw collection data + sentinel2_cube = connection.load_collection( + "SENTINEL2_L2A", + spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19}, + temporal_extent = ["2020-01-01", "2021-12-31"], + bands=["B02", "B04", "B08", "SCL"], + ) + + # Extract spectral bands and calculate EVI with the "band math" feature + blue = sentinel2_cube.band("B02") * 0.0001 + red = sentinel2_cube.band("B04") * 0.0001 + nir = sentinel2_cube.band("B08") * 0.0001 + evi = 2.5 * (nir - red) / (nir + 6.0 * red - 7.5 * blue + 1.0) + + # Use the scene classification layer to mask out non-vegetation pixels + scl = sentinel2_cube.band("SCL") + evi_masked = evi.mask(scl != 4) + +Now we use the :py:meth:`~openeo.rest.datacube.DataCube.aggregate_spatial()` method +to do spatial aggregation over the geometries we defined earlier. +Note how we can specify the aggregation function ``"mean"`` as a simple string for the ``reducer`` argument. + +.. code-block:: python + + evi_aggregation = evi_masked.aggregate_spatial( + geometries=features, + reducer="mean", + ) + +If we download this, we get the timeseries encoded as a JSON structure, other useful formats are CSV and netCDF. + +.. code-block:: python + + evi_aggregation.download("evi-aggregation.json") + +.. warning:: + + Technically, the output of the openEO process ``aggregate_spatial`` + is a so-called "vector cube". + At the time of this writing, the specification of this openEO concept + is not fully fleshed out yet in the openEO API. + openEO back-ends and clients to provide best-effort support for it, + but bear in mind that some details are subject to change. + +The openEO Python Client Library provides helper functions +to convert the downloaded JSON data to a pandas dataframe, +which we massage a bit more: + +.. code-block:: python + + import json + import pandas as pd + from openeo.rest.conversions import timeseries_json_to_pandas + + import json + with open("evi-aggregation.json") as f: + data = json.load(f) + + df = timeseries_json_to_pandas(data) + df.index = pd.to_datetime(df.index) + df = df.dropna() + df.columns = ("Field A", "Field B") + +This gives us finally our EVI timeseries dataframe: + +.. code-block:: pycon + + >>> df + Field A Field B + date + 2020-01-06 00:00:00+00:00 0.522499 0.300250 + 2020-01-16 00:00:00+00:00 0.529591 0.288079 + 2020-01-18 00:00:00+00:00 0.633011 0.327598 + ... ... ... + + +.. image:: _static/images/basics/evi-timeseries.png + + +Computing multiple statistics +============================= + +The same method also allows the computation of multiple statistics at once. This does rely +on 'callbacks' to construct a result with multiple statistics. +The use of such more complex processes is further explained in :ref:`callbackfunctions`. + +.. code-block:: python + + from openeo.processes import array_create, mean, sd, median, count + + evi_aggregation = evi_masked.aggregate_spatial( + geometries=features, + reducer=lambda x: array_create([mean(x), sd(x), median(x), count(x)]), + ) diff --git a/_sources/batch_jobs.rst.txt b/_sources/batch_jobs.rst.txt new file mode 100644 index 000000000..547cb8caa --- /dev/null +++ b/_sources/batch_jobs.rst.txt @@ -0,0 +1,413 @@ + +.. index:: + single: batch job + see: job; batch job + +.. _batch-jobs-chapter: + +============ +Batch Jobs +============ + +Most of the simple, basic openEO usage examples show **synchronous** downloading of results: +you submit a process graph with a (HTTP POST) request and receive the result +as direct response of that same request. +This only works properly if the processing doesn't take too long (order of seconds, or a couple of minutes at most). + +For the heavier work (larger regions of interest, larger time series, more intensive processing, ...) +you have to use **batch jobs**, which are supported in the openEO API through separate HTTP requests, corresponding to these steps: + +- you create a job (providing a process graph and some other metadata like title, description, ...) +- you start the job +- you wait for the job to finish, periodically polling its status +- when the job finished successfully: get the listing of result assets +- you download the result assets (or use them in an other way) + +.. tip:: + + This documentation mainly discusses how to **programmatically** + create and interact with batch job using the openEO Python client library. + The openEO API however does not enforce usage of the same tool + for each step in the batch job life cycle. + + For example: if you prefer a graphical, web-based **interactive environment** + to manage and monitor your batch jobs, + feel free to *switch to an openEO web editor* + like `editor.openeo.org `_ + or `editor.openeo.cloud `_ + at any time. + After logging in with the same account you use in your Python scripts, + you should see your batch jobs listed under the "Data Processing" tab: + + .. image:: _static/images/batchjobs-webeditor-listing.png + + With the "action" buttons on the right, you can for example + inspect batch job details, start/stop/delete jobs, + download their results, get batch job logs, etc. + + + +.. index:: batch job; create + +Create a batch job +=================== + +In the openEO Python Client Library, if you have a (raster) data cube, you can easily +create a batch job with the :py:meth:`DataCube.create_job() ` method. +It's important to specify in what *format* the result should be stored, +which can be done with an explicit :py:meth:`DataCube.save_result() ` call before creating the job: + +.. code-block:: python + + cube = connection.load_collection(...) + ... + # Store raster data as GeoTIFF files + cube = cube.save_result(format="GTiff") + job = cube.create_job() + +or directly in :py:meth:`job.create_job() `: + +.. code-block:: python + + cube = connection.load_collection(...) + ... + job = cube.create_job(out_format="GTiff) + +While not necessary, it is also recommended to give your batch job a descriptive title +so it's easier to identify in your job listing, e.g.: + +.. code-block:: python + + job = cube.create_job(title="NDVI timeseries 2022") + + + +.. index:: batch job; object + +Batch job object +================= + +The ``job`` object returned by :py:meth:`~openeo.rest.datacube.DataCube.create_job()` +is a :py:class:`~openeo.rest.job.BatchJob` object. +It is basically a *client-side reference* to a batch job that *exists on the back-end* +and allows to interact with that batch job +(see the :py:class:`~openeo.rest.job.BatchJob` API docs for +available methods). + + +.. note:: + The :py:class:`~openeo.rest.job.BatchJob` class originally had + the more cryptic name :py:class:`~openeo.rest.job.RESTJob`, + which is still available as legacy alias, + but :py:class:`~openeo.rest.job.BatchJob` is (available and) recommended since version 0.11.0. + + +A batch job on a back-end is fully identified by its +:py:data:`~openeo.rest.job.BatchJob.job_id`: + +.. code-block:: pycon + + >>> job.job_id + 'd5b8b8f2-74ce-4c2e-b06d-bff6f9b14b8d' + + +Reconnecting to a batch job +---------------------------- + +Depending on your situation or use case: +make sure to properly take note of the batch job id. +It allows you to "reconnect" to your job on the back-end, +even if it was created at another time, +by another script/notebook or even with another openEO client. + +Given a back-end connection and the batch job id, +use :py:meth:`Connection.job() ` +to create a :py:class:`~openeo.rest.job.BatchJob` object for an existing batch job: + +.. code-block:: python + + job_id = "5d806224-fe79-4a54-be04-90757893795b" + job = connection.job(job_id) + + +Jupyter integration +-------------------- + +:py:class:`~openeo.rest.job.BatchJob` objects have basic Jupyter notebook integration. +Put your :py:class:`~openeo.rest.job.BatchJob` object as last statement +in a notebook cell and you get an overview of your batch jobs, +including job id, status, title and even process graph visualization: + +.. image:: _static/images/batchjobs-jupyter-created.png + + +.. index:: batch job; listing + +List your batch jobs +======================== + +You can list your batch jobs on the back-end with +:py:meth:`Connection.list_jobs() `, which returns a list of job metadata: + +.. code-block:: pycon + + >>> connection.list_jobs() + [{'title': 'NDVI timeseries 2022', 'status': 'created', 'id': 'd5b8b8f2-74ce-4c2e-b06d-bff6f9b14b8d', 'created': '2022-06-08T08:58:11Z'}, + {'title': 'NDVI timeseries 2021', 'status': 'finished', 'id': '4e720e70-88bd-40bc-92db-a366985ebd67', 'created': '2022-06-04T14:46:06Z'}, + ... + +The listing returned by :py:meth:`Connection.list_jobs() ` +has Jupyter notebook integration: + +.. image:: _static/images/batchjobs-jupyter-listing.png + + +.. index:: batch job; start + +Run a batch job +================= + +Starting a batch job is pretty straightforward with the +:py:meth:`~openeo.rest.job.BatchJob.start()` method: + +.. code-block:: python + + job.start() + +If this didn't raise any errors or exceptions your job +should now have started (status "running") +or be queued for processing (status "queued"). + + + +.. index:: batch job; status + +Wait for a batch job to finish +-------------------------------- + +A batch job typically takes some time to finish, +and you can check its status with the :py:meth:`~openeo.rest.job.BatchJob.status()` method: + +.. code-block:: pycon + + >>> job.status() + "running" + +The possible batch job status values, defined by the openEO API, are +"created", "queued", "running", "canceled", "finished" and "error". + +Usually, you can only reliably get results from your job, +as discussed in :ref:`batch_job_results`, +when it reaches status "finished". + + + +.. index:: batch job; polling loop + +Create, start and wait in one go +---------------------------------- + +You could, depending on your situation, manually check your job's status periodically +or set up a **polling loop** system to keep an eye on your job. +The openEO Python client library also provides helpers to do that for you. + +Working from an existing :py:class:`~openeo.rest.job.BatchJob` instance + + If you have a batch job that is already created as shown above, you can use + the :py:meth:`job.start_and_wait() ` method + to start it and periodically poll its status until it reaches status "finished" (or fails with status "error"). + Along the way it will print some progress messages. + + .. code-block:: pycon + + >>> job.start_and_wait() + 0:00:00 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': send 'start' + 0:00:36 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': queued (progress N/A) + 0:01:35 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': queued (progress N/A) + 0:02:19 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': running (progress N/A) + 0:02:50 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': running (progress N/A) + 0:03:28 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': finished (progress N/A) + + +Working from a :py:class:`~openeo.rest.datacube.DataCube` instance + + If you didn't create the batch job yet from a given :py:class:`~openeo.rest.datacube.DataCube` + you can do the job creation, starting and waiting in one go + with :py:meth:`cube.execute_batch() `: + + .. code-block:: pycon + + >>> job = cube.execute_batch() + 0:00:00 Job 'f9f4e3d3-bc13-441b-b76a-b7bfd3b59669': send 'start' + 0:00:23 Job 'f9f4e3d3-bc13-441b-b76a-b7bfd3b59669': queued (progress N/A) + ... + + Note that :py:meth:`cube.execute_batch() ` + returns a :py:class:`~openeo.rest.job.BatchJob` instance pointing to + the newly created batch job. + + +.. tip:: + + You can fine-tune the details of the polling loop (the poll frequency, + how the progress is printed, ...). + See :py:meth:`job.start_and_wait() ` + or :py:meth:`cube.execute_batch() ` + for more information. + + +.. index:: batch job; logs + + +Batch job logs +=============== + +Batch jobs in openEO have **logs** to help with *monitoring and debugging* batch jobs. +The back-end typically uses this to dump information during data processing +that may be relevant for the user (e.g. warnings, resource stats, ...). +Moreover, openEO processes like ``inspect`` allow users to log their own information. + +Batch job logs can be fetched with :py:meth:`job.logs() ` + +.. code-block:: pycon + + >>> job.logs() + [{'id': 'log001', 'level': 'info', 'message': 'Job started with 4 workers'}, + {'id': 'log002', 'level': 'debug', 'message': 'Loading 5x3x6 tiles'}, + {'id': 'log003', 'level': 'error', 'message': "Failed to load data cube: corrupt data for tile 'J9A7K2'."}, + ... + +In a Jupyter notebook environment, this also comes with Jupyter integration: + +.. image:: _static/images/batchjobs-jupyter-logs.png + + + +Automatic batch job log printing +--------------------------------- + +When using +:py:meth:`job.start_and_wait() ` +or :py:meth:`cube.execute_batch() ` +to run a batch job and it fails, +the openEO Python client library will automatically +print the batch job logs and instructions to help with further investigation: + +.. code-block:: pycon + + >>> job.start_and_wait() + 0:00:00 Job '68caccff-54ee-470f-abaa-559ed2d4e53c': send 'start' + 0:00:01 Job '68caccff-54ee-470f-abaa-559ed2d4e53c': running (progress N/A) + 0:00:07 Job '68caccff-54ee-470f-abaa-559ed2d4e53c': error (progress N/A) + + Your batch job '68caccff-54ee-470f-abaa-559ed2d4e53c' failed. + Logs can be inspected in an openEO (web) editor + or with `connection.job('68caccff-54ee-470f-abaa-559ed2d4e53c').logs()`. + + Printing logs: + [{'id': 'log001', 'level': 'info', 'message': 'Job started with 4 workers'}, + {'id': 'log002', 'level': 'debug', 'message': 'Loading 5x3x6 tiles'}, + {'id': 'log003', 'level': 'error', 'message': "Failed to load data cube: corrupt data for tile 'J9A7K2'."}] + + + +.. index:: batch job; results + +.. _batch_job_results: + +Download batch job results +========================== + +Once a batch job is finished you can get a handle to the results +(which can be a single file or multiple files) and metadata +with :py:meth:`~openeo.rest.job.BatchJob.get_results`: + +.. code-block:: pycon + + >>> results = job.get_results() + >>> results + + +The result metadata describes the spatio-temporal properties of the result +and is in fact a valid STAC item: + +.. code-block:: pycon + + >>> results.get_metadata() + { + 'bbox': [3.5, 51.0, 3.6, 51.1], + 'geometry': {'coordinates': [[[3.5, 51.0], [3.5, 51.1], [3.6, 51.1], [3.6, 51.0], [3.5, 51.0]]], 'type': 'Polygon'}, + 'assets': { + 'res001.tiff': { + 'href': 'https://openeo.example/download/432f3b3ef3a.tiff', + 'type': 'image/tiff; application=geotiff', + ... + 'res002.tiff': { + ... + + +Download all assets +-------------------- + +In the general case, when you have one or more result files (also called "assets"), +the easiest option to download them is +using :py:meth:`~openeo.rest.job.JobResults.download_files` (plural) +where you just specify a download folder +(otherwise the current working directory will be used by default): + +.. code-block:: python + + results.download_files("data/out") + +The resulting files will be named as they are advertised in the results metadata +(e.g. ``res001.tiff`` and ``res002.tiff`` in case of the metadata example above). + + +Download single asset +--------------------- + +If you know that there is just a single result file, you can also download it directly with +:py:meth:`~openeo.rest.job.JobResults.download_file` (singular) with the desired file name: + +.. code-block:: python + + results.download_file("data/out/result.tiff") + +This will fail however if there are multiple assets in the job result +(like in the metadata example above). +In that case you can still download a single by specifying which one you +want to download with the ``name`` argument: + +.. code-block:: python + + results.download_file("data/out/result.tiff", name="res002.tiff") + + +Fine-grained asset downloads +---------------------------- + +If you need a bit more control over which asset to download and how, +you can iterate over the result assets explicitly +and download these :py:class:`~openeo.rest.job.ResultAsset` instances +with :py:meth:`~openeo.rest.job.ResultAsset.download`, like this: + +.. code-block:: python + + for asset in results.get_assets(): + if asset.metadata["type"].startswith("image/tiff"): + asset.download("data/out/result-v2-" + asset.name) + + +Directly load batch job results +=============================== + +If you want to skip downloading an asset to disk, you can also load it directly. +For example, load a JSON asset with :py:meth:`~openeo.rest.job.ResultAsset.load_json`: + +.. code-block:: pycon + + >>> asset.metadata + {"type": "application/json", "href": "https://openeo.example/download/432f3b3ef3a.json"} + >>> data = asset.load_json() + >>> data + {"2021-02-24T10:59:23Z": [[3, 2, 5], [3, 4, 5]], ....} diff --git a/_sources/best_practices.rst.txt b/_sources/best_practices.rst.txt new file mode 100644 index 000000000..ac196f22d --- /dev/null +++ b/_sources/best_practices.rst.txt @@ -0,0 +1,93 @@ + +Best practices, coding style and general tips +=============================================== + +This is a collection of guidelines regarding best practices, +coding style and usage patterns for the openEO Python Client Library. + +It is in the first place an internal recommendation for openEO *developers* +to give documentation, code examples, demo's and tutorials +a *consistent* look and feel, +following common software engineering best practices. +Secondly, the wider audience of openEO *users* is also invited to pick up +a couple of tips and principles to improve their own code and scripts. + + +Background and inspiration +--------------------------- + +While some people consider coding style a personal choice or even irrelevant, +there are various reasons to settle on certain conventions. +Just the fact alone of following conventions +lowers the bar to get faster to the important details in someone else's code. +Apart from taste, there are also technical reasons to pick certain rules +to *streamline the programming workflow*, +not only for humans, +but also supporting tools (e.g. minimize risk on merge conflicts). + +While the Python language already has a strong focus on readability by design, +the Python community is strongly gravitating to even more strict conventions: + +- `pep8 `_: the mother of all Python code style guides +- `black `_: an opinionated code formatting tool + that gets more and more traction in popular, high profile projects. + +This openEO oriented style guide will highlight +and build on these recommendations. + + +General code style recommendations +------------------------------------ + +- Indentation with 4 spaces. +- Avoid star imports (``from module import *``). + While this seems like a quick way to import a bunch of functions/classes, + it makes it very hard for the reader to figure out where things come from. + It can also lead to strange bugs and behavior because it silently overwrites + references you previously imported. + + +Line (length) management +-------------------------- + +While desktop monitors offer plenty of (horizontal) space nowadays, +it is still a common recommendation to *avoid long source code lines*. +Not only are long lines hard to read and understand, +one should also consider that source code might still be viewed +on a small screen or tight viewport, +where scrolling horizontally is annoying or even impossible. +Unnecessarily long lines are also notorious +for not playing well with version control tools and workflows. + +Here are some guidelines on how to split long statements over multiple lines. + +Split long function/method calls directly after the opening parenthesis +and list arguments with a standard 4 space indentation +(not after the first argument with some ad-hoc indentation). +Put the closing parenthesis on its own line. + +.. code-block:: python + + # Avoid this: + s2_fapar = connection.load_collection("TERRASCOPE_S2_FAPAR_V2", + spatial_extent={'west': 16.138916, 'east': 16.524124, 'south': 48.1386, 'north': 48.320647}, + temporal_extent=["2020-05-01", "2020-05-20"]) + + # This is better: + s2_fapar = connection.load_collection( + "TERRASCOPE_S2_FAPAR_V2", + spatial_extent={'west': 16.138916, 'east': 16.524124, 'south': 48.1386, 'north': 48.320647}, + temporal_extent=["2020-05-01", "2020-05-20"], + ) + +.. TODO how to handle chained method calls + + + +Jupyter(lab) tips and tricks +------------------------------- + +- Add a cell with ``openeo.client_version()`` (e.g. just after importing all your libraries) + to keep track of which version of the openeo Python client library you used in your notebook. + +.. TODO how to work with "helper" modules? diff --git a/_sources/changelog.md.txt b/_sources/changelog.md.txt new file mode 100644 index 000000000..66efc0fec --- /dev/null +++ b/_sources/changelog.md.txt @@ -0,0 +1,2 @@ +```{include} ../CHANGELOG.md +``` diff --git a/_sources/configuration.rst.txt b/_sources/configuration.rst.txt new file mode 100644 index 000000000..c946376af --- /dev/null +++ b/_sources/configuration.rst.txt @@ -0,0 +1,95 @@ + +=============== +Configuration +=============== + +.. warning:: + Configuration files are an experimental feature + and some details are subject to change. + +.. versionadded:: 0.10.0 + + +.. _configuration_files: + +Configuration files +==================== + +Some functionality of the openEO Python client library can customized +through configuration files. + + +.. note:: + Note that these configuration files are different from the authentication secret/cache files + discussed at :ref:`auth_configuration_files`. + The latter are focussed on storing authentication secrets + and are mostly managed automatically. + The normal configuration files however should not contain secrets, + are usually edited manually, can be placed at various locations + and it is not uncommon to store them in version control where that makes sense. + + +Format +------- + +At the moment, only INI-style configs are supported. +This is a simple configuration format, easy to maintain +and it is supported out of the box in Python (without additional libraries). + +Example (note the use of sections and support for comments):: + + [General] + # Print loaded configuration file and default back-end URLs in interactive mode + verbose = auto + + [Connection] + default_backend = openeo.cloud + + +.. _configuration_file_locations: + +Location +--------- + +The following configuration locations are probed (in this order) for an existing configuration file. The first successful hit will be loaded: + +- the path in environment variable ``OPENEO_CLIENT_CONFIG`` if it is set (filename must end with extension ``.ini``) +- the file ``openeo-client-config.ini`` in the current working directory +- the file ``${OPENEO_CONFIG_HOME}/openeo-client-config.ini`` if the environment variable ``OPENEO_CONFIG_HOME`` is set +- the file ``${XDG_CONFIG_HOME}/openeo-python-client/openeo-client-config.ini`` if environment variable ``XDG_CONFIG_HOME`` is set +- the file ``.openeo-client-config.ini`` in the home folder of the user + + +Configuration options +---------------------- + +.. list-table:: + :widths: 10 10 40 + :header-rows: 1 + + * - Config Section + - Config + - Description and possible values + * - ``General`` + - ``verbose`` + - Verbosity mode when important config values are used: + + ``print``: always ``print()`` info + + ``auto`` (default): only ``print()`` when in an interactive context + + ``off``: don't print info + * - ``Connection`` + - ``default_backend`` + - Default back-end to connect to when :py:func:`openeo.connect()` + is used without explicit back-end URL. + Also see :ref:`default_url_and_auto_auth` + * - ``Connection`` + - ``default_backend.auto_authenticate`` + - Automatically authenticate in :py:func:`openeo.connect()` when using the ``default_backend`` config. Allowed values: + + ``basic`` for basic authentication + + ``oidc`` for OpenID Connect authentication + + ``off`` (default) for no authentication + Also see :ref:`default_url_and_auto_auth` + * - ``Connection`` + - ``auto_authenticate`` + - Automatically authenticate in :py:func:`openeo.connect()`. + Allowed values: see ``default_backend.auto_authenticate``. + Also see :ref:`default_url_and_auto_auth` diff --git a/_sources/cookbook/ard.rst.txt b/_sources/cookbook/ard.rst.txt new file mode 100644 index 000000000..908e2bb83 --- /dev/null +++ b/_sources/cookbook/ard.rst.txt @@ -0,0 +1,113 @@ +.. _ard: + +============================== +Analysis Ready Data generation +============================== + +For certain use cases, the preprocessed data collections available in the openEO back-ends are not sufficient or simply not +available. For that case, openEO supports a few very common preprocessing scenario: + +- Atmospheric correction of optical data +- SAR backscatter computation + +These processes also offer a number of parameters to customize the processing. There's also variants with a default +parametrization that results in data that is compliant with CEOS CARD4L specifications https://ceos.org/ard/. + +We should note that these operations can be computationally expensive, so certainly affect overall processing time and +cost of your final algorithm. Hence, make sure to make an informed decision when you decide to use these methods. + +Atmospheric correction +---------------------- + +The `atmospheric correction `_ process can apply a chosen +method on raw 'L1C' data. The supported methods and input datasets depend on the back-end, because not every method is +validated or works on any dataset, and different back-ends try to offer a variety of options. This gives you as a user +more options to run and compare different methods, and select the most suitable one for your case. + + +To perform an `atmospheric correction `_, the user has to +load an uncorrected L1C optical dataset. On the resulting datacube, the :func:`~openeo.rest.datacube.DataCube.atmospheric_correction` +method can be invoked. Note that it may not be possible to apply certain processes to the raw input data: preprocessing +algorithms can be tightly coupled with the raw data, making it hard or impossible for the back-end to perform operations +in between loading and correcting the data. + +The CARD4L variant of this process is: :func:`~openeo.rest.datacube.DataCube.ard_surface_reflectance`. This process follows +CEOS specifications, and thus can additional processing steps, like a BRDF correction, that are not yet available as a +separate process. + +Reference implementations +######################### + +This section shows a few working examples for these processes. + +EODC back-end +************* + +EODC (https://openeo.eodc.eu/v1.0) supports ard_surface_reflectance, based on the FORCE toolbox. (https://github.com/davidfrantz/force) + +Geotrellis back-end +******************* + +The geotrellis back-end (https://openeo.vito.be) supports :func:`~openeo.rest.datacube.DataCube.atmospheric_correction` with iCor and SMAC as methods. +The version of iCor only offers basic atmoshperic correction features, without special options for water products: https://remotesensing.vito.be/case/icor +SMAC is implemented based on: https://github.com/olivierhagolle/SMAC +Both methods have been tested with Sentinel-2 as input. The viewing and sun angles need to be selected by the user to make them +available for the algorithm. + +This is an example of applying iCor:: + + l1c = connection.load_collection("SENTINEL2_L1C_SENTINELHUB", + spatial_extent={'west':3.758216409030558,'east':4.087806252,'south':51.291835566,'north':51.3927399}, + temporal_extent=["2017-03-07","2017-03-07"],bands=['B04','B03','B02','B09','B8A','B11','sunAzimuthAngles','sunZenithAngles','viewAzimuthMean','viewZenithMean'] ) + l1c.atmospheric_correction(method="iCor").download("rgb-icor.geotiff",format="GTiff") + + +SAR backscatter +--------------- + +Data from synthetic aperture radar sensors requires significant preprocessing to be calibrated and normalized for terrain. +This is referred to as backscatter computation, and supported by +`sar_backscatter `_ and the CARD4L compliant variant +`ard_normalized_radar_backscatter `_ + +The user should load a datacube containing raw SAR data, such as Sentinel-1 GRD. On the resulting datacube, the +:func:`~openeo.rest.datacube.DataCube.sar_backscatter` method can be invoked. The CEOS CARD4L variant is: +:func:`~openeo.rest.datacube.DataCube.ard_normalized_radar_backscatter`. These processes are tightly coupled to +metadata from specific sensors, so it is not possible to apply other processes to the datacube first, +with the exception of specifying filters in space and time. + + +Reference implementations +######################### + +This section shows a few working examples for these processes. + +EODC back-end +************* + +EODC (https://openeo.eodc.eu/v1.0) supports sar_backscatter, based on the Sentinel-1 toolbox. (https://sentinel.esa.int/web/sentinel/toolboxes/sentinel-1) + +Geotrellis back-end +******************* + +When working with the Sentinelhub SENTINEL1_GRD collection, both sar processes can be used. The underlying implementation is +provided by Sentinelhub, (https://docs.sentinel-hub.com/api/latest/data/sentinel-1-grd/#processing-options), and offers full +CARD4L compliant processing options. + +This is an example of :func:`~openeo.rest.datacube.DataCube.ard_normalized_radar_backscatter`:: + + s1grd = (connection.load_collection('SENTINEL1_GRD', bands=['VH', 'VV']) + .filter_bbox(west=2.59003, east=2.8949, north=51.2206, south=51.069) + .filter_temporal(extent=["2019-10-10","2019-10-10"])) + + job = s1grd.ard_normalized_radar_backscatter().execute_batch() + + for asset in job.get_results().get_assets(): + asset.download() + +When working with other GRD data, an implementation based on Orfeo Toolbox is used: + +- `Orfeo docs `_ +- `Implementation `_ + +The Orfeo implementation currently only supports sigma0 computation, and is not CARD4L compliant. diff --git a/_sources/cookbook/index.rst.txt b/_sources/cookbook/index.rst.txt new file mode 100644 index 000000000..719d2049b --- /dev/null +++ b/_sources/cookbook/index.rst.txt @@ -0,0 +1,14 @@ +openEO CookBook +=============== + +.. toctree:: + :maxdepth: 3 + :caption: Contents: + + ard + sampling + udp_sharing + spectral_indices + job_manager + localprocessing + tricks diff --git a/_sources/cookbook/job_manager.rst.txt b/_sources/cookbook/job_manager.rst.txt new file mode 100644 index 000000000..6988ed2c5 --- /dev/null +++ b/_sources/cookbook/job_manager.rst.txt @@ -0,0 +1,9 @@ +==================================== +Multi Backend Job Manager +==================================== + +.. warning:: + This is a new experimental API, subject to change. + +.. automodule:: openeo.extra.job_management + :members: MultiBackendJobManager, ignore_connection_errors diff --git a/_sources/cookbook/localprocessing.rst.txt b/_sources/cookbook/localprocessing.rst.txt new file mode 100644 index 000000000..da39271c9 --- /dev/null +++ b/_sources/cookbook/localprocessing.rst.txt @@ -0,0 +1,180 @@ +=============================== +Client-side (local) processing +=============================== + +.. warning:: + This is a new experimental feature and API, subject to change. + +Background +---------- + +The client-side processing functionality allows to test and use openEO with its processes locally, i.e. without any connection to an openEO back-end. +It relies on the projects `openeo-pg-parser-networkx `_, which provides an openEO process graph parsing tool, and `openeo-processes-dask `_, which provides an Xarray and Dask implementation of most openEO processes. + +Installation +------------ + +.. note:: + This feature requires ``Python>=3.9``. + Tested with ``openeo-pg-parser-networkx==2023.5.1`` and + ``openeo-processes-dask==2023.7.1``. + +.. code:: bash + + pip install openeo[localprocessing] + +Usage +----- + +Every openEO process graph relies on data which is typically provided by a cloud infrastructure (the openEO back-end). +The client-side processing adds the possibility to read and use local netCDFs, geoTIFFs, ZARR files, and remote STAC Collections or Items for your experiments. + +STAC Collections and Items +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. warning:: + The provided examples using STAC rely on third party STAC Catalogs, we can't guarantee that the urls will remain valid. + +With the ``load_stac`` process it's possible to load and use data provided by remote or local STAC Collections or Items. +The following code snippet loads Sentinel-2 L2A data from a public STAC Catalog, using specific spatial and temporal extent, band name and also properties for cloud coverage. + +.. code-block:: pycon + + >>> from openeo.local import LocalConnection + >>> local_conn = LocalConnection("./") + + >>> url = "https://earth-search.aws.element84.com/v1/collections/sentinel-2-l2a" + >>> spatial_extent = {"west": 11, "east": 12, "south": 46, "north": 47} + >>> temporal_extent = ["2019-01-01", "2019-06-15"] + >>> bands = ["red"] + >>> properties = {"eo:cloud_cover": dict(lt=50)} + >>> s2_cube = local_conn.load_stac(url=url, + ... spatial_extent=spatial_extent, + ... temporal_extent=temporal_extent, + ... bands=bands, + ... properties=properties, + ... ) + >>> s2_cube.execute() + + dask.array + Coordinates: (12/53) + * time (time) datetime64[ns] 2019-01-02... + id (time) `_. + If the code can not handle you special netCDF, you can still modify the function that reads the metadata from it `here `_ and the function that reads the data `here `_. + +Local Processing +~~~~~~~~~~~~~~~~ + +Let's start with the provided sample netCDF of Sentinel-2 data: + +.. code-block:: pycon + + >>> local_collection = "openeo-localprocessing-data/sample_netcdf/S2_L2A_sample.nc" + >>> s2_datacube = local_conn.load_collection(local_collection) + >>> # Check if the data is loaded correctly + >>> s2_datacube.execute() + + dask.array + Coordinates: + * t (t) datetime64[ns] 2022-06-02 2022-06-05 ... 2022-06-27 2022-06-30 + * x (x) float64 6.75e+05 6.75e+05 6.75e+05 ... 6.843e+05 6.843e+05 + * y (y) float64 5.155e+06 5.155e+06 5.155e+06 ... 5.148e+06 5.148e+06 + crs |S1 ... + * bands (bands) object 'B04' 'B03' 'B02' 'B08' 'SCL' + Attributes: + Conventions: CF-1.9 + institution: openEO platform - Geotrellis backend: 0.9.5a1 + description: + title: + +As you can see in the previous example, we are using a call to execute() which will execute locally the generated openEO process graph. +In this case, the process graph consist only in a single load_collection, which performs lazy loading of the data. With this first step you can check if the data is being read correctly by openEO. + +Looking at the metadata of this netCDF sample, we can see that it contains the bands B04, B03, B02, B08 and SCL. +Additionally, we also see that it is composed by more than one element in time and that it covers the month of June 2022. + +We can now do a simple processing for demo purposes, let's compute the median NDVI in time and visualize the result: + +.. code:: python + + b04 = s2_datacube.band("B04") + b08 = s2_datacube.band("B08") + ndvi = (b08 - b04) / (b08 + b04) + ndvi_median = ndvi.reduce_dimension(dimension="t", reducer="median") + result_ndvi = ndvi_median.execute() + result_ndvi.plot.imshow(cmap="Greens") + +.. image:: ../_static/images/local/local_ndvi.jpg + +We can perform the same example using data provided by STAC Collection: + +.. code:: python + + from openeo.local import LocalConnection + local_conn = LocalConnection("./") + + url = "https://earth-search.aws.element84.com/v1/collections/sentinel-2-l2a" + spatial_extent = {"east": 11.40, "north": 46.52, "south": 46.46, "west": 11.25} + temporal_extent = ["2022-06-01", "2022-06-30"] + bands = ["red", "nir"] + properties = {"eo:cloud_cover": dict(lt=80)} + s2_datacube = local_conn.load_stac( + url=url, + spatial_extent=spatial_extent, + temporal_extent=temporal_extent, + bands=bands, + properties=properties, + ) + + b04 = s2_datacube.band("red") + b08 = s2_datacube.band("nir") + ndvi = (b08 - b04) / (b08 + b04) + ndvi_median = ndvi.reduce_dimension(dimension="time", reducer="median") + result_ndvi = ndvi_median.execute() diff --git a/_sources/cookbook/sampling.rst.txt b/_sources/cookbook/sampling.rst.txt new file mode 100644 index 000000000..a2262bac9 --- /dev/null +++ b/_sources/cookbook/sampling.rst.txt @@ -0,0 +1,60 @@ + +Dataset sampling +---------------- + +Tested on: + +- Terrascope +- Copernicus Dataspace Ecosystem + +A number of use cases do not require a full datacube to be computed, +but rather want to extract a result at specific locations. +Examples include extracting training data for model calibration, or computing the result for +areas where validation data is available. + +Sampling can be done for points or polygons: +- point extractions basically result in a 'vector cube', so can be exported into tabular formats. +- polygon extractions can be stored to an individual netCDF per polygon so in this case the output is a sparse raster cube. + +To indicate to openEO that we only want to compute the datacube for certain polygon features, we use the +:func:`~openeo.rest.datacube.DataCube.filter_spatial` method. + +Next to that, we will also indicate that we want to write multiple output files. This is more convenient, as we will +want to have one or more raster outputs per sampling feature, for convenient further processing. To do this, we set +the 'sample_by_feature' output format property, which is available for the netCDF and GTiff output formats. + +Combining all of this, results in the following sample code:: + + s2_bands = auth_connection.load_collection( + "TERRASCOPE_S2_TOC_V2", + bands=["B04"], + temporal_extent=["2020-05-01", "2020-06-01"], + ) + s2_bands = s2_bands.filter_spatial( + "https://artifactory.vgt.vito.be/testdata-public/parcels/test_10.geojson", + ) + job = s2_bands.create_job( + title="Sentinel2", + description="Sentinel-2 L2A bands", + out_format="netCDF", + sample_by_feature=True, + ) + +Sampling only works for batch jobs, because it results in multiple output files, which can not be conveniently transferred +in a synchronous call. + +Performance & scalability +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It's important to note that dataset sampling is not necessarily a cheap operation, since creation of a sparse datacube still +may require accessing a large number of raw EO assets. Backends of course can and should optimize to restrict processing +to a minimum, but the size of the required input datasets is often a determining factor for cost and performance rather +than the size of the output dataset. + +Sampling at scale +~~~~~~~~~~~~~~~~~ + +When doing large scale (e.g. continental) sampling, it is usually not possible or impractical to run it as a single openEO +batch job. The recommendation here is to apply a spatial grouping to your sampling locations, with a single group covering +an area of around 100x100km. The optimal size of a group may be backend dependant. Also remember that when working with +data in the UTM projection, you may want to avoid covering multiple UTM zones in a single group. diff --git a/_sources/cookbook/spectral_indices.rst.txt b/_sources/cookbook/spectral_indices.rst.txt new file mode 100644 index 000000000..21ebe849d --- /dev/null +++ b/_sources/cookbook/spectral_indices.rst.txt @@ -0,0 +1,88 @@ +==================================== +Spectral Indices +==================================== + +.. warning:: + This is a new experimental API, subject to change. + +``openeo.extra.spectral_indices`` is an auxiliary subpackage +to simplify the calculation of common spectral indices +used in various Earth observation applications (vegetation, water, urban etc.). +It leverages the spectral indices defined in the +`Awesome Spectral Indices `_ project +by `David Montero Loaiza `_. + +.. versionadded:: 0.9.1 + +Band mapping +============= + +The formulas provided by "Awesome Spectral Indices" are defined in terms of standardized variable names +like "B" for blue, "R" for red, "N" for near-infrared, "WV" for water vapour, etc. + +.. code-block:: json + + "NDVI": { + "formula": "(N - R)/(N + R)", + "long_name": "Normalized Difference Vegetation Index", + +Obviously, these formula variables have to be mapped properly to the band names of your cube. + +Automatic band mapping +----------------------- +In most simple cases, when there is enough collection metadata +to automatically detect the satellite platform (Sentinel2, Landsat8, ..) +and the original band names haven't been renamed, +this mapping will be handled automatically, e.g.: + +.. code-block:: python + :emphasize-lines: 2 + + cube = connection.load_collection("SENTINEL2_L2A", ...) + indices = compute_indices(cube, indices=["NDVI", "NDMI"]) + + + +.. _spectral_indices_manual_band_mapping: + +Manual band mapping +-------------------- + +In more complex cases, it might be necessary to specify some additional information to guide the band mapping. +If the band names follow the standard, but it's just the satellite platform can not be guessed +from the collection metadata, it is typically enough to specify the platform explicitly: + +.. code-block:: python + :emphasize-lines: 4 + + indices = compute_indices( + cube, + indices=["NDVI", "NDMI"], + platform="SENTINEL2", + ) + +Additionally, if the band names in your cube have been renamed, deviating from conventions, it is also +possible to explicitly specify the band name to spectral index variable name mapping: + +.. code-block:: python + :emphasize-lines: 4-8 + + indices = compute_indices( + cube, + indices=["NDVI", "NDMI"], + variable_map={ + "R": "S2-red", + "N": "S2-nir", + "S1": "S2-swir", + }, + ) + +.. versionadded:: 0.26.0 + Function arguments ``platform`` and ``variable_map`` to fine-tune the band mapping. + + +API +==== + +.. automodule:: openeo.extra.spectral_indices + :members: list_indices, compute_and_rescale_indices, append_and_rescale_indices, compute_indices, append_indices, compute_index, append_index diff --git a/_sources/cookbook/tricks.rst.txt b/_sources/cookbook/tricks.rst.txt new file mode 100644 index 000000000..4b9fb3fb2 --- /dev/null +++ b/_sources/cookbook/tricks.rst.txt @@ -0,0 +1,82 @@ +=============================== +Miscellaneous tips and tricks +=============================== + + +.. _process_graph_export: + +Export a process graph +----------------------- + +You can export the underlying process graph of +a :py:class:`~openeo.rest.datacube.DataCube`, :py:class:`~openeo.rest.vectorcube.VectorCube`, etc, +to a standardized JSON format, which allows interoperability with other openEO tools. + +For example, use :py:meth:`~openeo.rest.datacube.DataCube.print_json()` to directly print the JSON representation +in your interactive Jupyter or Python session: + +.. code-block:: pycon + + >>> dump = cube.print_json() + { + "process_graph": { + "loadcollection1": { + "process_id": "load_collection", + ... + +Or save it to a file, by getting the JSON representation first as a string +with :py:meth:`~openeo.rest.datacube.DataCube.to_json()`: + +.. code-block:: python + + # Export as JSON string + dump = cube.to_json() + + # Write to file in `pathlib` style + export_path = pathlib.Path("path/to/export.json") + export_path.write_text(dump, encoding="utf8") + + # Write to file in `open()` style + with open("path/to/export.json", encoding="utf8") as f: + f.write(dump) + + +.. warning:: + + Avoid using methods like :py:meth:`~openeo.rest.datacube.DataCube.flat_graph()`, + which are mainly intended for internal use. + Not only are these methods subject to change, they also lead to representations + with interoperability and reuse issues. + For example, naively printing or automatic (``repr``) rendering of + :py:meth:`~openeo.rest.datacube.DataCube.flat_graph()` output will roughly look like JSON, + but is in fact invalid: it uses single quotes (instead of double quotes) + and booleans values are title-case (instead of lower case). + + + + +Execute a process graph directly from raw JSON +----------------------------------------------- + +When you have a process graph in JSON format, as a string, a local file or a URL, +you can execute/download it without converting it do a DataCube first. +Just pass the string, path or URL directly to +:py:meth:`Connection.download() `, +:py:meth:`Connection.execute() ` or +:py:meth:`Connection.create_job() `. +For example: + +.. code-block:: python + + # `execute` with raw JSON string + connection.execute(""" + { + "add": {"process_id": "add", "arguments": {"x": 3, "y": 5}, "result": true} + } + """) + + # `download` with local path to JSON file + connection.download("path/to/my-process-graph.json") + + # `create_job` with URL to JSON file + job = connection.create_job("https://jsonbin.example/my/process-graph.json") diff --git a/_sources/cookbook/udp_sharing.rst.txt b/_sources/cookbook/udp_sharing.rst.txt new file mode 100644 index 000000000..a1cd8370d --- /dev/null +++ b/_sources/cookbook/udp_sharing.rst.txt @@ -0,0 +1,125 @@ +==================================== +Sharing of user-defined processes +==================================== + + +.. warning:: + Beta feature - + At the time of this writing (July 2021), sharing of :ref:`user-defined processes ` + (publicly or among users) is not standardized in the openEO API. + There are however some experimental sharing features in the openEO Python Client Library + and some back-end providers that we are going to discuss here. + + Be warned that the details of this feature are subject to change. + For more status information, consult GitHub ticket + `Open-EO/openeo-api#310 `_. + + + + +Publicly publishing a user-defined process. +============================================ + +As discussed in :ref:`build_and_store_udp`, user-defined processes can be +stored with the :py:meth:`~openeo.rest.connection.Connection.save_user_defined_process` method +on a on a back-end :py:class:`~openeo.rest.connection.Connection`. +By default, these user-defined processes are private and only accessible by the user that saved it:: + + from openeo.processes import subtract, divide + from openeo.api.process import Parameter + + # Build user-defined process + f = Parameter.number("f", description="Degrees Fahrenheit.") + fahrenheit_to_celsius = divide(x=subtract(x=f, y=32), y=1.8) + + # Store user-defined process in openEO back-end. + udp = connection.save_user_defined_process( + "fahrenheit_to_celsius", + fahrenheit_to_celsius, + parameters=[f] + ) + + +Some back-ends, like the VITO/Terrascope back-end allow a user to flag a user-defined process as "public" +so that other users can access its description and metadata:: + + udp = connection.save_user_defined_process( + ... + public=True + ) + +The sharable, public URL of this user-defined process is available from the metadata given by +:py:meth:`RESTUserDefinedProcess.describe `. +It's listed as "canonical" link:: + + >>> udp.describe() + { + "id": "fahrenheit_to_celsius", + "links": [ + { + "rel": "canonical", + "href": "https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius", + "title": "Public URL for user-defined process fahrenheit_to_celsius" + } + ], + ... + + +.. _udp_sharing_call_url_namespace: + +Using a public UDP through URL based "namespace" +================================================== + +Some back-ends, like the VITO/Terrascope back-end, allow to use a public UDP +through setting its public URL as the ``namespace`` property of the process graph node. + +For example, based on the ``fahrenheit_to_celsius`` UDP created above, +the "flat graph" representation of a process graph could look like this:: + + { + ... + "to_celsius": { + "process_id": "fahrenheit_to_celsius", + "namespace": "https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius", + "arguments": {"f": 86} + } + + +As a very basic illustration with the openEO Python Client library, +we can create and evaluate a process graph, +containing a ``fahrenheit_to_celsius`` call as single process, +with :meth:`Connection.datacube_from_process ` as follows:: + + cube = connection.datacube_from_process( + process_id="fahrenheit_to_celsius", + namespace="https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius", + f=86 + ) + print(cube.execute()) + # Prints: 30.0 + + +Loading a published user-defined process as DataCube +====================================================== + + +From the public URL of the user-defined process, +it is also possible for another user to construct, fully client-side, +a new :class:`~openeo.rest.datacube.DataCube` +with :meth:`Connection.datacube_from_json `. + +It is important to note that this approach is different from calling +a user-defined process as described in :ref:`evaluate_udp` and :ref:`udp_sharing_call_url_namespace`. +:meth:`Connection.datacube_from_json ` +breaks open the encapsulation of the user-defined process and "unrolls" the process graph inside +into a new :class:`~openeo.rest.datacube.DataCube`. +This also implies that parameters defined in the user-defined process have to be provided when calling +:meth:`Connection.datacube_from_json ` :: + + + udp_url = "https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius" + cube = connection.datacube_from_json(udp_url, parameters={"f": 86}) + print(cube.execute()) + # Prints: 30.0 + +For more information, also see :ref:`datacube_from_json`. diff --git a/_sources/data_access.rst.txt b/_sources/data_access.rst.txt new file mode 100644 index 000000000..952f91527 --- /dev/null +++ b/_sources/data_access.rst.txt @@ -0,0 +1,344 @@ +.. _data_access_chapter: + +######################## +Finding and loading data +######################## + + +As illustrated in the basic concepts, most openEO scripts start with ``load_collection``, but this skips the step of +actually finding out which collection to load. This section dives a bit deeper into finding the right data, and some more +advanced data loading use cases. + +Data discovery +============== + +To explore data in a given back-end, it is recommended to use a more visual tool like the openEO Hub +(http://hub.openeo.org/). This shows available collections, and metadata in a user-friendly manner. + +Next to that, the client also offers various :py:class:`~openeo.rest.connection.Connection` methods +to explore collections and their metadata: + +- :py:meth:`~openeo.rest.connection.Connection.list_collection_ids` + to list all collection ids provided by the back-end +- :py:meth:`~openeo.rest.connection.Connection.list_collections` + to list the basic metadata of all collections +- :py:meth:`~openeo.rest.connection.Connection.describe_collection` + to get the complete metadata of a particular collection + +When using these methods inside a Jupyter notebook, you should notice that the output is rendered in a user friendly way. + +In a regular script, these methods can be used to programmatically find a collection that matches specific criteria. + +As a user, make sure to carefully read the documentation for a given collection, as there can be important differences. +You should also be aware of the data retention policy of a given collection: some data archives only retain the last 3 months +for instance, making them only suitable for specific types of analysis. Such differences can have an impact on the reproducibility +of your openEO scripts. + +Also note that the openEO metadata may use links to point to much more information for a particular collection. For instance +technical specification on how the data was preprocessed, or viewers that allow you to visually explore the data. This can +drastically improve your understanding of the dataset. + +Finally, licensing information is important to keep an eye on: not all data is free and open. + + +Initial exploration of an openEO collection +------------------------------------------- + +A common question from users is about very specific details of a collection, we'd like to list some examples and solutions here: + +- The collection data type, and range of values, can be determined by simply downloading a sample of data, as NetCDF or Geotiff. This can in fact be done at any point in the design of your script, to get a good idea of intermediate results. +- Data availability, and available timestamps can be retrieved by computing average values for your area of interest. Just construct a polygon, and retrieve those statistics. For optical data, this can also be used to get an idea on cloud statistics. +- Most collections have a native projection system, again a simple download will give you this information if its not clear from the metadata. + +.. _data-loading-and-filtering: + +Loading a data cube from a collection +===================================== + +Many examples already illustrate the basic openEO ``load_collection`` process through a :py:meth:`Connection.load_collection() ` call, +with filters on space, time and bands. +For example: + +.. code-block:: python + + cube = connection.load_collection( + "SENTINEL2_L2A", + spatial_extent={"west": 3.75, "east": 4.08, "south": 51.29, "north": 51.39}, + temporal_extent=["2021-05-07", "2021-05-14"], + bands=["B04", "B03", "B02"], + ) + + +The purpose of these filters in ``load_collection`` is to reduce the amount of raw data that is loaded (and processed) by the back-end. +This is essential to get a response to your processing request in reasonable time and keep processing costs low. +It's recommended to start initial exploration with a small spatio-temporal extent +and gradually increase the scope once initial tests work out. + +Next to specifying filters inside the ``load_collection`` process, +there are also possibilities to filter with separate filter processes, e.g. at a later stage in your process graph. +For most openEO back-ends, the following example snippet should be equivalent to the previous: + +.. code-block:: python + + cube = connection.load_collection("SENTINEL2_L2A") + cube = cube.filter_bbox(west=3.75, east=4.08, south=51.29, north=51.39) + cube = cube.filter_temporal("2021-05-07", "2021-05-14") + cube = cube.filter_bands(["B04", "B03", "B02"]) + + +Another nice feature is that processes that work with geometries or vector features +(e.g. aggregated statistics for a polygon, or masking by polygon) +can also be used by a back-end to automatically infer an appropriate spatial extent. +This way, you do not need to explicitly set these filters yourself. + +In the following sections, we want to dive a bit into details, and more advanced cases. + + +Filter on spatial extent +======================== + +A spatial extent is a bounding box that specifies the minimum and and maximum longitude and latitude of the region of interest you want to process. + +By default these latitude and longitude values are expressed in the standard Coordinate Reference System for the world, which is EPSG:4623, also known as "WGS 84", or just "lat-long". + +.. code-block:: python + + connection.load_collection( + ..., + spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19}, + ) + +.. _filtering-on-temporal-extent-section: + +Filter on temporal extent +========================= + +Usually you don't need the complete time range provided by a collection +and you should specify an appropriate time window to load +as a ``temporal_extent`` pair containing a start and end date: + +.. code-block:: python + + connection.load_collection( + ..., + temporal_extent=["2021-05-07", "2021-05-14"], + ) + +In most use cases, day-level granularity is enough and you can just express the dates as strings in the format ``"yyyy-mm-dd"``. +You can also pass ``datetime.date`` objects (from Python standard library) if you already have your dates in that format. + +.. note:: + When you need finer, time-level granularity, you can pass ``datetime.datetime`` objects. + Or, when passed as a string, the openEO API requires date and time to be provided in RFC 3339 format. + For example for for 2020-03-17 at 12:34:56 in UTC:: + + "2020-03-17T12:34:56Z" + + + +.. _left-closed-temporal-extent: + +Left-closed intervals: start included, end excluded +--------------------------------------------------- + +Time ranges in openEO processes like ``load_collection`` and ``filter_temporal`` are handled as left-closed ("half-open") temporal intervals: +the start instant is included in the interval, but the end instant is excluded from the interval. + +For example, the interval defined by ``["2020-03-05", "2020-03-15"]`` covers observations +from 2020-03-05 up to (and including) 2020-03-14 (just before midnight), +but does not include observations from 2020-03-15. + +.. TODO: nicer diagram instead of this ASCII art +.. code-block:: text + + 2020-03-05 2020-03-14 2022-03-15 + ________|____________|_________________________|____________|____________|_____ + + [--------------------------------------------------(O + including excluding + 2020-03-05 00:00:00.000 2020-03-15 00:00:00.000 + + +While this might look unintuitive at first, +working with half-open intervals avoids common and hard to discover pitfalls when combining multiple intervals, +like unintended window overlaps or double counting observations at interval borders. + +.. _date-shorthand-handling: + +Year/month shorthand notation +------------------------------ + +.. note:: + + Year/month shorthand notation handling is available since version 0.23.0. + +Rounding down periods to dates +`````````````````````````````` + +The openEO Python Client Library supports some shorthand notations for the temporal extent, +which come in handy if you work with year/month based temporal intervals. +Date strings that only consist of a year or a month will be automatically +"rounded down" to the first day of that period. For example:: + + "2023" -> "2023-01-01" + "2023-08" -> "2023-08-01" + +This approach fits best with :ref:`left-closed interval handling `. + +For example, the following two ``load_collection`` calls are equivalent: + +.. code-block:: python + + # Filter for observations in 2021 (left-closed interval). + connection.load_collection(temporal_extent=["2021", "2022"], ...) + # The above is shorthand for: + connection.load_collection(temporal_extent=["2021-01-01", "2022-01-01"], ...) + +The same applies for :py:meth:`~openeo.rest.datacube.DataCube.filter_temporal()`, +which has a couple of additional call forms. +All these calls are equivalent: + +.. code-block:: python + + # Filter for March, April and May (left-closed interval) + cube = cube.filter_temporal("2021-03", "2021-06") + cube = cube.filter_temporal(["2021-03", "2021-06"]) + cube = cube.filter_temporal(start_date="2021-03", end_date="2021-06") + cube = cube.filter_temporal(extent=("2021-03", "2021-06")) + + # The above are shorthand for: + cube = cube.filter_temporal("2021-03-01", "2022-06-01") + +.. _single-string-temporal-extents: + +Single string temporal extents +`````````````````````````````` + +Apart from rounding down year or month string, the openEO Python Client Library provides an additional +``extent`` handling feature in methods like +:py:meth:`Connection.load_collection(temporal_extent=...) ` +and :py:meth:`DataCube.filter_temporal(extent=...) `. +Normally, the ``extent`` argument should be a list or tuple containing start and end date, +but if a single string is given, representing a year, month (or day) period, +it is automatically expanded to the appropriate interval, +again following the :ref:`left-closed interval principle `. +For example:: + + extent="2022" -> extent=("2022-01-01", "2023-01-01") + extent="2022-05" -> extent=("2022-05-01", "2022-06-01") + extent="2022-05-17" -> extent=("2022-05-17", "2022-05-18") + + +The following snippet shows some examples of equivalent calls: + +.. code-block:: python + + connection.load_collection(temporal_extent="2022", ...) + # The above is shorthand for: + connection.load_collection(temporal_extent=("2022-01-01", "2023-01-01"), ...) + + + cube = cube.filter_temporal(extent="2021-03") + # The above are shorthand for: + cube = cube.filter_temporal(extent=("2021-03-01", "2022-04-01")) + + +Filter on collection properties +=============================== + +Although openEO presents data in a data cube, a lot of collections are still backed by a product based catalog. This +allows filtering on properties of that catalog. + +A very common use case is to pre-filter Sentinel-2 products on cloud cover. +This avoids loading clouded data unnecessarily and increases performance. +:py:meth:`Connection.load_collection() ` provides +a dedicated ``max_cloud_cover`` argument (shortcut for the ``eo:cloud_cover`` property) for that: + +.. code-block:: python + :emphasize-lines: 4 + + connection.load_collection( + "SENTINEL2_L2A", + ..., + max_cloud_cover=80, + ) + +For more general cases, you can use the ``properties`` argument to filter on any collection property. +For example, to filter on the relative orbit number of SAR data: + +.. code-block:: python + :emphasize-lines: 4-6 + + connection.load_collection( + "SENTINEL1_GRD", + ..., + properties={ + "relativeOrbitNumber": lambda x: x==116 + }, + ) + +Version 0.26.0 of the openEO Python Client Library adds +:py:func:`~openeo.rest.graph_building.collection_property` +which makes defining such property filters more user-friendly by avoiding the ``lambda`` construct: + +.. code-block:: python + :emphasize-lines: 6-8 + + import openeo + + connection.load_collection( + "SENTINEL1_GRD", + ..., + properties=[ + openeo.collection_property("relativeOrbitNumber") == 116, + ], + ) + +Note that property names follow STAC metadata conventions, but some collections can have different names. + +Property filters in openEO are also specified by small process graphs, that allow the use of the same generic processes +defined by openEO. This is the 'lambda' process that you see in the property dictionary. Do note that not all processes +make sense for product filtering, and can not always be properly translated into the query language of the catalog. +Hence, some experimentation may be needed to find a filter that works. + +One important caveat in this example is that 'relativeOrbitNumber' is a catalog specific property name. Meaning that +different archives may choose a different name for a given property, and the properties that are available can depend +on the collection and the catalog that is used by it. This is not a problem caused by openEO, but by the limited +standardization between catalogs of EO data. + + +Handling large vector data sets +=============================== + +For simple use cases, it is common to directly embed geometries (vector data) in your openEO process graph. +Unfortunately, with large vector data sets this leads to very large process graphs +and you might hit certain limits, +resulting in HTTP errors like ``413 Request Entity Too Large`` or ``413 Payload Too Large``. + +This problem can be circumvented by first uploading your vector data to a file sharing service +(like Google Drive, DropBox, GitHub, ...) +and use its public URL in the process graph instead +through :py:meth:`Connection.vectorcube_from_paths `. +For example, as follows: + +.. code-block:: python + + # Load vector data from URL + url = "https://github.com/Open-EO/openeo-python-client/raw/master/tests/data/example_aoi.pq" + parcels = connection.vectorcube_from_paths([url], format="parquet") + + # Use the parcel vector data, for example to do aggregation. + cube = connection.load_collection( + "SENTINEL2_L2A", + bands=["B04", "B03", "B02"], + temporal_extent=["2021-05-12", "2021-06-01"], + ) + aggregations = cube.aggregate_spatial( + geometries=parcels, + reducer="mean", + ) + +Note that while openEO back-ends typically support multiple vector formats, like GeoJSON and GeoParquet, +it is usually recommended to use a compact format like GeoParquet, instead of GeoJSON. The list of supported formats +is also advertised by the backend, and can be queried with +:py:meth:`Connection.list_file_formats `. diff --git a/_sources/datacube_construction.rst.txt b/_sources/datacube_construction.rst.txt new file mode 100644 index 000000000..6ac9e4489 --- /dev/null +++ b/_sources/datacube_construction.rst.txt @@ -0,0 +1,178 @@ + +======================= +DataCube construction +======================= + + +The ``load_collection`` process +================================= + +The most straightforward way to start building your openEO data cube is through the ``load_collection`` process. +As mentioned earlier, this is provided by the +:meth:`~openeo.rest.connection.Connection.load_collection` method +on a :class:`~openeo.rest.connection.Connection` object, +which produces a :class:`~openeo.rest.datacube.DataCube` instance. +For example:: + + cube = connection.load_collection("SENTINEL2_TOC") + +While this should cover the majority of use cases, +there some cases +where one wants to build a :class:`~openeo.rest.datacube.DataCube` object +from something else or something more than just a simple ``load_collection`` process. + + + +.. _datacube_from_process: + +Construct DataCube from process +================================= + +Through :ref:`user-defined processes ` one can encapsulate +one or more ``load_collection`` processes and additional processing steps in a single +reusable user-defined process. +For example, imagine a user-defined process "masked_s2" +that loads an openEO collection "SENTINEL2_TOC" and applies some kind of cloud masking. +The implementation details of the cloud masking are not important here, +but let's assume there is a parameter "dilation" to fine-tune the cloud mask. +Also note that the collection id "SENTINEL2_TOC" is hardcoded in the user-defined process. + +We can now construct a data cube from this user-defined process +with :meth:`~openeo.rest.connection.Connection.datacube_from_process` +as follows:: + + cube = connection.datacube_from_process("masked_s2", dilation=10) + + # Further processing of the cube: + cube = cube.filter_temporal("2020-09-01", "2020-09-10") + + +Note that :meth:`~openeo.rest.connection.Connection.datacube_from_process` can be +used with all kind of processes, not only user-defined processes. +For example, while this is not exactly a real EO data use case, +it will produce a valid openEO process graph that can be executed:: + + >>> cube = connection.datacube_from_process("mean", data=[2, 3, 5, 8]) + >>> cube.execute() + 4.5 + + + +.. _datacube_from_json: + +Construct DataCube from JSON +============================== + +openEO process graphs are typically stored and published in JSON format. +Most notably, user-defined processes are transferred between openEO client +and back-end in a JSON structure roughly like in this example:: + + { + "id": "evi", + "parameters": [ + {"name": "red", "schema": {"type": "number"}}, + {"name": "blue", "schema": {"type": "number"}}, + ... + ], + "process_graph": { + "sub": {"process_id": "subtract", "arguments": {"x": {"from_parameter": "nir"}, "y": {"from_parameter": "red"}}}, + "p1": {"process_id": "multiply", "arguments": {"x": 6, "y": {"from_parameter": "red"}}}, + "div": {"process_id": "divide", "arguments": {"x": {"from_node": "sub"}, "y": {"from_node": "sum"}}, + ... + + +It is possible to construct a :class:`~openeo.rest.datacube.DataCube` object that corresponds with this +process graph with the :meth:`Connection.datacube_from_json ` method. +It can be given one of: + + - a raw JSON string, + - a path to a local JSON file, + - an URL that points to a JSON resource + +The JSON structure should be one of: + + - a mapping (dictionary) like the example above with at least a ``"process_graph"`` item, + and optionally a ``"parameters"`` item. + - a mapping (dictionary) with ``{"process_id": ...}`` items + + +Some examples +--------------- + +Load a :class:`~openeo.rest.datacube.DataCube` from a raw JSON string, containing a +simple "flat graph" representation:: + + raw_json = '''{ + "lc": {"process_id": "load_collection", "arguments": {"id": "SENTINEL2_TOC"}}, + "ak": {"process_id": "apply_kernel", "arguments": {"data": {"from_node": "lc"}, "kernel": [[1,2,1],[2,5,2],[1,2,1]]}, "result": true} + }''' + cube = connection.datacube_from_json(raw_json) + +Load from a raw JSON string, containing a mapping with "process_graph" and "parameters":: + + raw_json = '''{ + "parameters": [ + {"name": "kernel", "schema": {"type": "array"}, "default": [[1,2,1], [2,5,2], [1,2,1]]} + ], + "process_graph": { + "lc": {"process_id": "load_collection", "arguments": {"id": "SENTINEL2_TOC"}}, + "ak": {"process_id": "apply_kernel", "arguments": {"data": {"from_node": "lc"}, "kernel": {"from_parameter": "kernel"}}, "result": true} + } + }''' + cube = connection.datacube_from_json(raw_json) + +Load directly from a file or URL containing these kind of JSON representations:: + + cube = connection.datacube_from_json("path/to/my_udp.json") + + cube = connection.datacube_from_json("https://openeo.example/process_graphs/my_udp") + + +Parameterization +----------------- + +When the process graph uses parameters, you must specify the desired parameter values +at the time of calling :meth:`Connection.datacube_from_json `. + +For example, take this simple toy example of a process graph that takes the sum of 5 and a parameter "increment":: + + raw_json = '''{"add": { + "process_id": "add", + "arguments": {"x": 5, "y": {"from_parameter": "increment"}}, + "result": true + }}''' + +Trying to build a :class:`~openeo.rest.datacube.DataCube` from it without specifying parameter values will fail +like this:: + + >>> cube = connection.datacube_from_json(raw_json) + ProcessGraphVisitException: No substitution value for parameter 'increment'. + +Instead, specify the parameter value:: + + >>> cube = connection.datacube_from_json(raw_json, parameters={"increment": 4}) + >>> cube.execute() + 9 + + +Parameters can also be defined with default values, which will be used when they are not specified +in the :meth:`Connection.datacube_from_json ` call:: + + raw_json = '''{ + "parameters": [ + {"name": "increment", "schema": {"type": "number"}, "default": 100} + ], + "process_graph": { + "add": {"process_id": "add", "arguments": {"x": 5, "y": {"from_parameter": "increment"}}, "result": true} + } + }''' + + cube = connection.datacube_from_json(raw_json) + result = cube.execute()) + # result will be 105 + + +Re-parameterization +``````````````````` + +TODO diff --git a/_sources/development.rst.txt b/_sources/development.rst.txt new file mode 100644 index 000000000..943256b00 --- /dev/null +++ b/_sources/development.rst.txt @@ -0,0 +1,419 @@ +.. _development-and-maintenance: + +########################### +Development and maintenance +########################### + + +For development on the ``openeo`` package itself, +it is recommended to install a local git checkout of the project +in development mode (``-e``) +with additional development related dependencies (``[dev]``) +like this:: + + pip install -e .[dev] + +If you are on Windows and experience problems installing this way, you can find some solutions in section `Development Installation on Windows`_. + +Running the unit tests +====================== + +The test suite of the openEO Python Client leverages +the nice `pytest `_ framework. +It is installed automatically when installing the openEO Python Client +with the ``[dev]`` extra as shown above. +Running the whole tests is as simple as executing:: + + pytest + +There are a ton of command line options for fine-tuning +(e.g. select a subset of tests, how results should be reported, ...). +Run ``pytest -h`` for a quick overview +or check the `pytest `_ documentation for more information. + +For example:: + + # Skip tests that are marked as slow + pytest -m "not slow" + + +Building the documentation +========================== + +Building the documentation requires `Sphinx `_ +and some plugins +(which are installed automatically as part of the ``[dev]`` install). + +Quick and easy +--------------- + +The easiest way to build the documentation is working from the ``docs`` folder +and using the ``Makefile``: + +.. code-block:: shell + + # From `docs` folder + make html + +(assumes you have ``make`` available, if not: use ``python -msphinx -M html . _build``.) + +This will generate the docs in HTML format under ``docs/_build/html/``. +Open the HTML files manually, +or use Python's built-in web server to host them locally, e.g.: + +.. code-block:: shell + + # From `docs` folder + python -m http.server 8000 + +Then, visit http://127.0.0.1:8000/_build/html/ in your browser + + +Like a Pro +------------ + +When doing larger documentation work, it can be tedious to manually rebuild the docs +and refresh your browser to check the result. +Instead, use `sphinx-autobuild `_ +to automatically rebuild on documentation changes and live-reload it in your browser. +After installation (``pip install sphinx-autobuild`` in your development environment), +just run + +.. code-block:: shell + + # From project root + sphinx-autobuild docs/ --watch openeo/ docs/_build/html/ + +and then visit http://127.0.0.1:8000 . +When you change (and save) documentation source files, your browser should now +automatically refresh and show the newly built docs. Just like magic. + + +Contributing code +================== + +User contributions (such as bug fixes and new features, both in source code and documentation) +are greatly appreciated and welcome. + + +Pull requests +-------------- + +We use a traditional `GitHub Pull Request (PR) `_ workflow +for user contributions, which roughly follows these steps: + +- Create a personal fork of https://github.com/Open-EO/openeo-python-client + (unless you already have push permissions to an existing fork or the original repo) +- Preferably: work on your contribution in a new feature branch +- Push your feature branch to your fork and create a pull request +- The pull request is the place for review, discussion and fine-tuning of your work +- Once your pull request is in good shape it will be merged by a maintainer + + +.. _precommit: + +Pre-commit for basic code quality checks +------------------------------------------ + +We started using the `pre-commit `_ tool +for basic fine-tuning of code style and quality in new contributions. +It's currently not enforced, but **enabling pre-commit is recommended** and appreciated +when contributing code. + +.. note:: + + Note that the whole repository does not fully follow all code styles rules at the moment. + We're just gradually introducing it, piggybacking on new contributions and commits. + + +Pre-commit set up +"""""""""""""""""" + +- Install the general ``pre-commit`` command line tool: + + - The simplest option is to install it directly in the *virtual environment* + you are using for openEO Python client development (e.g. ``pip install pre-commit``). + - You can also install it *globally* on your system + (e.g. using `pipx `_, conda, homebrew, ...) + so you can use it across different projects. + +- Install the project specific git hook scripts by running this in the root of your local git clone: + + .. code-block:: console + + pre-commit install + + This will automatically install additional scripts and tools in a sandbox + to run the various checks defined in the project's ``.pre-commit-config.yaml`` configuration file. + +Pre-commit usage +""""""""""""""""" + +When you commit new changes, the freshly installed pre-commit hook +will now automatically run each of the configured linters/formatters/... +Some of these just flag issues (e.g. invalid JSON files) +while others even automatically fix problems (e.g. clean up excessive whitespace). + +If there is some kind of violation, the commit will be blocked. +Address these problems and try to commit again. + +.. attention:: + + Some pre-commit tools directly *edit* your files (e.g. formatting tweaks) + instead of just flagging issues. + This might feel intrusive at first, but once you get the hang of it, + it should allow to streamline your workflow. + + In particular, it is recommended to use the *staging* feature of git to prepare your commit. + Pre-commit's proposed changes are not staged automatically, + so you can more easily keep them separate and review. + +.. tip:: + + You can temporarily disable pre-commit for these rare cases + where you intentionally want to commit violating code style, + e.g. through ``git commit`` command line option ``-n``/``--no-verify``. + + + + +Creating a release +================== + +This section describes the procedure to create +properly versioned releases of the ``openeo`` package +that can be downloaded by end users (e.g. through ``pip`` from pypi.org) +and depended on by other projects. + +The releases will end up on: + +- PyPi: `https://pypi.org/project/openeo `_ +- VITO Artifactory: `https://artifactory.vgt.vito.be/api/pypi/python-openeo/simple/openeo/ `_ +- GitHub: `https://github.com/Open-EO/openeo-python-client/releases `_ + +Prerequisites +------------- + +- You have permissions to push branches and tags and maintain releases on + the `openeo-python-client project on GitHub `_. +- You have permissions to upload releases to the + `openeo project on pypi.org `_ +- The Python virtual environment you work in has the latest versions + of the ``twine`` package installed. + If you plan to build the wheel yourself (instead of letting GitHub or Jenkins do this), + you also need recent enough versions of the ``setuptools`` and ``wheel`` packages. + +Important files +--------------- + +``setup.py`` + describes the metadata of the package, + like package name ``openeo`` and version + (which is extracted from ``openeo/_version.py``). + +``openeo/_version.py`` + defines the version of the package. + During general **development**, this version string should contain + a `pre-release `_ + segment (e.g. ``a1`` for alpha releases, ``b1`` for beta releases, etc) + to avoid collision with final releases. For example:: + + __version__ = '0.8.0a1' + + As discussed below, this pre-release suffix should + only be removed during the release procedure + and restored when bumping the version after the release procedure. + +``CHANGELOG.md`` + keeps track of important changes associated with each release. + It follows the `Keep a Changelog `_ convention + and should be properly updated with each bug fix, feature addition/removal, ... + under the ``Unreleased`` section during development. + +Procedure +--------- + +These are the steps to create and publish a new release of the ``openeo`` package. +To avoid the confusion with ad-hoc injection of some abstract version placeholder +that has to be replaced properly, +we will use a concrete version ``0.8.0`` in the examples below. + +0. Make sure you are working on **latest master branch**, + without uncommitted changes and all tests are properly passing. + +#. Create release commit: + + A. **Drop the pre-release suffix** from the version string in ``openeo/_version.py`` + so that it just a "final" semantic versioning string, e.g. ``0.8.0`` + + B. **Update CHANGELOG.md**: rename the "Unreleased" section title + to contain version and date, e.g.:: + + ## [0.8.0] - 2020-12-15 + + remove empty subsections + and start a new "Unreleased" section above it, like:: + + ## [Unreleased] + + ### Added + + ### Changed + + ### Removed + + ### Fixed + + + C. **Commit** these changes in git with a commit message like ``Release 0.8.0`` + and **push** to GitHub:: + + git add openeo/_version.py CHANGELOG.md + git commit -m 'Release 0.8.0' + git push origin master + +#. Optional, but recommended: wait for **VITO Jenkins** to build this updated master + (trigger it manually if necessary), + so that a build of a final, non-alpha release ``0.8.0`` + is properly uploaded to **VITO artifactory**. + +#. Create release on `PyPI `_: + + A. **Obtain a wheel archive** of the package, with one of these approaches: + + - *Preferably, the path of least surprise*: build wheel through GitHub Actions. + Go to workflow `"Build wheel" `_, + manually trigger a build with "Run workflow" button, wait for it to finish successfully, + download generated ``artifact.zip``, and finally: unzip it to obtain ``openeo-0.8.0-py3-none-any.whl`` + + - *Or, if you know what you are doing* and you're sure you have a clean + local checkout, you can also build it locally:: + + python setup.py bdist_wheel + + This should create ``dist/openeo-0.8.0-py3-none-any.whl`` + + B. **Upload** this wheel to `PyPI `_:: + + python -m twine upload openeo-0.8.0-py3-none-any.whl + + Check the `release history on PyPI `_ + to verify the twine upload. + Another way to verify that the freshly created release installs + is using docker to do a quick install-and-burn, + for example as follows (check the installed version in pip's output):: + + docker run --rm -it python python -m pip install --no-deps openeo + +#. Create a **git version tag** and push it to GitHub:: + + git tag v0.8.0 + git push origin v0.8.0 + +#. Create a **release in GitHub**: + Go to `https://github.com/Open-EO/openeo-python-client/releases/new `_, + Enter ``v0.8.0`` under "tag", + enter title: ``openEO Python Client v0.8.0``, + use the corresponding ``CHANGELOG.md`` section as description + and publish it + (no need to attach binaries). + +#. **Bump the version** in ``openeo/_version.py``, (usually the "minor" level) + and append a pre-release "a1" suffix again, for example:: + + __version__ = '0.9.0a1' + + Commit this (e.g. with message ``_version.py: bump to 0.9.0a1``) + and push to GitHub. + +#. Update `conda-forge package `_ too + (requires conda recipe maintainer role). + Normally, the "regro-cf-autotick-bot" will create a `pull request `_. + If it builds fine, merge it. + If not, fix the issue + (typically in `recipe/meta.yaml `_) + and merge. + +#. Optionally: send a tweet about the release + or announce it in the `openEO Platform Forum `_. + +Verification +""""""""""""" + +The new release should now be available/listed at: + +- `https://pypi.org/project/openeo/#history `_ +- `https://github.com/Open-EO/openeo-python-client/releases `_ + +Here is a bash (subshell) oneliner to verify that the PyPI release works properly:: + + ( + cd /tmp &&\ + python -m venv venv-openeo &&\ + source venv-openeo/bin/activate &&\ + pip install -U openeo &&\ + python -c "import openeo;print(openeo);print(openeo.__version__)" + ) + +It tries to install the latest version of the ``openeo`` package in a temporary virtual env, +import it and print the package version. + + +Development Installation on Windows +=================================== + +Normally you can install the client the same way on Windows as on Linux, like so: + +.. code-block:: console + + pip install -e .[dev] + +Alternative development installation +------------------------------------- + +The standard pure-``pip`` based installation should work with the most recent code. +However, in the past we sometimes had issues with this procedure. +Should you experience problems, consider using an alternative conda-based installation procedure: + +1. Create and activate a new conda environment for developing the openeo-python-client. + For example: + + .. code-block:: console + + conda create -n openeopyclient + conda activate openeopyclient + +2. In that conda environment, install only the dependencies of ``openeo`` via conda, + but not the ``openeo`` package itself. + + .. code-block:: console + + # Install openeo dependencies (from the conda-forge channel) + conda install --only-deps -c conda-forge openeo + +3. Do a ``pip install`` from the project root in *editable mode* (``pip -e``): + + .. code-block:: console + + pip install -e .[dev] + + + +Update of generated files +========================== + +Some parts of the openEO Python Client Library source code are +generated/compiled from upstream sources (e.g. official openEO specifications). +Because updates are not often required, +it's just a semi-manual procedure (to run from the project root): + +.. code-block:: console + + # Update the sub-repositories (like git submodules, but optional) + python specs/update-subrepos.py + + # Update `openeo/processes.py` from specifications in openeo-processes repository + python openeo/internal/processes/generator.py specs/openeo-processes specs/openeo-processes/proposals --output openeo/processes.py + + # Update the openEO process mapping documentation page + python docs/process_mapping.py > docs/process_mapping.rst diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 000000000..b2c1ba643 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,75 @@ + +openEO Python Client +===================== + +.. image:: https://img.shields.io/badge/Status-Stable-yellow.svg + +Welcome to the documentation of ``openeo``, +the official Python client library for interacting with **openEO** back-ends +to process remote sensing and Earth observation data. +It provides a **Pythonic** interface for the openEO API, +supporting data/process discovery, process graph building, +batch job management and much more. + + +Usage example +------------- + +A simple example, to give a feel of using this library: + +.. code-block:: python + + import openeo + + # Connect to openEO back-end. + connection = openeo.connect("openeo.vito.be").authenticate_oidc() + + # Load data cube from TERRASCOPE_S2_NDVI_V2 collection. + cube = connection.load_collection( + "TERRASCOPE_S2_NDVI_V2", + spatial_extent={"west": 5.05, "south": 51.21, "east": 5.1, "north": 51.23}, + temporal_extent=["2022-05-01", "2022-05-30"], + bands=["NDVI_10M"], + ) + # Rescale digital number to physical values and take temporal maximum. + cube = cube.apply(lambda x: 0.004 * x - 0.08).max_time() + + cube.download("ndvi-max.tiff") + + +.. image:: _static/images/welcome.png + + +Table of contents +----------------- + +.. toctree:: + :maxdepth: 2 + + self + installation + basics + data_access + processes + batch_jobs + udp + auth + udf + datacube_construction + machine_learning + configuration + cookbook/index + api + api-processes + process_mapping + development + best_practices + changelog + + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/_sources/installation.rst.txt b/_sources/installation.rst.txt new file mode 100644 index 000000000..02fdf4049 --- /dev/null +++ b/_sources/installation.rst.txt @@ -0,0 +1,119 @@ +************* +Installation +************* + + +It is an explicit goal of the openEO Python client library to be as easy to install as possible, +unlocking the openEO ecosystem to a broad audience. +The package is a pure Python implementation and its dependencies are carefully considered (in number and complexity). + + +Basic install +============= + +At least *Python 3.7* is required (since version 0.23.0). +Also, it is recommended to work in a some kind of *virtual environment* (``venv``, ``conda``, ...) +to avoid polluting the base install of Python on your operating system +or introducing conflicts with other applications. +How you organize your virtual environments heavily depends on your use case and workflow, +and is out of scope of this documentation. + + +Installation with ``pip`` +------------------------- + +The openEO Python client library is available from `PyPI `_ +and can be easily installed with a tool like ``pip``, for example: + +.. code-block:: console + + $ pip install openeo + +To upgrade the package to the latest release: + +.. code-block:: console + + $ pip install --upgrade openeo + + +Installation with Conda +------------------------ + +The openEO Python client library is available on `conda-forge `_ +and can be easily installed in a conda environment, for example: + +.. code-block:: console + + $ conda install -c conda-forge openeo + + +Verifying and troubleshooting +----------------------------- + +You can check if the installation worked properly +by trying to import the ``openeo`` package in a Python script, interactive shell or notebook: + +.. code-block:: python + + import openeo + + print(openeo.client_version()) + +This should print the installed version of the ``openeo`` package. + +If the first line gives an error like ``ModuleNotFoundError: No module named 'openeo'``, +some troubleshooting tips: + +- Restart you Python shell or notebook (or start a fresh one). +- Double check that the installation went well, + e.g. try re-installing and keep an eye out for error/warning messages. +- Make sure that you are working in the same (virtual) environment you installed the package in. + +If you still have troubles installing and importing ``openeo``, +feel free to reach out in the `community forum `_ +or the `project's issue tracker `_. +Try to describe your setup in enough detail: your operating system, +which virtual environment system you use, +the installation tool (``pip``, ``conda`` or something else), ... + + +Optional dependencies +====================== + +Depending on your use case, you might also want to install some additional libraries. +For example: + +- ``netCDF4`` or ``h5netcdf`` for loading and writing NetCDF files (e.g. integrated in ``xarray.load_dataset()``) +- ``matplotlib`` for visualisation (e.g. integrated plot functionality in ``xarray`` ) + + +Enabling additional features +---------------------------- + +To use the on-demand preview feature and other Jupyter-enabled features, you need to install the necessary dependencies. + +.. code-block:: console + + $ pip install openeo[jupyter] + + +Source or development install +============================== + +If you closely track the development of the ``openeo`` package at +`github.com/Open-EO/openeo-python-client `_ +and want to work with unreleased features or contribute to the development of the package, +you can install it as follows from the root of a git source checkout: + +.. code-block:: console + + $ pip install -e .[dev] + +The ``-e`` option enables "development mode", which makes sure that changes you make to the source code +happen directly on the installed package, so that you don't have to re-install the package each time +you make a change. + +The ``[dev]`` (a so-called "extra") installs additional development related dependencies, +for example to run the unit tests. + +You can also find more information about installation for development on the :ref:`development-and-maintenance` page. diff --git a/_sources/machine_learning.rst.txt b/_sources/machine_learning.rst.txt new file mode 100644 index 000000000..69f315e1b --- /dev/null +++ b/_sources/machine_learning.rst.txt @@ -0,0 +1,118 @@ +****************** +Machine Learning +****************** + +.. warning:: + This API and documentation is experimental, + under heavy development and subject to change. + + +.. versionadded:: 0.10.0 + + +Random Forest based Classification and Regression +=================================================== + +openEO defines a couple of processes for *random forest* based machine learning +for Earth Observation applications: + +- ``fit_class_random_forest`` for training a random forest based classification model +- ``fit_regr_random_forest`` for training a random forest based regression model +- ``predict_random_forest`` for inference/prediction + +The openEO Python Client library provides the necessary functionality to set up +and execute training and inference workflows. + +Training +--------- + +Let's focus on training a classification model, where we try to predict +a class like a land cover type or crop type based on predictors +we derive from EO data. +For example, assume we have a GeoJSON FeatureCollection +of sample points and a corresponding classification target value as follows:: + + feature_collection = {"type": "FeatureCollection", "features": [ + { + "type": "Feature", + "properties": {"id": "b3dw-wd23", "target": 3}, + "geometry": {"type": "Point", "coordinates": [3.4, 51.1]} + }, + { + "type": "Feature", + "properties": {"id": "r8dh-3jkd", "target": 5}, + "geometry": {"type": "Point", "coordinates": [3.6, 51.2]} + }, + ... + + +.. note:: + Confusingly, the concept "feature" has somewhat conflicting meanings + for different audiences. GIS/EO people use "feature" to refer to the "rows" + in this feature collection. + For the machine learning community however, the properties (the "columns") + are the features. + To avoid confusion in this discussion we will avoid the term "feature" + and instead use "sample point" for the former and "predictor" for the latter. + + +We first build a datacube of "predictor" bands. +For simplicity, we will just use the raw B02/B03/B04 band values here +and use the temporal mean to eliminate the time dimension:: + + cube = connection.load_collection( + "SENTINEL2", + temporal_extent=[start, end], + spatial_extent=bbox, + bands=["B02", "B03", "B04"] + ) + cube = cube.reduce_dimension(dimension="t", reducer="mean") + +We now use ``aggregate_spatial`` to sample this *raster data cube* at the sample points +and get a *vector cube* where we have the temporal mean of the B02/B03/B04 bands as predictor values:: + + predictors = cube.aggregate_spatial(feature_collection, reducer="mean") + +We can now train a *Random Forest* model by calling the +:py:meth:`~openeo.rest.vectorcube.VectorCube.fit_class_random_forest` method on the predictor vector cube +and passing the original target class data:: + + model = predictors.fit_class_random_forest( + target=feature_collection, + ) + # Save the model as a batch job result asset + # so that we can load it in another job. + model = model.save_ml_model() + +Finally execute this whole training flow as a batch job:: + + training_job = model.create_job() + training_job.start_and_wait() + + +Inference +---------- + +When the batch job finishes successfully, the trained model can then be used +with the ``predict_random_forest`` process on the raster data cube +(or another cube with the same band structure) to classify all the pixels. + +Technically, the openEO ``predict_random_forest`` process has to be used as a reducer function +inside a ``reduce_dimension`` call, but the openEO Python client library makes it +a bit easier by providing a :py:meth:`~openeo.rest.datacube.DataCube.predict_random_forest` method +directly on the :py:class:`~openeo.rest.datacube.DataCube` class, so that you can just do:: + + predicted = cube.predict_random_forest( + model=training_job.job_id, + dimension="bands" + ) + + predicted.download("predicted.GTiff") + + +We specified the model here by batch job id (string), +but it can also be specified in other ways: +as :py:class:`~openeo.rest.job.BatchJob` instance, +as URL to the corresponding STAC Item that implements the `ml-model` extension, +or as :py:class:`~openeo.rest.mlmodel.MlModel` instance (e.g. loaded through +:py:meth:`~openeo.rest.connection.Connection.load_ml_model`). diff --git a/_sources/process_mapping.rst.txt b/_sources/process_mapping.rst.txt new file mode 100644 index 000000000..60519285c --- /dev/null +++ b/_sources/process_mapping.rst.txt @@ -0,0 +1,332 @@ + +.. + !Warning! This is an auto-generated file. + Do not edit directly. + Generated from: ['docs/process_mapping.py'] + +.. _openeo_process_mapping: + +openEO Process Mapping +####################### + +The table below maps openEO processes to the corresponding +method or function in the openEO Python Client Library. + +.. list-table:: + :header-rows: 1 + + * - openEO process + - openEO Python Client Method + + * - `absolute `_ + - :py:meth:`ProcessBuilder.absolute() `, :py:meth:`absolute() ` + * - `add `_ + - :py:meth:`ProcessBuilder.__add__() `, :py:meth:`ProcessBuilder.__radd__() `, :py:meth:`ProcessBuilder.add() `, :py:meth:`add() `, :py:meth:`DataCube.add() `, :py:meth:`DataCube.__add__() `, :py:meth:`DataCube.__radd__() ` + * - `add_dimension `_ + - :py:meth:`ProcessBuilder.add_dimension() `, :py:meth:`add_dimension() `, :py:meth:`DataCube.add_dimension() ` + * - `aggregate_spatial `_ + - :py:meth:`ProcessBuilder.aggregate_spatial() `, :py:meth:`aggregate_spatial() `, :py:meth:`DataCube.aggregate_spatial() ` + * - `aggregate_spatial_window `_ + - :py:meth:`ProcessBuilder.aggregate_spatial_window() `, :py:meth:`aggregate_spatial_window() `, :py:meth:`DataCube.aggregate_spatial_window() ` + * - `aggregate_temporal `_ + - :py:meth:`ProcessBuilder.aggregate_temporal() `, :py:meth:`aggregate_temporal() `, :py:meth:`DataCube.aggregate_temporal() ` + * - `aggregate_temporal_period `_ + - :py:meth:`ProcessBuilder.aggregate_temporal_period() `, :py:meth:`aggregate_temporal_period() `, :py:meth:`DataCube.aggregate_temporal_period() ` + * - `all `_ + - :py:meth:`ProcessBuilder.all() `, :py:meth:`all() ` + * - `and `_ + - :py:meth:`DataCube.logical_and() `, :py:meth:`DataCube.__and__() ` + * - `and_ `_ + - :py:meth:`ProcessBuilder.and_() `, :py:meth:`and_() ` + * - `anomaly `_ + - :py:meth:`ProcessBuilder.anomaly() `, :py:meth:`anomaly() ` + * - `any `_ + - :py:meth:`ProcessBuilder.any() `, :py:meth:`any() ` + * - `apply `_ + - :py:meth:`ProcessBuilder.apply() `, :py:meth:`apply() `, :py:meth:`DataCube.apply() ` + * - `apply_dimension `_ + - :py:meth:`ProcessBuilder.apply_dimension() `, :py:meth:`apply_dimension() `, :py:meth:`DataCube.apply_dimension() ` + * - `apply_kernel `_ + - :py:meth:`ProcessBuilder.apply_kernel() `, :py:meth:`apply_kernel() `, :py:meth:`DataCube.apply_kernel() ` + * - `apply_neighborhood `_ + - :py:meth:`ProcessBuilder.apply_neighborhood() `, :py:meth:`apply_neighborhood() `, :py:meth:`DataCube.apply_neighborhood() ` + * - `arccos `_ + - :py:meth:`ProcessBuilder.arccos() `, :py:meth:`arccos() ` + * - `arcosh `_ + - :py:meth:`ProcessBuilder.arcosh() `, :py:meth:`arcosh() ` + * - `arcsin `_ + - :py:meth:`ProcessBuilder.arcsin() `, :py:meth:`arcsin() ` + * - `arctan `_ + - :py:meth:`ProcessBuilder.arctan() `, :py:meth:`arctan() ` + * - `arctan2 `_ + - :py:meth:`ProcessBuilder.arctan2() `, :py:meth:`arctan2() ` + * - `ard_normalized_radar_backscatter `_ + - :py:meth:`ProcessBuilder.ard_normalized_radar_backscatter() `, :py:meth:`ard_normalized_radar_backscatter() `, :py:meth:`DataCube.ard_normalized_radar_backscatter() ` + * - `ard_surface_reflectance `_ + - :py:meth:`ProcessBuilder.ard_surface_reflectance() `, :py:meth:`ard_surface_reflectance() `, :py:meth:`DataCube.ard_surface_reflectance() ` + * - `array_append `_ + - :py:meth:`ProcessBuilder.array_append() `, :py:meth:`array_append() ` + * - `array_apply `_ + - :py:meth:`ProcessBuilder.array_apply() `, :py:meth:`array_apply() ` + * - `array_concat `_ + - :py:meth:`ProcessBuilder.array_concat() `, :py:meth:`array_concat() ` + * - `array_contains `_ + - :py:meth:`ProcessBuilder.array_contains() `, :py:meth:`array_contains() ` + * - `array_create `_ + - :py:meth:`ProcessBuilder.array_create() `, :py:meth:`array_create() ` + * - `array_create_labeled `_ + - :py:meth:`ProcessBuilder.array_create_labeled() `, :py:meth:`array_create_labeled() ` + * - `array_element `_ + - :py:meth:`ProcessBuilder.__getitem__() `, :py:meth:`ProcessBuilder.array_element() `, :py:meth:`array_element() ` + * - `array_filter `_ + - :py:meth:`ProcessBuilder.array_filter() `, :py:meth:`array_filter() ` + * - `array_find `_ + - :py:meth:`ProcessBuilder.array_find() `, :py:meth:`array_find() ` + * - `array_find_label `_ + - :py:meth:`ProcessBuilder.array_find_label() `, :py:meth:`array_find_label() ` + * - `array_interpolate_linear `_ + - :py:meth:`ProcessBuilder.array_interpolate_linear() `, :py:meth:`array_interpolate_linear() ` + * - `array_labels `_ + - :py:meth:`ProcessBuilder.array_labels() `, :py:meth:`array_labels() ` + * - `array_modify `_ + - :py:meth:`ProcessBuilder.array_modify() `, :py:meth:`array_modify() ` + * - `arsinh `_ + - :py:meth:`ProcessBuilder.arsinh() `, :py:meth:`arsinh() ` + * - `artanh `_ + - :py:meth:`ProcessBuilder.artanh() `, :py:meth:`artanh() ` + * - `atmospheric_correction `_ + - :py:meth:`ProcessBuilder.atmospheric_correction() `, :py:meth:`atmospheric_correction() `, :py:meth:`DataCube.atmospheric_correction() ` + * - `between `_ + - :py:meth:`ProcessBuilder.between() `, :py:meth:`between() ` + * - `ceil `_ + - :py:meth:`ProcessBuilder.ceil() `, :py:meth:`ceil() ` + * - `climatological_normal `_ + - :py:meth:`ProcessBuilder.climatological_normal() `, :py:meth:`climatological_normal() ` + * - `clip `_ + - :py:meth:`ProcessBuilder.clip() `, :py:meth:`clip() ` + * - `cloud_detection `_ + - :py:meth:`ProcessBuilder.cloud_detection() `, :py:meth:`cloud_detection() ` + * - `constant `_ + - :py:meth:`ProcessBuilder.constant() `, :py:meth:`constant() ` + * - `cos `_ + - :py:meth:`ProcessBuilder.cos() `, :py:meth:`cos() ` + * - `cosh `_ + - :py:meth:`ProcessBuilder.cosh() `, :py:meth:`cosh() ` + * - `count `_ + - :py:meth:`ProcessBuilder.count() `, :py:meth:`count() `, :py:meth:`DataCube.count_time() ` + * - `create_raster_cube `_ + - :py:meth:`ProcessBuilder.create_raster_cube() `, :py:meth:`create_raster_cube() ` + * - `cummax `_ + - :py:meth:`ProcessBuilder.cummax() `, :py:meth:`cummax() ` + * - `cummin `_ + - :py:meth:`ProcessBuilder.cummin() `, :py:meth:`cummin() ` + * - `cumproduct `_ + - :py:meth:`ProcessBuilder.cumproduct() `, :py:meth:`cumproduct() ` + * - `cumsum `_ + - :py:meth:`ProcessBuilder.cumsum() `, :py:meth:`cumsum() ` + * - `date_shift `_ + - :py:meth:`ProcessBuilder.date_shift() `, :py:meth:`date_shift() ` + * - `dimension_labels `_ + - :py:meth:`ProcessBuilder.dimension_labels() `, :py:meth:`dimension_labels() `, :py:meth:`DataCube.dimension_labels() ` + * - `divide `_ + - :py:meth:`ProcessBuilder.__truediv__() `, :py:meth:`ProcessBuilder.__rtruediv__() `, :py:meth:`ProcessBuilder.divide() `, :py:meth:`divide() `, :py:meth:`DataCube.divide() `, :py:meth:`DataCube.__truediv__() `, :py:meth:`DataCube.__rtruediv__() ` + * - `drop_dimension `_ + - :py:meth:`ProcessBuilder.drop_dimension() `, :py:meth:`drop_dimension() `, :py:meth:`DataCube.drop_dimension() ` + * - `e `_ + - :py:meth:`ProcessBuilder.e() `, :py:meth:`e() ` + * - `eq `_ + - :py:meth:`ProcessBuilder.__eq__() `, :py:meth:`ProcessBuilder.eq() `, :py:meth:`eq() `, :py:meth:`DataCube.__eq__() ` + * - `exp `_ + - :py:meth:`ProcessBuilder.exp() `, :py:meth:`exp() ` + * - `extrema `_ + - :py:meth:`ProcessBuilder.extrema() `, :py:meth:`extrema() ` + * - `filter_bands `_ + - :py:meth:`ProcessBuilder.filter_bands() `, :py:meth:`filter_bands() `, :py:meth:`DataCube.filter_bands() ` + * - `filter_bbox `_ + - :py:meth:`ProcessBuilder.filter_bbox() `, :py:meth:`filter_bbox() `, :py:meth:`DataCube.filter_bbox() ` + * - `filter_labels `_ + - :py:meth:`ProcessBuilder.filter_labels() `, :py:meth:`filter_labels() ` + * - `filter_spatial `_ + - :py:meth:`ProcessBuilder.filter_spatial() `, :py:meth:`filter_spatial() `, :py:meth:`DataCube.filter_spatial() ` + * - `filter_temporal `_ + - :py:meth:`ProcessBuilder.filter_temporal() `, :py:meth:`filter_temporal() `, :py:meth:`DataCube.filter_temporal() ` + * - `first `_ + - :py:meth:`ProcessBuilder.first() `, :py:meth:`first() ` + * - `fit_class_random_forest `_ + - :py:meth:`ProcessBuilder.fit_class_random_forest() `, :py:meth:`fit_class_random_forest() `, :py:meth:`VectorCube.fit_class_random_forest() ` + * - `fit_curve `_ + - :py:meth:`ProcessBuilder.fit_curve() `, :py:meth:`fit_curve() `, :py:meth:`DataCube.fit_curve() ` + * - `fit_regr_random_forest `_ + - :py:meth:`ProcessBuilder.fit_regr_random_forest() `, :py:meth:`fit_regr_random_forest() `, :py:meth:`VectorCube.fit_regr_random_forest() ` + * - `flatten_dimensions `_ + - :py:meth:`ProcessBuilder.flatten_dimensions() `, :py:meth:`flatten_dimensions() `, :py:meth:`DataCube.flatten_dimensions() ` + * - `floor `_ + - :py:meth:`ProcessBuilder.floor() `, :py:meth:`floor() ` + * - `ge `_ + - :py:meth:`ProcessBuilder.__ge__() `, :py:meth:`DataCube.__ge__() ` + * - `gt `_ + - :py:meth:`ProcessBuilder.__gt__() `, :py:meth:`ProcessBuilder.gt() `, :py:meth:`gt() `, :py:meth:`DataCube.__gt__() ` + * - `gte `_ + - :py:meth:`ProcessBuilder.gte() `, :py:meth:`gte() ` + * - `if_ `_ + - :py:meth:`ProcessBuilder.if_() `, :py:meth:`if_() ` + * - `inspect `_ + - :py:meth:`ProcessBuilder.inspect() `, :py:meth:`inspect() ` + * - `int `_ + - :py:meth:`ProcessBuilder.int() `, :py:meth:`int() ` + * - `is_infinite `_ + - :py:meth:`ProcessBuilder.is_infinite() `, :py:meth:`is_infinite() ` + * - `is_nan `_ + - :py:meth:`ProcessBuilder.is_nan() `, :py:meth:`is_nan() ` + * - `is_nodata `_ + - :py:meth:`ProcessBuilder.is_nodata() `, :py:meth:`is_nodata() ` + * - `is_valid `_ + - :py:meth:`ProcessBuilder.is_valid() `, :py:meth:`is_valid() ` + * - `last `_ + - :py:meth:`ProcessBuilder.last() `, :py:meth:`last() ` + * - `le `_ + - :py:meth:`DataCube.__le__() ` + * - `linear_scale_range `_ + - :py:meth:`ProcessBuilder.linear_scale_range() `, :py:meth:`linear_scale_range() `, :py:meth:`DataCube.linear_scale_range() ` + * - `ln `_ + - :py:meth:`ProcessBuilder.ln() `, :py:meth:`ln() `, :py:meth:`DataCube.ln() ` + * - `load_collection `_ + - :py:meth:`ProcessBuilder.load_collection() `, :py:meth:`load_collection() `, :py:meth:`DataCube.load_collection() `, :py:meth:`Connection.load_collection() ` + * - `load_geojson `_ + - :py:meth:`VectorCube.load_geojson() `, :py:meth:`Connection.load_geojson() ` + * - `load_ml_model `_ + - :py:meth:`ProcessBuilder.load_ml_model() `, :py:meth:`load_ml_model() `, :py:meth:`MlModel.load_ml_model() ` + * - `load_result `_ + - :py:meth:`ProcessBuilder.load_result() `, :py:meth:`load_result() `, :py:meth:`Connection.load_result() ` + * - `load_stac `_ + - :py:meth:`Connection.load_stac() ` + * - `load_uploaded_files `_ + - :py:meth:`ProcessBuilder.load_uploaded_files() `, :py:meth:`load_uploaded_files() ` + * - `log `_ + - :py:meth:`ProcessBuilder.log() `, :py:meth:`log() `, :py:meth:`DataCube.logarithm() `, :py:meth:`DataCube.log2() `, :py:meth:`DataCube.log10() ` + * - `lt `_ + - :py:meth:`ProcessBuilder.__lt__() `, :py:meth:`ProcessBuilder.lt() `, :py:meth:`lt() `, :py:meth:`DataCube.__lt__() ` + * - `lte `_ + - :py:meth:`ProcessBuilder.__le__() `, :py:meth:`ProcessBuilder.lte() `, :py:meth:`lte() ` + * - `mask `_ + - :py:meth:`ProcessBuilder.mask() `, :py:meth:`mask() `, :py:meth:`DataCube.mask() ` + * - `mask_polygon `_ + - :py:meth:`ProcessBuilder.mask_polygon() `, :py:meth:`mask_polygon() `, :py:meth:`DataCube.mask_polygon() ` + * - `max `_ + - :py:meth:`ProcessBuilder.max() `, :py:meth:`max() `, :py:meth:`DataCube.max_time() ` + * - `mean `_ + - :py:meth:`ProcessBuilder.mean() `, :py:meth:`mean() `, :py:meth:`DataCube.mean_time() ` + * - `median `_ + - :py:meth:`ProcessBuilder.median() `, :py:meth:`median() `, :py:meth:`DataCube.median_time() ` + * - `merge_cubes `_ + - :py:meth:`ProcessBuilder.merge_cubes() `, :py:meth:`merge_cubes() `, :py:meth:`DataCube.merge_cubes() ` + * - `min `_ + - :py:meth:`ProcessBuilder.min() `, :py:meth:`min() `, :py:meth:`DataCube.min_time() ` + * - `mod `_ + - :py:meth:`ProcessBuilder.mod() `, :py:meth:`mod() ` + * - `multiply `_ + - :py:meth:`ProcessBuilder.__mul__() `, :py:meth:`ProcessBuilder.__rmul__() `, :py:meth:`ProcessBuilder.__neg__() `, :py:meth:`ProcessBuilder.multiply() `, :py:meth:`multiply() `, :py:meth:`DataCube.multiply() `, :py:meth:`DataCube.__neg__() `, :py:meth:`DataCube.__mul__() `, :py:meth:`DataCube.__rmul__() ` + * - `nan `_ + - :py:meth:`ProcessBuilder.nan() `, :py:meth:`nan() ` + * - `ndvi `_ + - :py:meth:`ProcessBuilder.ndvi() `, :py:meth:`ndvi() `, :py:meth:`DataCube.ndvi() ` + * - `neq `_ + - :py:meth:`ProcessBuilder.__ne__() `, :py:meth:`ProcessBuilder.neq() `, :py:meth:`neq() `, :py:meth:`DataCube.__ne__() ` + * - `normalized_difference `_ + - :py:meth:`ProcessBuilder.normalized_difference() `, :py:meth:`normalized_difference() `, :py:meth:`DataCube.normalized_difference() ` + * - `not `_ + - :py:meth:`DataCube.__invert__() ` + * - `not_ `_ + - :py:meth:`ProcessBuilder.not_() `, :py:meth:`not_() ` + * - `or `_ + - :py:meth:`DataCube.logical_or() `, :py:meth:`DataCube.__or__() ` + * - `or_ `_ + - :py:meth:`ProcessBuilder.or_() `, :py:meth:`or_() ` + * - `order `_ + - :py:meth:`ProcessBuilder.order() `, :py:meth:`order() ` + * - `pi `_ + - :py:meth:`ProcessBuilder.pi() `, :py:meth:`pi() ` + * - `power `_ + - :py:meth:`ProcessBuilder.__pow__() `, :py:meth:`ProcessBuilder.power() `, :py:meth:`power() `, :py:meth:`DataCube.__rpow__() `, :py:meth:`DataCube.__pow__() `, :py:meth:`DataCube.power() ` + * - `predict_curve `_ + - :py:meth:`ProcessBuilder.predict_curve() `, :py:meth:`predict_curve() `, :py:meth:`DataCube.predict_curve() ` + * - `predict_random_forest `_ + - :py:meth:`ProcessBuilder.predict_random_forest() `, :py:meth:`predict_random_forest() `, :py:meth:`DataCube.predict_random_forest() ` + * - `product `_ + - :py:meth:`ProcessBuilder.product() `, :py:meth:`product() ` + * - `quantiles `_ + - :py:meth:`ProcessBuilder.quantiles() `, :py:meth:`quantiles() ` + * - `rearrange `_ + - :py:meth:`ProcessBuilder.rearrange() `, :py:meth:`rearrange() ` + * - `reduce_dimension `_ + - :py:meth:`ProcessBuilder.reduce_dimension() `, :py:meth:`reduce_dimension() `, :py:meth:`DataCube.reduce_dimension() ` + * - `reduce_spatial `_ + - :py:meth:`ProcessBuilder.reduce_spatial() `, :py:meth:`reduce_spatial() ` + * - `rename_dimension `_ + - :py:meth:`ProcessBuilder.rename_dimension() `, :py:meth:`rename_dimension() `, :py:meth:`DataCube.rename_dimension() ` + * - `rename_labels `_ + - :py:meth:`ProcessBuilder.rename_labels() `, :py:meth:`rename_labels() `, :py:meth:`DataCube.rename_labels() ` + * - `resample_cube_spatial `_ + - :py:meth:`ProcessBuilder.resample_cube_spatial() `, :py:meth:`resample_cube_spatial() ` + * - `resample_cube_temporal `_ + - :py:meth:`ProcessBuilder.resample_cube_temporal() `, :py:meth:`resample_cube_temporal() `, :py:meth:`DataCube.resample_cube_temporal() ` + * - `resample_spatial `_ + - :py:meth:`ProcessBuilder.resample_spatial() `, :py:meth:`resample_spatial() `, :py:meth:`DataCube.resample_spatial() ` + * - `resolution_merge `_ + - :py:meth:`DataCube.resolution_merge() ` + * - `round `_ + - :py:meth:`ProcessBuilder.round() `, :py:meth:`round() ` + * - `run_udf `_ + - :py:meth:`ProcessBuilder.run_udf() `, :py:meth:`run_udf() `, :py:meth:`VectorCube.run_udf() ` + * - `run_udf_externally `_ + - :py:meth:`ProcessBuilder.run_udf_externally() `, :py:meth:`run_udf_externally() ` + * - `sar_backscatter `_ + - :py:meth:`ProcessBuilder.sar_backscatter() `, :py:meth:`sar_backscatter() `, :py:meth:`DataCube.sar_backscatter() ` + * - `save_ml_model `_ + - :py:meth:`ProcessBuilder.save_ml_model() `, :py:meth:`save_ml_model() ` + * - `save_result `_ + - :py:meth:`ProcessBuilder.save_result() `, :py:meth:`save_result() `, :py:meth:`VectorCube.save_result() `, :py:meth:`DataCube.save_result() ` + * - `sd `_ + - :py:meth:`ProcessBuilder.sd() `, :py:meth:`sd() ` + * - `sgn `_ + - :py:meth:`ProcessBuilder.sgn() `, :py:meth:`sgn() ` + * - `sin `_ + - :py:meth:`ProcessBuilder.sin() `, :py:meth:`sin() ` + * - `sinh `_ + - :py:meth:`ProcessBuilder.sinh() `, :py:meth:`sinh() ` + * - `sort `_ + - :py:meth:`ProcessBuilder.sort() `, :py:meth:`sort() ` + * - `sqrt `_ + - :py:meth:`ProcessBuilder.sqrt() `, :py:meth:`sqrt() ` + * - `subtract `_ + - :py:meth:`ProcessBuilder.__sub__() `, :py:meth:`ProcessBuilder.__rsub__() `, :py:meth:`ProcessBuilder.subtract() `, :py:meth:`subtract() `, :py:meth:`DataCube.subtract() `, :py:meth:`DataCube.__sub__() `, :py:meth:`DataCube.__rsub__() ` + * - `sum `_ + - :py:meth:`ProcessBuilder.sum() `, :py:meth:`sum() ` + * - `tan `_ + - :py:meth:`ProcessBuilder.tan() `, :py:meth:`tan() ` + * - `tanh `_ + - :py:meth:`ProcessBuilder.tanh() `, :py:meth:`tanh() ` + * - `text_begins `_ + - :py:meth:`ProcessBuilder.text_begins() `, :py:meth:`text_begins() ` + * - `text_concat `_ + - :py:meth:`ProcessBuilder.text_concat() `, :py:meth:`text_concat() ` + * - `text_contains `_ + - :py:meth:`ProcessBuilder.text_contains() `, :py:meth:`text_contains() ` + * - `text_ends `_ + - :py:meth:`ProcessBuilder.text_ends() `, :py:meth:`text_ends() ` + * - `trim_cube `_ + - :py:meth:`ProcessBuilder.trim_cube() `, :py:meth:`trim_cube() ` + * - `unflatten_dimension `_ + - :py:meth:`ProcessBuilder.unflatten_dimension() `, :py:meth:`unflatten_dimension() `, :py:meth:`DataCube.unflatten_dimension() ` + * - `variance `_ + - :py:meth:`ProcessBuilder.variance() `, :py:meth:`variance() ` + * - `vector_buffer `_ + - :py:meth:`ProcessBuilder.vector_buffer() `, :py:meth:`vector_buffer() ` + * - `vector_to_random_points `_ + - :py:meth:`ProcessBuilder.vector_to_random_points() `, :py:meth:`vector_to_random_points() ` + * - `vector_to_regular_points `_ + - :py:meth:`ProcessBuilder.vector_to_regular_points() `, :py:meth:`vector_to_regular_points() ` + * - `xor `_ + - :py:meth:`ProcessBuilder.xor() `, :py:meth:`xor() ` + +:subscript:`(Table autogenerated on 2023-08-07)` diff --git a/_sources/processes.rst.txt b/_sources/processes.rst.txt new file mode 100644 index 000000000..b81db1c53 --- /dev/null +++ b/_sources/processes.rst.txt @@ -0,0 +1,465 @@ +*********************** +Working with processes +*********************** + +In openEO, a **process** is an operation that performs a specific task on +a set of parameters and returns a result. +For example, with the ``add`` process you can add two numbers, in openEO's JSON notation:: + + { + "process_id": "add", + "arguments": {"x": 3, "y": 5} + } + + +A process is similar to a *function* in common programming languages, +and likewise, multiple processes can be combined or chained together +into new, more complex operations. + +A bit of terminology +==================== + +A **pre-defined process** is a process provided out of the box by a given *back-end*. +These are often the `centrally defined openEO processes `_, +such as common mathematical (``sum``, ``divide``, ``sqrt``, ...), +statistical (``mean``, ``max``, ...) and +image processing (``mask``, ``apply_kernel``, ...) +operations. +Back-ends are expected to support most of these standard ones, +but are free to pre-define additional ones too. + + +Processes can be combined into a larger pipeline, parameterized +and stored on the back-end as a so called **user-defined process**. +This allows you to build a library of reusable building blocks +that can be be inserted easily in multiple other places. +See :ref:`user-defined-processes` for more information. + + +How processes are combined into a larger unit +is internally represented by a so-called **process graph**. +It describes how the inputs and outputs of processes +should be linked together. +A user of the Python client should normally not worry about +the details of a process graph structure, as most of these aspects +are hidden behind regular Python functions, classes and methods. + + + +Using common pre-defined processes +=================================== + +The listing of pre-defined processes provided by a back-end +can be inspected with :func:`~openeo.rest.connection.Connection.list_processes`. +For example, to get a list of the process names (process ids):: + + >>> process_ids = [process["id"] for process in connection.list_processes()] + >>> print(process_ids[:16]) + ['arccos', 'arcosh', 'power', 'last', 'subtract', 'not', 'cosh', 'artanh', + 'is_valid', 'first', 'median', 'eq', 'absolute', 'arctan2', 'divide','is_nan'] + +More information about the processes, like a description +or expected parameters, can be queried like that, +but it is often easier to look them up on the +`official openEO process documentation `_ + +A single pre-defined process can be retrieved with +:func:`~openeo.rest.connection.Connection.describe_process`. + +Convenience methods +-------------------- + +Most of the important pre-defined processes are covered directly by methods +on classes like :class:`~openeo.rest.datacube.DataCube` or +:class:`~openeo.rest.vectorcube.VectorCube`. + +.. seealso:: + See :ref:`openeo_process_mapping` for a mapping of openEO processes + the corresponding methods in the openEO Python Client library. + +For example, to apply the ``filter_temporal`` process to a raster data cube:: + + cube = cube.filter_temporal("2020-02-20", "2020-06-06") + +Being regular Python methods, you get usual function call features +you're accustomed to: default values, keyword arguments, ``kwargs`` usage, ... +For example, to use a bounding box dictionary with ``kwargs``-expansion:: + + bbox = { + "west": 5.05, "south": 51.20, "east": 5.10, "north": 51.23 + } + cube = cube.filter_bbox(**bbox) + +Note that some methods try to be more flexible and convenient to use +than how the official process definition prescribes. +For example, the ``filter_temporal`` process expects an ``extent`` array +with 2 items (the start and end date), +but you can call the corresponding client method in multiple equivalent ways:: + + cube.filter_temporal("2019-07-01", "2019-08-01") + cube.filter_temporal(["2019-07-01", "2019-08-01"]) + cube.filter_temporal(extent=["2019-07-01", "2019-08-01"]) + cube.filter_temporal(start_date="2019-07-01", end_date="2019-08-01"]) + + +Advanced argument tweaking +--------------------------- + +.. versionadded:: 0.10.1 + +In some situations, you may want to finetune what the (convenience) methods generate. +For example, you want to play with non-standard, experimental arguments, +or there is a problem with a automatic argument handling/conversion feature. + +You can tweak the arguments of your current result node as follows. +Say, we want to add some non-standard ``feature_flags`` argument to the ``load_collection`` process node. +We first get the current result node with :py:meth:`~openeo.rest.datacube.DataCube.result_node` and use :py:meth:`~openeo.internal.graph_building.PGNode.update_arguments` to add an additional argument to it:: + + # `Connection.load_collection` does not support `feature_flags` argument + cube = connection.load_collection(...) + + # Add `feature_flag` argument `load_collection` process graph node + cube.result_node().update_arguments(feature_flags="rXPk") + + # The resulting process graph will now contain this non-standard argument: + # { + # "process_id": "load_collection", + # "arguments": { + # ... + # "feature_flags": "rXPk", + + +Generic API for adding processes +================================= + +An openEO back-end may offer processes that are not part of the core API, +or the client may not (yet) have a corresponding method +for a process that you wish to use. +In that case, you can fall back to a more generic API +that allows you to add processes directly. + +Basics +------ + +To add a simple process to the graph, use +the :func:`~openeo.rest.datacube.DataCube.process` method +on a :class:`~openeo.rest.datacube.DataCube`. +You have to specify the process id and arguments +(as a single dictionary or through keyword arguments ``**kwargs``). +It will return a new DataCube with the new process appended +to the internal process graph. + +.. # TODO this example makes no sense: it uses cube for what? + +A very simple example using the ``mean`` process and a +literal list in an arguments dictionary:: + + arguments= { + "data": [1, 3, -1] + } + res = cube.process("mean", arguments) + +or equivalently, leveraging keyword arguments:: + + res = cube.process("mean", data=[1, 3, -1]) + + +Passing data cube arguments +---------------------------- + +The example above is a bit convoluted however in the sense that +you start from a given data cube ``cube``, you add a ``mean`` process +that works on a given data array, while completely ignoring the original cube. +In reality you typically want to apply the process on the cube. +This is possible by passing a data cube object directly as argument, +for example with the ``ndvi`` process that at least expects +a data cube as ``data`` argument :: + + res = cube.process("ndvi", data=cube) + + +Note that you have to specify ``cube`` twice here: +a first time to call the method and a second time as argument. +Moreover, it requires you to define a Python variable for the data +cube, which is annoying if you want to use a chained expressions. +To solve these issues, you can use the :const:`~openeo.rest.datacube.THIS` +constant as symbolic reference to the "current" cube:: + + from openeo.rest.datacube import THIS + + res = ( + cube + .process("filter_bands", data=THIS) + .process("mask", data=THIS, mask=mask) + .process("ndvi", data=THIS) + ) + + +Passing results from other process calls as arguments +------------------------------------------------------ + +Another use case of generically applying (custom) processes is +passing a process result as argument to another process working on a cube. +For example, assume we have a custom process ``load_my_vector_cube`` +to load a vector cube from an online resource. +We can use this vector cube as geometry for +:py:meth:`DataCube.aggregate_spatial() ` +using :py:func:`openeo.processes.process()` as follows: + + +.. code-block:: python + + from openeo.processes import process + + res = cube.aggregate_spatial( + geometries=process("load_my_vector_cube", url="https://geo.example/features.db"), + reducer="mean" + ) + + +.. _callbackfunctions: + +Processes with child "callbacks" +================================ + +Some openEO processes expect some kind of sub-process +to be invoked on a subset or slice of the datacube. +For example: + +* process ``apply`` requires a transformation that will be applied + to each pixel in the cube (separately), e.g. in pseudocode + + .. code-block:: text + + cube.apply( + given a pixel value + => scale it with factor 0.01 + ) + +* process ``reduce_dimension`` requires an aggregation function to convert + an array of pixel values (along a given dimension) to a single value, + e.g. in pseudocode + + .. code-block:: text + + cube.reduce_dimension( + given a pixel timeseries (array) for a (x,y)-location + => temporal mean of that array + ) + +* process ``aggregate_spatial`` requires a function to aggregate the values + in one or more geometries + +These transformation functions are usually called "**callbacks**" +because instead of being called explicitly by the user, +they are called and managed by their "parent" process +(the ``apply``, ``reduce_dimension`` and ``aggregate_spatial`` in the examples) + + +The openEO Python Client Library currently provides a couple of DataCube methods +that expect such a callback, most commonly: + +- :py:meth:`openeo.rest.datacube.DataCube.aggregate_spatial` +- :py:meth:`openeo.rest.datacube.DataCube.aggregate_temporal` +- :py:meth:`openeo.rest.datacube.DataCube.apply` +- :py:meth:`openeo.rest.datacube.DataCube.apply_dimension` +- :py:meth:`openeo.rest.datacube.DataCube.apply_neighborhood` +- :py:meth:`openeo.rest.datacube.DataCube.reduce_dimension` + +The openEO Python Client Library supports several ways +to specify the desired callback for these functions: + + +.. contents:: + :depth: 1 + :local: + :backlinks: top + +Callback as string +------------------ + +The easiest way is passing a process name as a string, +for example: + +.. code-block:: python + + # Take the absolute value of each pixel + cube.apply("absolute") + + # Reduce a cube along the temporal dimension by taking the maximum value + cube.reduce_dimension(reducer="max", dimension="t") + +This approach is only possible if the desired transformation is available +as a single process. If not, use one of the methods below. + +It's also important to note that the "signature" of the provided callback process +should correspond properly with what the parent process expects. +For example: ``apply`` requires a callback process that receives a +number and returns one (like ``absolute`` or ``sqrt``), +while ``reduce_dimension`` requires a callback process that receives +an array of numbers and returns a single number (like ``max`` or ``mean``). + + +.. _child_callback_callable: + +Callback as a callable +----------------------- + +You can also specify the callback as a "callable": +which is a fancy word for a Python object that can be called, +but just think of it like a function you can call. + +You can use a regular Python function, like this: + +.. code-block:: python + + def transform(x): + return x * 2 + 3 + + cube.apply(transform) + +or, more compactly, a "lambda" +(a construct in Python to create anonymous inline functions): + +.. code-block:: python + + cube.apply(lambda x: x * 2 + 3) + + +The openEO Python Client Library implements most of the official openEO processes as +:ref:`functions in the "openeo.processes" module `, +which can be used directly as callback: + +.. code-block:: python + + from openeo.processes import absolute, max + + cube.apply(absolute) + cube.reduce_dimension(reducer=max, dimension="t") + + +The argument that will be passed to all these callback functions is +a :py:class:`ProcessBuilder ` instance. +This is a helper object with predefined methods for all standard openEO processes, +allowing to use an object oriented coding style to define the callback. +For example: + +.. code-block:: python + + from openeo.processes import ProcessBuilder + + def avg(data: ProcessBuilder): + return data.mean() + + cube.reduce_dimension(reducer=avg, dimension="t") + + +These methods also return :py:class:`ProcessBuilder ` objects, +which also allows writing callbacks in chained fashion: + +.. code-block:: python + + cube.apply( + lambda x: x.absolute().cos().add(y=1.23) + ) + + +All this gives a lot of flexibility to define callbacks compactly +in a desired coding style. +The following examples result in the same callback: + +.. code-block:: python + + from openeo.processes import ProcessBuilder, mean, cos, add + + # Chained methods + cube.reduce_dimension( + lambda data: data.mean().cos().add(y=1.23), + dimension="t" + ) + + # Functions + cube.reduce_dimension( + lambda data: add(x=cos(mean(data)), y=1.23), + dimension="t" + ) + + # Mixing methods, functions and operators + cube.reduce_dimension( + lambda data: cos(data.mean())) + 1.23, + dimension="t" + ) + + +Caveats +```````` + +Specifying callbacks through Python functions (or lambdas) +looks intuitive and straightforward, but it should be noted +that not everything is allowed in these functions. +You should just limit yourself to calling +:py:mod:`openeo.processes` functions, +:py:class:`ProcessBuilder ` methods +and basic math operators. +Don't call functions from other libraries like numpy or scipy. +Don't use Python control flow statements like ``if/else`` constructs +or ``for`` loops. + +The reason for this is that the openEO Python Client Library +does not translate the function source code itself +to an openEO process graph. +Instead, when building the openEO process graph, +it passes a special object to the function +and keeps track of which :py:mod:`openeo.processes` functions +were called to assemble the corresponding process graph. +If you use control flow statements or use numpy functions for example, +this procedure will incorrectly detect what you want to do in the callback. + +For example, if you mistakenly use the Python builtin :py:func:`sum` function +in a callback instead of :py:func:`openeo.processes.sum`, you will run into trouble. +Luckily the openEO Python client Library should raise an error if it detects that:: + + >>> # Wrongly using builtin `sum` function + >>> cube.reduce_dimension(dimension="t", reducer=sum) + RuntimeError: Exceeded ProcessBuilder iteration limit. + Are you mistakenly using a builtin like `sum()` or `all()` in a callback + instead of the appropriate helpers from `openeo.processes`? + + >>> # Explicit usage of `openeo.processes.sum` + >>> import openeo.processes + >>> cube.reduce_dimension(dimension="t", reducer=openeo.processes.sum) + + + + +Callback as ``PGNode`` +----------------------- + +You can also pass a :py:class:`~openeo.internal.graph_building.PGNode` object as callback. + +.. attention:: + This approach should generally not be used in normal use cases. + The other options discussed above should be preferred. + It's mainly intended for internal use and an occasional, advanced use case. + It requires in-depth knowledge of the openEO API + and openEO Python Client Library to construct correctly. + +Some examples: + +.. code-block:: python + + from openeo.internal.graph_building import PGNode + + cube.apply(PGNode( + "add", + x=PGNode( + "cos", + x=PGNode("absolute", x={"from_parameter": "x"}) + ), + y=1.23 + )) + + cube.reduce_dimension( + reducer=PGNode("max", data={"from_parameter": "data"}), + dimension="bands" + ) diff --git a/_sources/udf.rst.txt b/_sources/udf.rst.txt new file mode 100644 index 000000000..4cc33232d --- /dev/null +++ b/_sources/udf.rst.txt @@ -0,0 +1,556 @@ +.. index:: User-defined functions +.. index:: UDF + +.. _user-defined-functions: + +###################################### +User-Defined Functions (UDF) explained +###################################### + + +While openEO supports a wide range of pre-defined processes +and allows to build more complex user-defined processes from them, +you sometimes need operations or algorithms that are +not (yet) available or standardized as openEO process. +**User-Defined Functions (UDF)** is an openEO feature +(through the `run_udf `_ process) +that aims to fill that gap by allowing a user to express (a part of) +an **algorithm as a Python/R/... script to be run back-end side**. + +There are a lot of details to cover, +but here is a rudimentary example snippet +to give you a quick impression of how to work with UDFs +using the openEO Python Client library: + +.. code-block:: python + :caption: Basic UDF usage example snippet to rescale pixel values + + # Build a UDF object from an inline string with Python source code. + udf = openeo.UDF(""" + from openeo.udf import XarrayDataCube + + def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube: + array = cube.get_array() + array.values = 0.0001 * array.values + return cube + """) + + # Apply the UDF to a cube. + rescaled_cube = cube.apply(process=udf) + + +Ideally, it allows you to embed existing Python/R/... implementations +in an openEO workflow (with some necessary "glue code"). +However, it is recommended to try to do as much pre- or postprocessing +with pre-defined processes +before blindly copy-pasting source code snippets as UDFs. +Pre-defined processes are typically well-optimized by the backend, +while UDFs can come with a performance penalty +and higher development/debug/maintenance costs. + + +.. warning:: + + Don not confuse **user-defined functions** (abbreviated as UDF) with + **user-defined processes** (sometimes abbreviated as UDP) in openEO, + which is a way to define and use your own process graphs + as reusable building blocks. + See :ref:`user-defined-processes` for more information. + + + +Applicability and Constraints +============================== + +.. index:: chunking + +openEO is designed to work transparently on large data sets +and your UDF has to follow a couple of guidelines to make that possible. +First of all, as data cubes play a central role in openEO, +your UDF should accept and return correct **data cube structures**, +with proper dimensions, dimension labels, etc. +Moreover, the back-end will typically divide your input data cube +in smaller chunks and process these chunks separately (e.g. on isolated workers). +Consequently, it's important that your **UDF algorithm operates correctly +in such a chunked processing context**. + +UDFs as apply/reduce "callbacks" +--------------------------------- + +UDFs are typically used as "callback" processes for "meta" processes +like ``apply`` or ``reduce_dimension`` (also see :ref:`callbackfunctions`). +These meta-processes make abstraction of a datacube as a whole +and allow the callback to focus on a small slice of data or a single dimension. +Their nature instructs the backend how the data should be processed +and can be chunked: + +`apply `_ + Applies a process on *each pixel separately*. + The back-end has all freedom to choose chunking + (e.g. chunk spatially and temporally). + Dimensions and their labels are fully preserved. + See :ref:`udf_example_apply` + +`apply_dimension `_ + Applies a process to all pixels *along a given dimension* + to produce a new series of values for that dimension. + The back-end will not split your data on that dimension. + For example, when working along the time dimension, + your UDF is guaranteed to receive a full timeseries, + but the data could be chunked spatially. + All dimensions and labels are preserved, + except for the dimension along which ``apply_dimension`` is applied: + the number of dimension labels is allowed to change. + +`reduce_dimension `_ + Applies a process to all pixels *along a given dimension* + to produce a single value, eliminating that dimension. + Like with ``apply_dimension``, the back-end will + not split your data on that dimension. + The dimension along which ``apply_dimension`` is applied must be removed + from the output. + For example, when applying ``reduce_dimension`` on a spatiotemporal cube + along the time dimension, + the UDF is guaranteed to receive full timeseries + (but the data could be chunked spatially) + and the output cube should only be a spatial cube, without a temporal dimension + +`apply_neighborhood `_ + Applies a process to a neighborhood of pixels + in a sliding-window fashion with (optional) overlap. + Data chunking in this case is explicitly controlled by the user. + Dimensions and number of labels are fully preserved. + + + +UDF function names and signatures +================================== + +The UDF code you pass to the back-end is basically a Python script +that contains one or more functions. +Exactly one of these functions should have a proper UDF signature, +as defined in the :py:mod:`openeo.udf.udf_signatures` module, +so that the back-end knows what the *entrypoint* function is +of your UDF implementation. + + +Module ``openeo.udf.udf_signatures`` +------------------------------------- + + +.. automodule:: openeo.udf.udf_signatures + :members: + + + +.. _udf_example_apply: + +A first example: ``apply`` with an UDF to rescale pixel values +================================================================ + +In most of the examples here, we will start from an initial Sentinel2 data cube like this: + +.. code-block:: python + + s2_cube = connection.load_collection( + "SENTINEL2_L2A", + spatial_extent={"west": 4.00, "south": 51.04, "east": 4.10, "north": 51.1}, + temporal_extent=["2022-03-01", "2022-03-31"], + bands=["B02", "B03", "B04"] + ) + + +The raw values in this initial ``s2_cube`` data cube are **digital numbers** +(integer values ranging from 0 to several thousands) +and to get **physical reflectance** values (float values, typically in the range between 0 and 0.5), +we have to rescale them. +This is a simple local transformation, without any interaction between pixels, +which is the modus operandi of the ``apply`` processes. + +.. note:: + + In practice it will be a lot easier and more efficient to do this kind of rescaling + with pre-defined openEO math processes, for example: ``s2_cube.apply(lambda x: 0.0001 * x)``. + This is just a very simple illustration to get started with UDFs. + +UDF script +---------- + +The UDF code is this short script (the part that does the actual value rescaling is highlighted): + +.. code-block:: python + :linenos: + :caption: ``udf-code.py`` + :emphasize-lines: 5 + + from openeo.udf import XarrayDataCube + + def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube: + array = cube.get_array() + array.values = 0.0001 * array.values + return cube + +Some details about this UDF script: + +- line 1: We import :py:class:`~openeo.udf.xarraydatacube.XarrayDataCube` to use as type annotation of the UDF function. +- line 3: We define a function named ``apply_datacube``, + which receives and returns a :py:class:`~openeo.udf.xarraydatacube.XarrayDataCube` instance. + We follow here the :py:meth:`~openeo.udf.udf_signatures.apply_datacube()` UDF function signature. +- line 4: ``cube`` (a :py:class:`~openeo.udf.xarraydatacube.XarrayDataCube` object) is a thin wrapper + around the data of the chunk we are currently processing. + We use :py:meth:`~openeo.udf.xarraydatacube.XarrayDataCube.get_array()` to get this data, + which is an ``xarray.DataArray`` object. +- line 5: Because our scaling operation is so simple, we can transform the ``xarray.DataArray`` values in-place. +- line 6: Consequently, because the values were updated in-place, + we don't have to build a new :py:class:`~openeo.udf.xarraydatacube.XarrayDataCube` object + and can just return the (in-place updated) ``cube`` object again. + +Workflow script +---------------- + +In this first example, we'll cite a full, standalone openEO workflow script, +including creating the back-end connection, loading the initial data cube and downloading the result. +The UDF-specific part is highlighted. + +.. warning:: + This implementation depends on :py:class:`openeo.UDF ` improvements + that were introduced in version 0.13.0 of the openeo Python Client Library. + If you are currently stuck with working with an older version, + check :ref:`old_udf_api` for more information on the difference with the old API. + +.. code-block:: python + :linenos: + :caption: UDF usage example snippet + :emphasize-lines: 14-25 + + import openeo + + # Create connection to openEO back-end + connection = openeo.connect("...").authenticate_oidc() + + # Load initial data cube. + s2_cube = connection.load_collection( + "SENTINEL2_L2A", + spatial_extent={"west": 4.00, "south": 51.04, "east": 4.10, "north": 51.1}, + temporal_extent=["2022-03-01", "2022-03-31"], + bands=["B02", "B03", "B04"] + ) + + # Create a UDF object from inline source code. + udf = openeo.UDF(""" + from openeo.udf import XarrayDataCube + + def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube: + array = cube.get_array() + array.values = 0.0001 * array.values + return cube + """) + + # Pass UDF object as child process to `apply`. + rescaled = s2_cube.apply(process=udf) + + rescaled.download("apply-udf-scaling.nc") + +In line 15, we build an :py:class:`openeo.UDF ` object +from an inline string with the UDF source code. +This :py:class:`openeo.UDF ` object encapsulates various aspects +that are necessary to create a ``run_udf`` node in the process graph, +and we can pass it directly in line 25 as the ``process`` argument +to :py:meth:`DataCube.apply() `. + +.. tip:: + + Instead of putting your UDF code in an inline string like in the example, + it's often a good idea to **load the UDF code from a separate file**, + which is easier to maintain in your preferred editor or IDE. + You can do that directly with the + :py:meth:`openeo.UDF.from_file ` method: + + .. code-block:: python + + udf = openeo.UDF.from_file("udf-code.py") + +After downloading the result, we can inspect the band values locally. +Note see that they fall mainly in a range from 0 to 1 (in most cases even below 0.2), +instead of the original digital number range (thousands): + +.. image:: _static/images/udf/apply-rescaled-histogram.png + + +UDF's that transform cube metadata +================================== +This is a new/experimental feature so may still be subject to change. + +In some cases, a UDF can have impact on the metadata of a cube, but this can not always +be easily inferred by process graph evaluation logic without running the actual +(expensive) UDF code. This limits the possibilities to validate process graphs, +or for instance make an estimate of the size of a datacube after applying a UDF. + +To provide evaluation logic with this information, the user should implement the +:py:meth:`~openeo.udf.udf_signatures.apply_metadata()` function as part of the UDF. +Please refer to the documentation of that function for more information. + +.. literalinclude:: ../examples/udf/udf_modify_spatial.py + :language: python + :caption: Example of a UDF that adjusts spatial metadata ``udf_modify_spatial.py`` + :name: spatial_udf + +To invoke a UDF like this, the apply_neighborhood method is most suitable: + +.. code-block:: python + + udf_code = Path('udf_modify_spatial.py').read_text() + cube_updated = cube.apply_neighborhood( + lambda data: data.run_udf(udf=udf_code, runtime='Python-Jep', context=dict()), + size=[ + {'dimension': 'x', 'value': 128, 'unit': 'px'}, + {'dimension': 'y', 'value': 128, 'unit': 'px'} + ], overlap=[]) + + +Illustration of data chunking in ``apply`` with a UDF +======================================================== + +TODO + +Example: ``apply_dimension`` with a UDF +======================================== + +TODO + +Example: ``reduce_dimension`` with a UDF +======================================== + +The key element for a UDF invoked in the context of `reduce_dimension` is that it should actually return +an XArray DataArray _without_ the dimension that is specified to be reduced. + +So a reduce over time would receive a DataArray with `bands,t,y,x` dimensions, and return one with only `bands,y,x`. + + +Example: ``apply_neighborhood`` with a UDF +=========================================== + +The apply_neighborhood process is generally used when working with complex AI models that require a +spatiotemporal input stack with a fixed size. It supports the ability to specify overlap, to ensure that the model +has sufficient border information to generate a spatially coherent output across chunks of the raster data cube. + +In the example below, the UDF will receive chunks of 128x128 pixels: 112 is the chunk size, while 2 times 8 pixels of +overlap on each side of the chunk results in 128. + +The time and band dimensions are not specified, which means that all values along these dimensions are passed into +the datacube. + + +.. code-block:: python + + output_cube = inputs_cube.apply_neighborhood(my_udf, size=[ + {'dimension': 'x', 'value': 112, 'unit': 'px'}, + {'dimension': 'y', 'value': 112, 'unit': 'px'} + ], overlap=[ + {'dimension': 'x', 'value': 8, 'unit': 'px'}, + {'dimension': 'y', 'value': 8, 'unit': 'px'} + ]) + +Example: Smoothing timeseries with a user defined function (UDF) +================================================================== + +In this example, we start from the ``evi_cube`` that was created in the previous example, and want to +apply a temporal smoothing on it. More specifically, we want to use the "Savitzky Golay" smoother +that is available in the SciPy Python library. + + +To ensure that openEO understand your function, it needs to follow some rules, the UDF specification. +This is an example that follows those rules: + +.. literalinclude:: ../examples/udf/smooth_savitzky_golay.py + :language: python + :caption: Example UDF code ``smooth_savitzky_golay.py`` + :name: savgol_udf + +The method signature of the UDF is very important, because the back-end will use it to detect +the type of UDF. +This particular example accepts a :py:class:`~openeo.rest.datacube.DataCube` object as input and also returns a :py:class:`~openeo.rest.datacube.DataCube` object. +The type annotations and method name are actually used to detect how to invoke the UDF, so make sure they remain unchanged. + + +Once the UDF is defined in a separate file, we load it +and apply it along a dimension: + +.. code-block:: python + + smoothing_udf = openeo.UDF.from_file('smooth_savitzky_golay.py') + smoothed_evi = evi_cube_masked.apply_dimension(smoothing_udf, dimension="t") + + +Downloading a datacube and executing an UDF locally +============================================================= + +Sometimes it is advantageous to run a UDF on the client machine (for example when developing/testing that UDF). +This is possible by using the convenience function :py:func:`openeo.udf.run_code.execute_local_udf`. +The steps to run a UDF (like the code from ``smooth_savitzky_golay.py`` above) are as follows: + +* Run the processes (or process graph) preceding the UDF and download the result in 'NetCDF' or 'JSON' format. +* Run :py:func:`openeo.udf.run_code.execute_local_udf` on the data file. + +For example:: + + from pathlib import Path + from openeo.udf import execute_local_udf + + my_process = connection.load_collection(... + + my_process.download('test_input.nc', format='NetCDF') + + smoothing_udf = Path('smooth_savitzky_golay.py').read_text() + execute_local_udf(smoothing_udf, 'test_input.nc', fmt='netcdf') + +Note: this algorithm's primary purpose is to aid client side development of UDFs using small datasets. It is not designed for large jobs. + +UDF dependency management +========================= + +Most UDF's have dependencies, because they often are used to run complex algorithms. Typical dependencies like numpy and +XArray can be assumed to be available, but others may be more specific for you. + +This part is probably the least standardized in the definition of UDF's, and may be backend specific. +We include some general pointers here: + +- Python dependencies can be packaged fairly easily by zipping a Python virtual environment. +- For some dependencies, it can be important that the Python major version of the virtual environment is the same as the one used by the backend. +- Python allows you to dynamically append (or prepend) libraries to the search path: `sys.path.append("unzipped_virtualenv_location")` + + + +Profile a process server-side +============================== + + +.. warning:: + Experimental feature - This feature only works on back-ends running the Geotrellis implementation, and has not yet been + adopted in the openEO API. + +Sometimes users want to 'profile' their UDF on the back-end. While it's recommended to first profile it offline, in the +same manner as you can debug UDF's, back-ends may support profiling directly. +Note that this will only generate statistics over the python part of the execution, therefore it is only suitable for profiling UDFs. + +Usage +------ + +Only batch jobs are supported! In order to turn on profiling, set 'profile' to 'true' in job options:: + + job_options={'profile':'true'} + ... # prepare the process + process.execute_batch('result.tif',job_options=job_options) + +When the process has finished, it will also download a file called 'profile_dumps.tar.gz': + +- ``rdd_-1.pstats`` is the profile data of the python driver, +- the rest are the profiling results of the individual rdd id-s (that can be correlated with the execution using the SPARK UI). + +Viewing profiling information +------------------------------ + +The simplest way is to visualize the results with a graphical visualization tool called kcachegrind. +In order to do that, install `kcachegrind `_ packages (most linux distributions have it installed by default) and it's python connector `pyprof2calltree `_. +From command line run:: + + pyprof2calltree rdd_.pstats. + +Another way is to use the builtin pstats functionality from within python:: + + import pstats + p = pstats.Stats('restats') + p.print_stats() + +Example +------- + + +An example code can be found `here `_ . + + + +.. _udf_logging_with_inspect: + +Logging from a UDF +===================== + +In some cases, you may want to log information from your user defined function, +for instance to provide debug information or to log warnings. You can use the :py:class:`~openeo.udf.debug.inspect` +logging function to achieve this. + +For example, in the previous example of rescaling an RGB image(from SENTINEL2_L2A), suppose you +want to keep a log of array shape encountered within a UDF:: + + # Create a UDF object from inline source code. + udf = openeo.UDF(""" + from openeo.udf import XarrayDataCube + from openeo.udf.debug import inspect + + def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube: + array = cube.get_array() + inspect(data=[array.shape], message="UDF logging shape of my array") + array.values = 0.0001 * array.values + return cube + """) + +If you are using Jupyter Notebook, you can see the log entries using :py:class:`~openeo.rest.job.BatchJob.logs` +as shown in the image: + +.. image:: _static/images/udf/logging_arrayshape.png + +Please note that this nice rendering only happens in Jupyter Notebook, while in plain Python you will get a dict. + +Thus, an array of shape 3x256x256 was logged in on which rescaling was performed. [Please note that at this moment, +this method is experimental and does not support all data types in ``data`` argument of :py:class:`~openeo.udf.debug.inspect`] + + +.. _old_udf_api: + +``openeo.UDF`` API and usage changes in version 0.13.0 +======================================================== + +Prior to version 0.13.0 of the openEO Python Client Library, +loading and working with UDFs was a bit inconsistent and cumbersome. + +- The old ``openeo.UDF()`` required an explicit ``runtime`` argument, which was usually ``"Python"``. + In the new :py:class:`openeo.UDF `, the ``runtime`` argument is optional, + and it will be auto-detected (from the source code or file extension) when not given. +- The old ``openeo.UDF()`` required an explicit ``data`` argument, and figuring out the correct + value (e.g. something like ``{"from_parameter": "x"}``) required good knowledge of the openEO API and processes. + With the new :py:class:`openeo.UDF ` it is not necessary anymore to provide + the ``data`` argument. In fact, while the ``data`` argument is only still there for compatibility reasons, + it is unused and it will be removed in a future version. + A deprecation warning will be triggered when ``data`` is given a value. +- :py:meth:`DataCube.apply_dimension() ` has direct UDF support through + ``code`` and ``runtime`` arguments, preceding the more generic and standard ``process`` argument, while + comparable methods like :py:meth:`DataCube.apply() ` + or :py:meth:`DataCube.reduce_dimension() ` + only support a ``process`` argument with no dedicated arguments for UDFs. + + The goal is to improve uniformity across all these methods and use a generic ``process`` argument everywhere + (that also supports a :py:class:`openeo.UDF ` object for UDF use cases). + For now, the ``code``, ``runtime`` and ``version`` arguments are still present + in :py:meth:`DataCube.apply_dimension() ` + as before, but usage is deprecated. + + Simple example to sum it up: + + .. code-block:: python + + udf_code = """ + ... + def apply_datacube(cube, ... + """ + + # Legacy `apply_dimension` usage: still works for now, + # but it will trigger a deprecation warning. + cube.apply_dimension(code=udf_code, runtime="Python", dimension="t") + + # New, preferred approach with a standard `process` argument. + udf = openeo.UDF(udf_code) + cube.apply_dimension(process=udf, dimension="t") + + # Unchanged: usage of other apply/reduce/... methods + cube.apply(process=udf) + cube.reduce_dimension(reducer=udf, dimension="t") diff --git a/_sources/udp.rst.txt b/_sources/udp.rst.txt new file mode 100644 index 000000000..a04e9da5c --- /dev/null +++ b/_sources/udp.rst.txt @@ -0,0 +1,514 @@ +.. _user-defined-processes: + +*********************** +User-Defined Processes +*********************** + + +Code reuse with user-defined processes +======================================= + +As explained before, processes can be chained together in a process graph +to build a certain algorithm. +Often, you have certain (sub)chains that reoccur in the same process graph +of even in different process graphs or algorithms. + +The openEO API enables you to store such (sub)chains +on the back-end as a so called **user-defined process**. +This allows you to build your own *library of reusable building blocks*. + +.. warning:: + + Do not confuse **user-defined processes** (sometimes abbreviated as UDP) with + **user-defined functions** (UDF) in openEO, which is a mechanism to + inject Python or R scripts as process nodes in a process graph. + See :ref:`user-defined-functions` for more information. + +A user-defined process can not only be constructed from +pre-defined processes provided by the back-end, +but also other user-defined processes. + +Ultimately, the openEO API allows you to publicly expose your user-defined process, +so that other users can invoke it as a service. +This turns your openEO process into a web application +that can be executed using the regular openEO +support for synchronous and asynchronous jobs. + + +Process Parameters +==================== + +User-defined processes are usually **parameterized**, +meaning certain inputs are expected when calling the process. + +For example, if you often have to convert Fahrenheit to Celsius:: + + c = (f - 32) / 1.8 + +you could define a user-defined process ``fahrenheit_to_celsius``, +consisting of two simple mathematical operations +(pre-defined processes ``subtract`` and ``divide``). + +We can represent this in openEO's JSON based format as follows +(don't worry too much about the syntax details of this representation, +the openEO Python client will hide this usually):: + + + { + "subtract32": { + "process_id": "subtract", + "arguments": {"x": {"from_parameter": "fahrenheit"}, "y": 32} + }, + "divide18": { + "process_id": "divide", + "arguments": {"x": {"from_node": "subtract32"}, "y": 1.8}, + "result": true + } + } + + +The important point here is the parameter reference ``{"from_parameter": "fahrenheit"}`` in the subtraction. +When we call this user-defined process we will have to provide a Fahrenheit value. +For example with 70 degrees Fahrenheit (again in openEO JSON format here):: + + { + "process_id": "fahrenheit_to_celsius", + "arguments" {"fahrenheit": 70} + } + + +Declaring Parameters +--------------------- + +It's good style to declare what parameters your user-defined process expects and supports. +It allows you to document your parameters, define the data type(s) you expect +(the "schema" in openEO-speak) and define default values. + +The openEO Python client lets you define parameters as +:class:`~openeo.api.process.Parameter` instances. +In general you have to specify at least the parameter name, +a description and a schema (to declare the expected parameter type). +The "fahrenheit" parameter from the example above can be defined like this:: + + from openeo.api.process import Parameter + + fahrenheit_param = Parameter( + name="fahrenheit", + description="Degrees Fahrenheit", + schema={"type": "number"} + ) + +To simplify working with parameter schemas, the :class:`~openeo.api.process.Parameter` class +provides a couple of helpers to create common types of parameters. +In the example above, the "fahrenheit" parameter (a number) can also be created more compactly +with the :py:meth:`Parameter.number() ` helper:: + + fahrenheit_param = Parameter.number( + name="fahrenheit", description="Degrees Fahrenheit" + ) + +Some useful parameter helpers (class methods of the :py:class:`~openeo.api.process.Parameter` class): + +- :py:meth:`Parameter.string() ` + to create a string parameter, + e.g. to parameterize the collection id in a ``load_collection`` call in your UDP. +- :py:meth:`Parameter.integer() `, + :py:meth:`Parameter.number() `, + and :py:meth:`Parameter.boolean() ` + to create integer, floating point, or boolean parameters respectively. +- :py:meth:`Parameter.array() ` + to create an array parameter, + e.g. to parameterize the a band selection in a ``load_collection`` call in your UDP. +- :py:meth:`Parameter.datacube() ` + (or its legacy, deprecated cousin :py:meth:`Parameter.raster_cube() `) + to create a data cube parameter. + +Consult the documentation of these helper class methods for additional features. +For example, declaring a default value for an integer parameter:: + + size_param = Parameter.integer( + name="size", description="Kernel size", default=4 + ) + + + +More advanced parameter schemas +-------------------------------- + +While the helper class methods of :py:class:`~openeo.api.process.Parameter` (discussed above) +cover the most common parameter usage, +you also might need to declare some parameters with a more special or specific schema. +You can do that through the ``schema`` argument +of the basic :py:class:`~openeo.api.process.Parameter()` constructor. +This "schema" argument follows the `JSON Schema draft-07 `_ specification, +which we will briefly illustrate here. + +Basic primitives can be declared through a (required) "type" field, for example: +``{"type": "string"}`` for strings, ``{"type": "integer"}`` for integers, etc. + +Likewise, arrays can be defined with a minimal ``{"type": "array"}``. +In addition, the expected type of the array items can also be specified, +e.g. an array of integers:: + + { + "type": "array", + "items": {"type": "integer"} + } + +Another, more complex type is ``{"type": "object"}`` for parameters +that are like Python dictionaries (or mappings). +For example, to define a bounding box parameter +that should contain certain fields with certain type:: + + { + "type": "object", + "properties": { + "west": {"type": "number"}, + "south": {"type": "number"}, + "east": {"type": "number"}, + "north": {"type": "number"}, + "crs": {"type": "string"} + } + } + +Check the documentation and examples of `JSON Schema draft-07 `_ +for even more features. + +On top of these generic types, the openEO API also defines a couple of custom (sub)types +in the `openeo-processes project `_ +(see the ``meta/subtype-schemas.json`` listing). +For example, the schema of an openEO data cube is:: + + { + "type": "object", + "subtype": "datacube" + } + + + +.. _build_and_store_udp: + +Building and storing user-defined process +============================================= + +There are a couple of ways to build and store user-defined processes: + +- using predefined :ref:`process functions ` +- :ref:`parameterized building of a data cube ` +- :ref:`directly from a well-formatted dictionary ` process graph representation + + + +.. _create_udp_through_process_functions: + +Through "process functions" +---------------------------- + +The openEO Python Client Library defines the +official processes in the :py:mod:`openeo.processes` module, +which can be used to build a process graph as follows:: + + from openeo.processes import subtract, divide + from openeo.api.process import Parameter + + # Define the input parameter. + f = Parameter.number("f", description="Degrees Fahrenheit.") + + # Do the calculations, using the parameter and other values + fahrenheit_to_celsius = divide(x=subtract(x=f, y=32), y=1.8) + + # Store user-defined process in openEO back-end. + connection.save_user_defined_process( + "fahrenheit_to_celsius", + fahrenheit_to_celsius, + parameters=[f] + ) + + +The ``fahrenheit_to_celsius`` object encapsulates the subtract and divide calculations in a symbolic way. +We can pass it directly to :py:meth:`~openeo.rest.connection.Connection.save_user_defined_process`. + + +If you want to inspect its openEO-style process graph representation, +use the :meth:`~openeo.rest.datacube.DataCube.to_json()` +or :meth:`~openeo.rest.datacube.DataCube.print_json()` method:: + + >>> fahrenheit_to_celsius.print_json() + { + "process_graph": { + "subtract1": { + "process_id": "subtract", + "arguments": { + "x": { + "from_parameter": "f" + }, + "y": 32 + } + }, + "divide1": { + "process_id": "divide", + "arguments": { + "x": { + "from_node": "subtract1" + }, + "y": 1.8 + }, + "result": true + } + } + } + + +.. _create_udp_parameterized_cube: + +From a parameterized data cube +------------------------------- + +It's also possible to work with a :class:`~openeo.rest.datacube.DataCube` directly +and parameterize it. +Let's create, as a simple but functional example, a custom ``load_collection`` +with hardcoded collection id and band name +and a parameterized spatial extent (with default):: + + spatial_extent = Parameter( + name="bbox", + schema="object", + default={"west": 3.7, "south": 51.03, "east": 3.75, "north": 51.05} + ) + + cube = connection.load_collection( + "SENTINEL2_L2A_SENTINELHUB", + spatial_extent=spatial_extent, + bands=["B04"] + ) + +Note how we just can pass :class:`~openeo.api.process.Parameter` objects as arguments +while building a :class:`~openeo.rest.datacube.DataCube`. + +.. note:: + + Not all :class:`~openeo.rest.datacube.DataCube` methods/processes properly support + :class:`~openeo.api.process.Parameter` arguments. + Please submit a bug report when you encounter missing or wrong parameterization support. + +We can now store this as a user-defined process called "fancy_load_collection" on the back-end:: + + connection.save_user_defined_process( + "fancy_load_collection", + cube, + parameters=[spatial_extent] + ) + +If you want to inspect its openEO-style process graph representation, +use the :meth:`~openeo.rest.datacube.DataCube.to_json()` +or :meth:`~openeo.rest.datacube.DataCube.print_json()` method:: + + >>> cube.print_json() + { + "loadcollection1": { + "process_id": "load_collection", + "arguments": { + "id": "SENTINEL2_L2A_SENTINELHUB", + "bands": [ + "B04" + ], + "spatial_extent": { + "from_parameter": "bbox" + }, + "temporal_extent": null + }, + "result": true + } + } + + + +.. _create_udp_from_dict: + +Using a predefined dictionary +------------------------------ + +In some (advanced) situation, you might already have +the process graph in dictionary format +(or JSON format, which is very close and easy to transform). +Another developer already prepared it for you, +or you prefer to fine-tune process graphs in a JSON editor. +It is very straightforward to submit this as a user-defined process. + +Say we start from the following Python dictionary, +representing the Fahrenheit to Celsius conversion we discussed before:: + + fahrenheit_to_celsius = { + "subtract1": { + "process_id": "subtract", + "arguments": {"x": {"from_parameter": "f"}, "y": 32} + }, + "divide1": { + "process_id": "divide", + "arguments": {"x": {"from_node": "subtract1"}, "y": 1.8}, + "result": True + }} + +We can store this directly, taking into account that we have to define +a parameter named ``f`` corresponding with the ``{"from_parameter": "f"}`` argument +from the dictionary above:: + + connection.save_user_defined_process( + user_defined_process_id="fahrenheit_to_celsius", + process_graph=fahrenheit_to_celsius, + parameters=[Parameter.number(name="f", description="Degrees Fahrenheit")] + ) + + +Store to a file +--------------- + +Some use cases might require storing the user-defined process in, +for example, a JSON file instead of storing it directly on a back-end. +Use :py:func:`~openeo.rest.udp.build_process_dict` to build a dictionary +compatible with the "process graph with metadata" format of the openEO API +and dump it in JSON format to a file:: + + import json + from openeo.rest.udp import build_process_dict + from openeo.processes import subtract, divide + from openeo.api.process import Parameter + + fahrenheit = Parameter.number("f", description="Degrees Fahrenheit.") + fahrenheit_to_celsius = divide(x=subtract(x=fahrenheit, y=32), y=1.8) + + spec = build_process_dict( + process_id="fahrenheit_to_celsius", + process_graph=fahrenheit_to_celsius, + parameters=[fahrenheit] + ) + + with open("fahrenheit_to_celsius.json", "w") as f: + json.dump(spec, f, indent=2) + +This results in a JSON file like this:: + + { + "id": "fahrenheit_to_celsius", + "process_graph": { + "subtract1": { + "process_id": "subtract", + ... + "parameters": [ + { + "name": "f", + ... + + +.. _evaluate_udp: + +Evaluate user-defined processes +================================ + +Let's evaluate the user-defined processes we defined. + +Because there is no pre-defined +wrapper function for our user-defined process, we use the +generic :func:`openeo.processes.process` function to build a simple +process graph that calls our ``fahrenheit_to_celsius`` process:: + + >>> pg = openeo.processes.process("fahrenheit_to_celsius", f=70) + >>> pg.print_json(indent=None) + {"process_graph": {"fahrenheittocelsius1": {"process_id": "fahrenheit_to_celsius", "arguments": {"f": 70}, "result": true}}} + + >>> res = connection.execute(pg) + >>> print(res) + 21.11111111111111 + + +To use our custom ``fancy_load_collection`` process, +we only have to specify a temporal extent, +and let the predefined and default values do their work. +We will use :func:`~openeo.rest.connection.Connection.datacube_from_process` +to construct a :class:`~openeo.rest.datacube.DataCube` object +which we can process further and download:: + + cube = connection.datacube_from_process("fancy_load_collection") + cube = cube.filter_temporal("2020-09-01", "2020-09-10") + cube.download("fancy.tiff", format="GTiff") + +See :ref:`datacube_from_process` for more information on :func:`~openeo.rest.connection.Connection.datacube_from_process`. + + +.. _udp_example_evi: + +UDP Example: EVI timeseries +========================================== + +In this UDP example, we'll build a reusable UDP ``evi_timeseries`` +to calculate the EVI timeseries for a given geometry. +It's a simplified version of the EVI workflow laid out in :ref:`basic_example_evi_map_and_timeseries`, +focussing on the UDP-specific aspects: defining and using parameters; +building, storing, and finally executing the UDP. + +.. code-block:: python + + import openeo + from openeo.api.process import Parameter + + # Create connection to openEO back-end + connection = openeo.connect("...").authenticate_oidc() + + # Declare the UDP parameters + temporal_extent = Parameter( + name="temporal_extent", + description="The date range to calculate the EVI for.", + schema={"type": "array", "subtype": "temporal-interval"}, + default =["2018-06-15", "2018-06-27"] + ) + geometry = Parameter( + name="geometry", + description="The geometry (a single (multi)polygon or a feature collection of (multi)polygons) of to calculate the EVI for.", + schema={"type": "object", "subtype": "geojson"} + ) + + # Load raw SENTINEL2_L2A data + sentinel2_cube = connection.load_collection( + "SENTINEL2_L2A", + temporal_extent=temporal_extent, + bands=["B02", "B04", "B08"], + ) + + # Extract spectral bands and calculate EVI with the "band math" feature + blue = sentinel2_cube.band("B02") * 0.0001 + red = sentinel2_cube.band("B04") * 0.0001 + nir = sentinel2_cube.band("B08") * 0.0001 + evi = 2.5 * (nir - red) / (nir + 6.0 * red - 7.5 * blue + 1.0) + + evi_aggregation = evi.aggregate_spatial( + geometries=geometry, + reducer="mean", + ) + + # Store the parameterized user-defined process at openEO back-end. + process_id = "evi_timeseries" + connection.save_user_defined_process( + user_defined_process_id=process_id, + process_graph=evi_aggregation, + parameters=[temporal_interval, geometry], + ) + +When this UDP ``evi_timeseries`` is successfully stored on the back-end, +we can use it through :func:`~openeo.rest.connection.Connection.datacube_from_process` +to get the EVI timeseries of a desired geometry and time window: + +.. code-block:: python + + time_window = ["2020-01-01", "2021-12-31"] + geometry = { + "type": "Polygon", + "coordinates": [[[5.1793, 51.2498], [5.1787, 51.2467], [5.1852, 51.2450], [5.1867, 51.2453], [5.1873, 51.2491], [5.1793, 51.2498]]], + } + + evi_timeseries = connection.datacube_from_process( + process_id="evi_timeseries", + temporal_extent=time_window, + geometry=geometry, + ) + + evi_timeseries.download("evi-aggregation.json") diff --git a/_static/alabaster.css b/_static/alabaster.css new file mode 100644 index 000000000..e6ba80ee2 --- /dev/null +++ b/_static/alabaster.css @@ -0,0 +1,703 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Cantarell, Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 1200px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 300px; +} + +div.sphinxsidebar { + width: 300px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 1200px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Cantarell, Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Cantarell, Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Cantarell, Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Cantarell, Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Liberation Mono', 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 000000000..30fee9d0f --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 000000000..5e48835fc --- /dev/null +++ b/_static/custom.css @@ -0,0 +1,139 @@ +/* + * Customization of Alabaster theme + * per https://alabaster.readthedocs.io/en/latest/customization.html#custom-stylesheet + */ + +/* "Quick Search" should be capitalized. */ +div#searchbox h3 { + text-transform: capitalize; +} + +/* Much-improved spacing around code blocks. */ +div.highlight pre { + padding: 1ex; +} + +/* Reduce space between paragraphs for better visual structure */ +p { + margin: 1ex 0; +} + +/* Hide "view source code" links by default, only show on hover */ +dt .viewcode-link { + visibility: hidden; + font-size: 70%; +} + +dt:hover .viewcode-link { + visibility: visible; +} + +/* More breathing space between successive methods */ +dl { + margin-bottom: 1.5em; +} + +dl.field-list > dt { + /* Cleaner aligning of Parameters/Returns/Raises listing with method description paragraphs */ + padding-left: 0; + /* Make Parameters/Returns/Raises labels less dominant */ + text-transform: uppercase; + font-size: 70%; +} + +.sidebar-meta { + font-size: 80%; +} + +div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { + margin: 1.5em 0 0.5em 0; +} + +div.body h1 { + margin: 0 0 0.5em 0; +} + +.toctree-l1 { + padding: 0.1em 0.5em; + margin-left: -0.5em; +} + +div.sphinxsidebar .toctree-l1 a { + border: none; +} + +.toctree-l1.current { + background-color: #f3f5f7; + border-right: 0.5rem solid #a2cedb; +} + + +div.admonition, +div.versionadded, +.py div.versionchanged, +.py div.deprecated { + padding: 0.5em 1em; + border-style: solid; + border-width: 0 0 0 0.5rem; + border-color: #cccccc; + background-color: #f3f5f7; +} + +div.admonition :first-child, +div.versionadded :first-child, +.py div.versionchanged :first-child, +.py div.deprecated :first-child { + margin-top: 0; +} + + +div.admonition :last-child, +div.versionadded :last-child, +.py div.versionchanged :last-child, +.py div.deprecated :last-child { + margin-bottom: 0; +} + +div.admonition p.admonition-title { + font-size: 80%; + text-transform: uppercase; + font-weight: bold; +} + +div.admonition.note, +div.admonition.tip, +div.admonition.seealso, +div.admonition.hint, +div.versionadded, +.py div.versionchanged { + border-left-color: #42b983; +} + +div.admonition.warning, +div.admonition.attention, +div.admonition.caution, +div.admonition.danger, +div.admonition.error, +div.admonition.important, +.py div.deprecated { + border-left-color: #b9425e; +} + + +pre { + background-color: #e2f0f4; +} + +.highlight-default, .highlight-python, .highlight-pycon, .highlight-shell , .highlight-text { + border-right: 0.5rem solid #a2cedb; +} + +.highlight span.linenos { + color: #888; + font-size: 75%; + padding: 0 1ex; +} + +nav.contents.local { + border: none; +} diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 000000000..d06a71d75 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 000000000..7bc11d3ac --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.26.0a1', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/_static/images/basics/evi-composite.png b/_static/images/basics/evi-composite.png new file mode 100644 index 0000000000000000000000000000000000000000..5680bf03e55509af77051f8fd0fa483ca5337578 GIT binary patch literal 31940 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
    !G}{+Y9*fOR|| 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≪02CyINip zv#Yi6w%l!gj|KdVc0UhheJ@=f_8JG}FI8v!Pga{QhXwXc`g-k& zINF%wZqF=UtGnLsfty4bXH1pBbsP!%ziXVd{mz>|GGB-FoeK*mh~Sc~ruJQSUP40ODG5U)C|4Ul^&L~=Daey&wj zMftFLzyH8rKAeKCL|FTVgi+}(tCsuzwzsWqDMozJq4yDWcXyWw5Yk3FV})arlL%^n zkv`iVZHi&}pKjn|o?J|(6L|elk~ z^t|k!`hW6lZub5gspdmERo0X2PEJmMGB?>C`QCi9^OKjKe`IRv56qa4d{=~?u%S9? z#FgsM$PPykvA~FQEG#TSV&W>`k70QNSiTFm3??QfV7Cq6meQ`$7q#T?MVZ?693h;NY=K&={3e5J!6b&rSQ&-ia23bF#7>R(&@D&PQ zZyP9nSLSFwf5Z++kUA0oXS@+Zf!ALYIC2vuo8e`ziQ>-Nrd^QnDGGncSOiO5V)$js|B^FNDob zH~y}zuUGg#`T=P`hwtUQfF6f`uWjR2E^G>MS|9HZwSg`M)-ws(tPEFDQgXM10$Hl; zV<#WJ_%@RdP#sJI1C9}sFZf>Sw}Ag26PwxEl1VO*-!Wb9O@aebjYxp| zqT({r6BW`+n@t8_%(t_MM@vCCPK&;mc<3Rr)nbLU+vbp4QujGW z6tG+1=DWT?E0qx&FPOVDUa@>2SYH|bt8&7M54f*-QQuv>!XTmwbi@45^l z2UzRg&Q#kkieK!{LbD#WvnoA~SB(EMyB68r04>qqLH`Hmh|ixJ06e-Hj`8EowIx$% z%o3pK?4(T%628CNgqQ=2cy}||N;T>Rve9Cfa~-3q5V8Dy!PHg3x0;$&&YLRO)Z+c? z$%X?!gM{Mb>4QmxIxet)F@dQG#(W>a z+$p8=+qRifKyw-zQUe16m#uy?)u1hbv-OZ`a7-E6$I+_9NkUO^@ogl3VnSoVbCVM0 zNfZYs+KWjk(dED&^{Wo>FTG))*`q0C#sx{m50J z6&V^Dif28l_U67BjfTF~7$YOuz>5il3otc+^z(Kg4PfHnICOM|> zg>gS2@e1j%MFoTRCntRzF<15a%(lHfJvkswNJ}HLva-@@_Tb`Zy*v3tkEgmW3XX`~ z6M^sm@ot9}STR#DD$|*K=RvV#u#T`kUM_gYXt8#K=0tME%2MFAo2llR64rl9^_%{H zi~jgw(LV#!6{H;#@2s_-s)`;XDkigcx$1-6*A<9_0fViu3>}z(Ij26hIgiySunFU` zvIfCJgzc`YHYkHTaDX(L&+%tN#5;~v7>HDw<(+wBISP!iCqN&mz#ag}%9LqLl!d(n zGcfU%1cukWnm>w*K`kWMyUz9hRPsNM6}?DRf_DHFryc+DO_qb~bZ>9(C+X*+=VR(G zCZ5uCPQ@j9OJ>jwtR;F^ZaBDn-QK>YUC#uVjVls>seedool)`=npETaE)M|EKA~BG z#XJZ0e|>3RN!>y(NIgLtG$N0Tfeuso&rO+Ikqi0Z0)BM!^dLriywu zAB%CGL${$Z!(-sfM`qa7ewecxW{V^rdSCs|A|yxp@_|65iRgd*I=2qe|rtXyUt*1Qraz;CFnSXc2e}bUUH>1Z| zVU%XGU0`@1h*b{H1U|mGUNVyM-#rS~PKYEUF}I6|OyJ2FlMki2sG4G+ff*=^(jqwV zKQ;bAQJ3-mi8f6-0VE7+aNc|a0(k%gZ}wt<;t#a30PoXr`a|+-b#v743wf&H#`w z*Ym~^_?G`4c38HAQm8NkIhfDDz&%)t=7`Rf7;TniSKf- zT#59V5(Wt>V&f?MMKy?EK)8a|R{5dN188ytM>kmVou~$oVHgqURuB#r|A*}(09t~) zso!Jr0K!LpdKiJ9n3%x!i2QGnSjB7G%~y)+qHxV1c!T*Qz;c``*g4j|Iv0&Xfx&;1 z$oqA}2RZ;i??BvZ-V;wZueogE6A$n`30~nhq&?5bRY6_>0d+Ms&Z2z^%fgJXz(9DQ zv4g8y@M3Ab-?x{miCS%!R(QemZ_?h#V`%+{kSI#VSx$+0GiOt40a&R1X3taErc~3? z=H?9ZOi$zzz9zT*=L`&Cxw*L&b{eg)4PYXTnfUYwU=|Y~bx2H3cJ5=VgSB!4Z(Y_8 zoSmw(1JNN))7ya#9RDjR1HbDJtbNZRkSy@dL0~Pmr%|lc4wwW>3ybXf`V`mQi8v+t zC-wWav;Ps_7IN7gxBb_ii$eyh@&6tP{dbtu_Zoy!h^hHKNW^+WzW%`Zb*?%Bf$HvL z+2O(iAWfx*v$m-eDWQJ-|`ORIssxlny);fEYkjO3|ySPH!f!V zDeYzc_tpkp+jIuN>Q~sszlwwHw@wo63X^}bQecAt-i&c|mX3fKqfS&|&q!yGF`mC| z0d+}E4w?=X1ojbMjDz_AQRE+@f3fEO77PC01H}h_2vby|*jMTcpJ#MrhI`LFXYaMwT4$dSl@Bu57$g`dC@9!+vXUQBP@W)xm(&Y1;3p*SD0G2; zo;kmlQ-1;c@p@tU9r!;nR7xAF=3owWGj=jVv9NcrGh=l&aWXTrceZqZ9-_8EfG@E< zeo4Z~%ou9rU{9%TWoL#W?PNvC#X~9YVo%A%!No<%At1!fA;il;siH(FA*H5HLwLA_ zfJ(p0d~C;iZ1o^6(&1WuCql6~PkVt!j!}o%Lx_UaxRc*R7<)(x&ZfdfuVV zMlT-LN?Dg4N3?D|0q{Jqg*6v}Z zZ>{|`iAm(>F=pZ%DgB>DC9W6_XM>4L>{_gSJ>pplin!)3{7&$*4#Oue; z6`$sa#{(aQn7*dOZv4+L#G+Wi=^j5!d?xG979Gw>sQ=|jr0Drfl+jk2=fTSLZW%?; z8|+kzG>@P#_Ez`ec-&}{o*&Uae+Cp5nzZ1Dm}*A>w+VT#s*1~(9FdoomvKYLsvD5S zsIH+AG1QLsXR1VxGf|P2j_�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 ZIW$3#!(*ed#}NYlR1`E3MRHHy{vWgV6Bqyh literal 0 HcmV?d00001 diff --git a/_static/images/batchjobs-jupyter-created.png b/_static/images/batchjobs-jupyter-created.png new file mode 100644 index 0000000000000000000000000000000000000000..8dd25f34c04ba92c79540389a4291640ae846cc0 GIT binary patch literal 56503 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 Wz52be*Am1(Sgo-AL;CVh5B~$w`zC?_ literal 0 HcmV?d00001 diff --git a/_static/images/batchjobs-jupyter-listing.png b/_static/images/batchjobs-jupyter-listing.png new file mode 100644 index 0000000000000000000000000000000000000000..6e94d16b17d2ab58919e7b8ff894dc5d0f4183b5 GIT binary patch literal 46962 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" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/api-processbuilder.html b/api-processbuilder.html new file mode 100644 index 000000000..57b8dc2c7 --- /dev/null +++ b/api-processbuilder.html @@ -0,0 +1,194 @@ + + + + + + + + <no title> — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    The ProcessBuilder class +is a helper class that implements +(much like the openEO process functions) +each openEO process as a method. +On top of that it also adds syntactic sugar to support Python operators as well +(e.g. + is translated to the add process).

    +
    +

    Attention

    +

    As normal user, you should never create a +ProcessBuilder instance +directly.

    +

    You should only interact with this class inside a callback +function/lambda while building a child callback process graph +as discussed at Callback as a callable.

    +
    +

    For example, let’s start from this simple usage snippet +where we want to reduce the temporal dimension +by taking the temporal mean of each timeseries:

    +
    def my_reducer(data):
    +    return data.mean()
    +
    +cube.reduce_dimension(reducer=my_reducer, dimension="t")
    +
    +
    +

    Note that this my_reducer function has a data argument, +which conceptually corresponds to an array of pixel values +(along the temporal dimension). +However, it’s important to understand that the my_reducer function +is actually not evaluated when you execute your process graph +on an openEO back-end, e.g. as a batch jobs. +Instead, my_reducer is evaluated +while building your process graph client-side +(at the time you execute that cube.reduce_dimension() statement to be precise). +This means that that data argument is actually not a concrete array of EO data, +but some kind of virtual placeholder, +a ProcessBuilder instance, +that keeps track of the operations you intend to do on the EO data.

    +

    To make that more concrete, it helps to add type hints +which will make it easier to discover what you can do with the argument +(depending on which editor or IDE you are using):

    +
    from openeo.processes import ProcessBuilder
    +
    +def my_reducer(data: ProcessBuilder) -> ProcessBuilder:
    +    return data.mean()
    +
    +cube.reduce_dimension(reducer=my_reducer, dimension="t")
    +
    +
    +

    Because ProcessBuilder methods +return new ProcessBuilder instances, +and because it support syntactic sugar to use Python operators on it, +and because openeo.process functions +also accept and return ProcessBuilder instances, +we can mix methods, functions and operators in the callback function like this:

    +
    from openeo.processes import ProcessBuilder, cos
    +
    +def my_reducer(data: ProcessBuilder) -> ProcessBuilder:
    +    return cos(data.mean()) + 1.23
    +
    +cube.reduce_dimension(reducer=my_reducer, dimension="t")
    +
    +
    +

    or compactly, using an anonymous lambda expression:

    +
    from openeo.processes import cos
    +
    +cube.reduce_dimension(
    +    reducer=lambda data: cos(data.mean())) + 1.23,
    +    dimension="t"
    +)
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/api-processes.html b/api-processes.html new file mode 100644 index 000000000..b8fc88e3d --- /dev/null +++ b/api-processes.html @@ -0,0 +1,8523 @@ + + + + + + + + API: openeo.processes — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    API: openeo.processes

    +

    The openeo.processes module contains building blocks and helpers +to construct so called “child callbacks” for openEO processes like +openeo.rest.datacube.DataCube.apply() and +openeo.rest.datacube.DataCube.reduce_dimension(), +as discussed at Callback as a callable.

    +
    +

    Note

    +

    The contents of the openeo.processes module is automatically compiled +from the official openEO process specifications. +Developers that want to fix bugs in, or add implementations to this +module should not touch the file directly, but instead address it in the +upstream openeo-processes repository +or in the internal tooling to generate this file.

    +
    + +
    +

    Functions in openeo.processes

    +

    The openeo.processes module implements (at top-level) +a regular Python function for each openEO process +(not only the official stable ones, but also experimental ones in “proposal” state).

    +

    These functions can be used directly as child callback, +for example as follows:

    +
    from openeo.processes import absolute, max
    +
    +cube.apply(absolute)
    +cube.reduce_dimension(max, dimension="t")
    +
    +
    +

    Note how the signatures of the parent DataCube methods +and the callback functions match up:

    + +
    +
    +openeo.processes.absolute(x)[source]
    +

    Absolute value

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed absolute value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “absolute”.

    +
    +
    + +
    +
    +openeo.processes.add(x, y)[source]
    +

    Addition of two numbers

    +
    +
    Parameters:
    +
      +
    • x – The first summand.

    • +
    • y – The second summand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sum of the two numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “add”.

    +
    +
    + +
    +
    +openeo.processes.add_dimension(data, name, label, type=<object object>)[source]
    +

    Add a new dimension

    +
    +
    Parameters:
    +
      +
    • data – A data cube to add the dimension to.

    • +
    • name – Name for the dimension.

    • +
    • label – A dimension label.

    • +
    • type – The type of dimension, defaults to other.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data cube with a newly added dimension. The new dimension has exactly one dimension label. All +other dimensions remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “add_dimension”.

    +
    +
    + +
    +
    +openeo.processes.aggregate_spatial(data, geometries, reducer, target_dimension=<object object>, context=<object object>)[source]
    +

    Zonal statistics for geometries

    +
    +
    Parameters:
    +
      +
    • data – A raster data cube. The 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. 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.

    • +
    • geometries – Geometries as GeoJSON on which the aggregation will be based. Vector properties are +preserved for vector data cubes and all GeoJSON Features. One 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. - 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). - For points, the process considers +the closest pixel center. - For lines (line strings), the process considers all the pixels whose +centers are closest to at least one point on the line. Thus, pixels may be part of multiple geometries and +be part of multiple aggregations. To 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).

    • +
    • reducer – A reducer to be applied on all values of each geometry. 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.

    • +
    • target_dimension – The name of a new dimensions that is used to store the results. A new dimension +will be created with the given name and type other (see add_dimension()). Defaults to the dimension +name result. Fails with a TargetDimensionExists exception if a dimension with the specified name +exists.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A vector data cube with the computed results and restricted to the bounds of the geometries. The +computed value is used for the dimension with the name that was specified in the parameter +target_dimension. The 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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_spatial”.

    +
    +
    + +
    +
    +openeo.processes.aggregate_spatial_window(data, reducer, size, boundary=<object object>, align=<object object>, context=<object object>)[source]
    +

    Zonal statistics for rectangular windows

    +
    +
    Parameters:
    +
      +
    • data – 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.

    • +
    • reducer – 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.

    • +
    • size – Window size in pixels along the horizontal spatial dimensions. The first value corresponds to +the x axis, the second value corresponds to the y axis.

    • +
    • boundary – 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: - pad (default): pad the data cube with +the no-data value null to fit the required window size. - trim: trim the data cube to fit the required +window size. Set the parameter align to specifies to which corner the data is aligned to.

    • +
    • align – 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The 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. The 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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_spatial_window”.

    +
    +
    + +
    +
    +openeo.processes.aggregate_temporal(data, intervals, reducer, labels=<object object>, dimension=<object object>, context=<object object>)[source]
    +

    Temporal aggregations

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • intervals – Left-closed temporal intervals, which are allowed to overlap. Each temporal interval in +the array has exactly two elements: 1. The first element is the start of the temporal interval. The +specified instance in time is included in the interval. 2. The second element is the end of the +temporal interval. The specified instance in time is excluded from the interval. The 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.

    • +
    • reducer – 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.

    • +
    • labels – Distinct labels for the intervals, which can contain dates and/or times. Is only required to +be specified if the values for the start of the temporal intervals are not distinct and thus the default +labels would not be unique. The number of labels and the number of groups need to be equal.

    • +
    • dimension – 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_temporal”.

    +
    +
    + +
    +
    +openeo.processes.aggregate_temporal_period(data, period, reducer, dimension=<object object>, context=<object object>)[source]
    +

    Temporal aggregations based on calendar hierarchies

    +
    +
    Parameters:
    +
      +
    • data – The source data cube.

    • +
    • period – The time intervals to aggregate. The following pre-defined values are available: * hour: +Hour of the day * day: Day of the year * week: Week of the year * 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. * month: Month +of the year * season: Three month periods of the calendar seasons (December - February, March - May, June +- August, September - November). * tropical-season: Six month periods of the tropical seasons (November - +April, May - October). * year: Proleptic years * 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. * 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.

    • +
    • reducer – 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.

    • +
    • dimension – 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 source 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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): * hour: YYYY-MM-DD-00 - YYYY-MM- +DD-23 * day: YYYY-001 - YYYY-365 * week: YYYY-01 - YYYY-52 * dekad: YYYY-00 - YYYY-36 * +month: YYYY-01 - YYYY-12 * season: YYYY-djf (December - February), YYYY-mam (March - May), +YYYY-jja (June - August), YYYY-son (September - November). * tropical-season: YYYY-ndjfma (November +- April), YYYY-mjjaso (May - October). * year: YYYY * decade: YYY0 * decade-ad: YYY1 The +dimension labels in the new data cube are complete for the whole extent of the source data cube. For +example, if period is set to day and the source data cube has two dimension labels at the beginning of +the year (2020-01-01) and the end of a year (2020-12-31), the process returns a data cube with 365 +dimension labels (2020-001, 2020-002, …, 2020-365). In contrast, if period is set to day and +the source data cube has just one dimension label 2020-01-05, the process returns a data cube with just a +single dimension label (2020-005).

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_temporal_period”.

    +
    +
    + +
    +
    +openeo.processes.all(data, ignore_nodata=<object object>)[source]
    +

    Are all of the values true?

    +
    +
    Parameters:
    +
      +
    • data – A set of boolean values.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not and ignores them by default.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical operation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “all”.

    +
    +
    + +
    +
    +openeo.processes.and_(x, y)[source]
    +

    Logical AND

    +
    +
    Parameters:
    +
      +
    • x – A boolean value.

    • +
    • y – A boolean value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical AND.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “and_”.

    +
    +
    + +
    +
    +openeo.processes.anomaly(data, normals, period)[source]
    +

    Compute anomalies

    +
    +
    Parameters:
    +
      +
    • data – A data cube with exactly one temporal dimension and the following dimension labels for the +given period (YYYY = four-digit year, MM = two-digit month, DD two-digit day of month): * hour: +YYYY-MM-DD-00 - YYYY-MM-DD-23 * day: YYYY-001 - YYYY-365 * week: YYYY-01 - YYYY-52 * +dekad: YYYY-00 - YYYY-36 * month: YYYY-01 - YYYY-12 * season: YYYY-djf (December - +February), YYYY-mam (March - May), YYYY-jja (June - August), YYYY-son (September - November). * +tropical-season: YYYY-ndjfma (November - April), YYYY-mjjaso (May - October). * year: YYYY * +decade: YYY0 * decade-ad: YYY1 * single-period / climatology-period: Any +aggregate_temporal_period() can compute such a data cube.

    • +
    • normals – A data cube with normals, e.g. daily, monthly or yearly values computed from a process such +as climatological_normal(). Must contain exactly one temporal dimension with the following dimension +labels for the given period: * hour: 00 - 23 * day: 001 - 365 * week: 01 - 52 * dekad: +00 - 36 * month: 01 - 12 * season: djf (December - February), mam (March - May), jja +(June - August), son (September - November) * tropical-season: ndjfma (November - April), mjjaso +(May - October) * year: Four-digit year numbers * decade: Four-digit year numbers, the last digit being +a 0 * decade-ad: Four-digit year numbers, the last digit being a 1 * single-period / climatology- +period: A single dimension label with any name is expected.

    • +
    • period – Specifies the time intervals available in the normals data cube. The following options are +available: * hour: Hour of the day * day: Day of the year * week: Week of the year * 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. * month: Month of the year * season: Three month periods of the calendar seasons (December - +February, March - May, June - August, September - November). * tropical-season: Six month periods of the +tropical seasons (November - April, May - October). * year: Proleptic years * 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. * 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. * single-period / climatology- +period: A single period of arbitrary length

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the same dimensions. The dimension properties (name, type, labels, reference +system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “anomaly”.

    +
    +
    + +
    +
    +openeo.processes.any(data, ignore_nodata=<object object>)[source]
    +

    Is at least one value true?

    +
    +
    Parameters:
    +
      +
    • data – A set of boolean values.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not and ignores them by default.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical operation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “any”.

    +
    +
    + +
    +
    +openeo.processes.apply(data, process, context=<object object>)[source]
    +

    Apply a process to each pixel

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • process – 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 absolute() or linear_scale_range().

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The dimension properties +(name, type, labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply”.

    +
    +
    + +
    +
    +openeo.processes.apply_dimension(data, process, dimension, target_dimension=<object object>, context=<object object>)[source]
    +

    Apply a process to pixels along a dimension

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • process – 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.

    • +
    • dimension – The name of the source dimension to apply the process on. Fails with a +DimensionNotAvailable exception if the specified dimension does not exist.

    • +
    • target_dimension – The name of the target dimension or null (the default) to use the source +dimension specified in the parameter dimension. By 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.

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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 dimensions can change: 1. +The source dimension is the target dimension: - The (number of) dimensions remain unchanged as the +source dimension is the target dimension. - The source dimension properties name and type remain +unchanged. - 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. 2. The source dimension is +not the target dimension and the latter exists: - The number of dimensions decreases by one as the +source dimension is dropped. - The target dimension properties name and type remain unchanged. All other +dimension properties change as defined in the list below. 3. The source dimension is not the target +dimension and the latter does not exist: - The number of dimensions remain unchanged, but the source +dimension is replaced with the target dimension. - The target dimension has the specified name and the +type other. All other dimension properties are set as defined in the list below. Unless otherwise stated +above, for the given (target) dimension the following applies: - the number of dimension labels is equal +to the number of values computed by the process, - the dimension labels are incrementing integers starting +from zero, - the resolution changes, and - the reference system is undefined.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_dimension”.

    +
    +
    + +
    +
    +openeo.processes.apply_kernel(data, kernel, factor=<object object>, border=<object object>, replace_invalid=<object object>)[source]
    +

    Apply a spatial convolution with a kernel

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • kernel – 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.

    • +
    • factor – A factor that is multiplied to each value after the kernel has been applied. This is +basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often required +for some kernel-based algorithms such as the Gaussian blur.

    • +
    • border – Determines how the data is extended when the kernel overlaps with the borders. Defaults to +fill the border with zeroes. The following options are available: * numeric value - fill with a user- +defined constant number n: nnnnnn|abcdefgh|nnnnnn (default, with n = 0) * replicate - repeat the +value from the pixel at the border: aaaaaa|abcdefgh|hhhhhh * reflect - mirror/reflect from the border: +fedcba|abcdefgh|hgfedc * reflect_pixel - mirror/reflect from the center of the pixel at the border: +gfedcb|abcdefgh|gfedcb * wrap - repeat/wrap the image: cdefgh|abcdefgh|abcdef

    • +
    • replace_invalid – This parameter specifies the value to replace non-numerical or infinite numerical +values with. By default, those values are replaced with zeroes.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The dimension properties +(name, type, labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_kernel”.

    +
    +
    + +
    +
    +openeo.processes.apply_neighborhood(data, process, size, overlap=<object object>, context=<object object>)[source]
    +

    Apply a process to pixels in a n-dimensional neighborhood

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • process – Process to be applied on all neighborhoods.

    • +
    • size – Neighborhood sizes along each dimension. This 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.

    • +
    • overlap – Overlap of neighborhoods along each dimension to avoid border effects. By default no +overlap is provided. For 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. Be aware that +large overlaps increase the need for computational resources and modifying overlapping data in subsequent +operations have no effect.

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The dimension properties +(name, type, labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_neighborhood”.

    +
    +
    + +
    +
    +openeo.processes.arccos(x)[source]
    +

    Inverse cosine

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arccos”.

    +
    +
    + +
    +
    +openeo.processes.arcosh(x)[source]
    +

    Inverse hyperbolic cosine

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arcosh”.

    +
    +
    + +
    +
    +openeo.processes.arcsin(x)[source]
    +

    Inverse sine

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arcsin”.

    +
    +
    + +
    +
    +openeo.processes.arctan(x)[source]
    +

    Inverse tangent

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arctan”.

    +
    +
    + +
    +
    +openeo.processes.arctan2(y, x)[source]
    +

    Inverse tangent of two numbers

    +
    +
    Parameters:
    +
      +
    • y – A number to be used as the dividend.

    • +
    • x – A number to be used as the divisor.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arctan2”.

    +
    +
    + +
    +
    +openeo.processes.ard_normalized_radar_backscatter(data, elevation_model=<object object>, contributing_area=<object object>, ellipsoid_incidence_angle=<object object>, noise_removal=<object object>, options=<object object>)[source]
    +

    CARD4L compliant SAR NRB generation

    +
    +
    Parameters:
    +
      +
    • data – The source data cube containing SAR input.

    • +
    • elevation_model – 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.

    • +
    • contributing_area – If set to true, a DEM-based local contributing area band named +contributing_area is added. The values are given in square meters.

    • +
    • ellipsoid_incidence_angle – If set to true, an ellipsoidal incidence angle band named +ellipsoid_incidence_angle is added. The values are given in degrees.

    • +
    • noise_removal – If set to false, no noise removal is applied. Defaults to true, which removes +noise.

    • +
    • options – Proprietary options for the backscatter computations. Specifying proprietary options will +reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Backscatter values expressed as gamma0 in linear scale. In 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: - mask: A data mask that indicates +which values are valid (1), invalid (0) or contain no-data (null). - local_incidence_angle: A band with +DEM-based local incidence angles in degrees. The data returned is CARD4L compliant with corresponding +metadata.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ard_normalized_radar_backscatter”.

    +
    +
    + +
    +
    +openeo.processes.ard_surface_reflectance(data, atmospheric_correction_method, cloud_detection_method, elevation_model=<object object>, atmospheric_correction_options=<object object>, cloud_detection_options=<object object>)[source]
    +

    CARD4L compliant Surface Reflectance generation

    +
    +
    Parameters:
    +
      +
    • data – The source data cube containing multi-spectral optical top of the atmosphere (TOA) +reflectances. There must be a single dimension of type bands available.

    • +
    • atmospheric_correction_method – The atmospheric correction method to use.

    • +
    • cloud_detection_method – The cloud detection method to use. Each method supports detecting different +atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water vapour in +optical imagery.

    • +
    • elevation_model – 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.

    • +
    • atmospheric_correction_options – Proprietary options for the atmospheric correction method. +Specifying proprietary options will reduce portability.

    • +
    • cloud_detection_options – Proprietary options for the cloud detection method. Specifying proprietary +options will reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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: 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. Depending on the methods +used, several additional bands will be added to the data cube: - date (optional): Specifies per-pixel +acquisition timestamps. - 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. - 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. - 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. - 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. +- 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. - incidence-angle (optional): Specifies per-pixel +incidence angles in degrees. - azimuth (optional): Specifies per-pixel azimuth angles in degrees. - sun- +azimuth: (optional): Specifies per-pixel sun azimuth angles in degrees. - sun-elevation (optional): +Specifies per-pixel sun elevation angles in degrees. - 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. - +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. - terrain-illumination +(optional): Contains coefficients used for terrain illumination correction are provided for each pixel. +The data returned is CARD4L compliant with corresponding metadata.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ard_surface_reflectance”.

    +
    +
    + +
    +
    +openeo.processes.array_append(data, value, label=<object object>)[source]
    +

    Append a value to an array

    +
    +
    Parameters:
    +
      +
    • data – An array.

    • +
    • value – Value to append to the array.

    • +
    • label – If the given array is a labeled array, a new label for the new value should be given. If not +given or null, the array index as string is used as the label. If in any case the label exists, a +LabelExists exception is thrown.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The new array with the value being appended.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_append”.

    +
    +
    + +
    +
    +openeo.processes.array_apply(data, process, context=<object object>)[source]
    +

    Apply a process to each array element

    +
    +
    Parameters:
    +
      +
    • data – An array.

    • +
    • process – 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 absolute() or linear_scale_range().

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the newly computed values. The number of elements are the same as for the original +array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_apply”.

    +
    +
    + +
    +
    +openeo.processes.array_concat(array1, array2)[source]
    +

    Merge two arrays

    +
    +
    Parameters:
    +
      +
    • array1 – The first array.

    • +
    • array2 – The second array.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The merged array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_concat”.

    +
    +
    + +
    +
    +openeo.processes.array_contains(data, value)[source]
    +

    Check whether the array contains a given value

    +
    +
    Parameters:
    +
      +
    • data – List to find the value in.

    • +
    • value – Value to find in data. If the value is null, this process returns always false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the list contains the value, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_contains”.

    +
    +
    + +
    +
    +openeo.processes.array_create(data=<object object>, repeat=<object object>)[source]
    +

    Create an array

    +
    +
    Parameters:
    +
      +
    • data – A (native) array to fill the newly created array with. Defaults to an empty array.

    • +
    • repeat – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The newly created array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_create”.

    +
    +
    + +
    +
    +openeo.processes.array_create_labeled(data, labels)[source]
    +

    Create a labeled array

    +
    +
    Parameters:
    +
      +
    • data – An array of values to be used.

    • +
    • labels – An array of labels to be used.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The newly created labeled array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_create_labeled”.

    +
    +
    + +
    +
    +openeo.processes.array_element(data, index=<object object>, label=<object object>, return_nodata=<object object>)[source]
    +

    Get an element from an array

    +
    +
    Parameters:
    +
      +
    • data – An array.

    • +
    • index – The zero-based index of the element to retrieve.

    • +
    • label – 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.

    • +
    • return_nodata – By default this process throws an ArrayElementNotAvailable exception if the index +or label is invalid. If you want to return null instead, set this flag to true.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The value of the requested element.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_element”.

    +
    +
    + +
    +
    +openeo.processes.array_filter(data, condition, context=<object object>)[source]
    +

    Filter an array based on a condition

    +
    +
    Parameters:
    +
      +
    • data – An array.

    • +
    • condition – 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.

    • +
    • context – Additional data to be passed to the condition.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array filtered by the specified condition. The number of elements are less than or equal +compared to the original array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_filter”.

    +
    +
    + +
    +
    +openeo.processes.array_find(data, value, reverse=<object object>)[source]
    +

    Get the index for a value in an array

    +
    +
    Parameters:
    +
      +
    • data – List to find the value in.

    • +
    • value – Value to find in data. If the value is null, this process returns always null.

    • +
    • reverse – By default, this process finds the index of the first match. To return the index of the +last match instead, set this flag to true.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The index of the first element with the specified value. If no element was found, null is +returned.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_find”.

    +
    +
    + +
    +
    +openeo.processes.array_find_label(data, label)[source]
    +

    Get the index for a label in a labeled array

    +
    +
    Parameters:
    +
      +
    • data – List to find the label in.

    • +
    • label – Label to find in data.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The index of the element with the specified label assigned. If no such label was found, null is +returned.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_find_label”.

    +
    +
    + +
    +
    +openeo.processes.array_interpolate_linear(data)[source]
    +

    One-dimensional linear interpolation for arrays

    +
    +
    Parameters:
    +

    data – An array of numbers and no-data values. If 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.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_interpolate_linear”.

    +
    +
    + +
    +
    +openeo.processes.array_labels(data)[source]
    +

    Get the labels for an array

    +
    +
    Parameters:
    +

    data – An array.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The labels or indices as array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_labels”.

    +
    +
    + +
    +
    +openeo.processes.array_modify(data, values, index, length=<object object>)[source]
    +

    Change the content of an array (remove, insert, update)

    +
    +
    Parameters:
    +
      +
    • data – The array to modify.

    • +
    • values – The values to insert into the data array.

    • +
    • index – The index in the data array of the element to insert the value(s) before. If the index is +greater than the number of elements in the data array, the process throws an ArrayElementNotAvailable +exception. To insert after the last element, there are two options: 1. Use the simpler processes +array_append() to append a single value or array_concat() to append multiple values. 2. 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.

    • +
    • length – The number of elements in the data array to remove (or replace) starting from the given +index. If the array contains fewer elements, the process simply removes all elements up to the end.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with values added, updated or removed.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_modify”.

    +
    +
    + +
    +
    +openeo.processes.arsinh(x)[source]
    +

    Inverse hyperbolic sine

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arsinh”.

    +
    +
    + +
    +
    +openeo.processes.artanh(x)[source]
    +

    Inverse hyperbolic tangent

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “artanh”.

    +
    +
    + +
    +
    +openeo.processes.atmospheric_correction(data, method, elevation_model=<object object>, options=<object object>)[source]
    +

    Apply atmospheric correction

    +
    +
    Parameters:
    +
      +
    • data – Data cube containing multi-spectral optical top of atmosphere reflectances to be corrected.

    • +
    • method – The atmospheric correction method to use. To get reproducible results, you have to set a +specific method. Set 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.

    • +
    • elevation_model – 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.

    • +
    • options – Proprietary options for the atmospheric correction method. Specifying proprietary options +will reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Data cube containing bottom of atmosphere reflectances.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “atmospheric_correction”.

    +
    +
    + +
    +
    +openeo.processes.between(x, min, max, exclude_max=<object object>)[source]
    +

    Between comparison

    +
    +
    Parameters:
    +
      +
    • x – The value to check.

    • +
    • min – Lower boundary (inclusive) to check against.

    • +
    • max – Upper boundary (inclusive) to check against.

    • +
    • exclude_max – Exclude the upper boundary max if set to true. Defaults to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is between the specified bounds, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “between”.

    +
    +
    + +
    +
    +openeo.processes.ceil(x)[source]
    +

    Round fractions up

    +
    +
    Parameters:
    +

    x – A number to round up.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The number rounded up.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ceil”.

    +
    +
    + +
    +
    +openeo.processes.climatological_normal(data, period, climatology_period=<object object>)[source]
    +

    Compute climatology normals

    +
    +
    Parameters:
    +
      +
    • data – A data cube with exactly one temporal dimension. The data cube must span at least the temporal +interval specified in the parameter climatology-period. Seasonal periods may span two consecutive years, +e.g. temporal winter that includes months December, January and February. If the required months before the +actual climate period are available, the season is taken into account. If not available, the first season +is not taken into account and the seasonal mean is based on one year less than the other seasonal normals. +The incomplete season at the end of the last year is never taken into account.

    • +
    • period – The time intervals to aggregate the average value for. The following pre-defined frequencies +are supported: * day: Day of the year * month: Month of the year * climatology-period: The period +specified in the climatology-period. * season: Three month periods of the calendar seasons (December - +February, March - May, June - August, September - November). * tropical-season: Six month periods of the +tropical seasons (November - April, May - October).

    • +
    • climatology_period – 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).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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 temporal +dimension. The temporal dimension has the following dimension labels: * day: 001 - 365 * month: +01 - 12 * climatology-period: climatology-period * season: djf (December - February), mam +(March - May), jja (June - August), son (September - November) * tropical-season: ndjfma (November +- April), mjjaso (May - October)

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “climatological_normal”.

    +
    +
    + +
    +
    +openeo.processes.clip(x, min, max)[source]
    +

    Clip a value between a minimum and a maximum

    +
    +
    Parameters:
    +
      +
    • x – A number.

    • +
    • min – Minimum value. If the value is lower than this value, the process will return the value of this +parameter.

    • +
    • max – Maximum value. If the value is greater than this value, the process will return the value of +this parameter.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The value clipped to the specified range.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “clip”.

    +
    +
    + +
    +
    +openeo.processes.cloud_detection(data, method, options=<object object>)[source]
    +

    Create cloud masks

    +
    +
    Parameters:
    +
      +
    • data – The source data cube containing multi-spectral optical top of the atmosphere (TOA) +reflectances on which to perform cloud detection.

    • +
    • method – The cloud detection method to use. To get reproducible results, you have to set a specific +method. Set 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.

    • +
    • options – Proprietary options for the cloud detection method. Specifying proprietary options will +reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cloud_detection”.

    +
    +
    + +
    +
    +openeo.processes.constant(x)[source]
    +

    Define a constant value

    +
    +
    Parameters:
    +

    x – The value of the constant.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The value of the constant.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “constant”.

    +
    +
    + +
    +
    +openeo.processes.cos(x)[source]
    +

    Cosine

    +
    +
    Parameters:
    +

    x – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed cosine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cos”.

    +
    +
    + +
    +
    +openeo.processes.cosh(x)[source]
    +

    Hyperbolic cosine

    +
    +
    Parameters:
    +

    x – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed hyperbolic cosine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cosh”.

    +
    +
    + +
    +
    +openeo.processes.count(data, condition=<object object>, context=<object object>)[source]
    +

    Count the number of elements

    +
    +
    Parameters:
    +
      +
    • data – An array with elements of any data type.

    • +
    • condition – 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.

    • +
    • context – Additional data to be passed to the condition.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The counted number of elements.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “count”.

    +
    +
    + +
    +
    +openeo.processes.create_raster_cube()[source]
    +

    Create an empty raster data cube

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An empty raster data cube with zero dimensions.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “create_raster_cube”.

    +
    +
    + +
    +
    +openeo.processes.cummax(data, ignore_nodata=<object object>)[source]
    +

    Cumulative maxima

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative maxima.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cummax”.

    +
    +
    + +
    +
    +openeo.processes.cummin(data, ignore_nodata=<object object>)[source]
    +

    Cumulative minima

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative minima.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cummin”.

    +
    +
    + +
    +
    +openeo.processes.cumproduct(data, ignore_nodata=<object object>)[source]
    +

    Cumulative products

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative products.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cumproduct”.

    +
    +
    + +
    +
    +openeo.processes.cumsum(data, ignore_nodata=<object object>)[source]
    +

    Cumulative sums

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative sums.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cumsum”.

    +
    +
    + +
    +
    +openeo.processes.date_shift(date, value, unit)[source]
    +

    Manipulates dates and times by addition or subtraction

    +
    +
    Parameters:
    +
      +
    • date – The date (and optionally time) to manipulate. If 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.

    • +
    • value – 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.

    • +
    • unit – The unit for the value given. The following pre-defined units are available: - millisecond: +Milliseconds - second: Seconds - leap seconds are ignored in computations. - minute: Minutes - hour: Hours +- day: Days - changes only the the day part of a date - week: Weeks (equivalent to 7 days) - month: Months +- year: Years Manipulations 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The manipulated date. If a time component was given in the parameter date, the time component is +returned with the date.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “date_shift”.

    +
    +
    + +
    +
    +openeo.processes.dimension_labels(data, dimension)[source]
    +

    Get the dimension labels

    +
    +
    Parameters:
    +
      +
    • data – The data cube.

    • +
    • dimension – The name of the dimension to get the labels for.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The labels as an array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “dimension_labels”.

    +
    +
    + +
    +
    +openeo.processes.divide(x, y)[source]
    +

    Division of two numbers

    +
    +
    Parameters:
    +
      +
    • x – The dividend.

    • +
    • y – The divisor.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed result.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “divide”.

    +
    +
    + +
    +
    +openeo.processes.drop_dimension(data, name)[source]
    +

    Remove a dimension

    +
    +
    Parameters:
    +
      +
    • data – The data cube to drop a dimension from.

    • +
    • name – Name of the dimension to drop.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube without the specified dimension. The number of dimensions decreases by one, but the +dimension properties (name, type, labels, reference system and resolution) for all other dimensions remain +unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “drop_dimension”.

    +
    +
    + +
    +
    +openeo.processes.e()[source]
    +

    Euler’s number (e)

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The numerical value of Euler’s number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “e”.

    +
    +
    + +
    +
    +openeo.processes.eq(x, y, delta=<object object>, case_sensitive=<object object>)[source]
    +

    Equal to comparison

    +
    +
    Parameters:
    +
      +
    • x – First operand.

    • +
    • y – Second operand.

    • +
    • delta – 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. This option is basically +an alias for the following computation: lte(abs(minus([x, y]), delta)

    • +
    • case_sensitive – Only applicable for comparing two strings. Case sensitive comparison can be disabled +by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is equal to y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “eq”.

    +
    +
    + +
    +
    +openeo.processes.exp(p)[source]
    +

    Exponentiation to the base e

    +
    +
    Parameters:
    +

    p – The numerical exponent.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed value for e raised to the power of p.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “exp”.

    +
    +
    + +
    +
    +openeo.processes.extrema(data, ignore_nodata=<object object>)[source]
    +

    Minimum and maximum values

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not. Ignores them by default. Setting +this flag to false considers no-data values so that an array with two null values is returned if any +value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array containing the minimum and maximum values for the specified numbers. The first element is +the minimum, the second element is the maximum. If the input array is empty both elements are set to +null.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “extrema”.

    +
    +
    + +
    +
    +openeo.processes.filter_bands(data, bands=<object object>, wavelengths=<object object>)[source]
    +

    Filter the bands by names

    +
    +
    Parameters:
    +
      +
    • data – A data cube with bands.

    • +
    • bands – 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. The 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.

    • +
    • wavelengths – 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). The 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube limited to a subset of its original bands. The dimensions and dimension properties +(name, type, labels, reference system and resolution) remain unchanged, except that the dimension of type +bands has less (or the same) dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bands”.

    +
    +
    + +
    +
    +openeo.processes.filter_bbox(data, extent)[source]
    +

    Spatial filter using a bounding box

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • extent – A bounding box, which may include a vertical axis (see base and height).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube restricted to the bounding box. The dimensions and dimension properties (name, type, +labels, reference system and resolution) remain unchanged, except that the spatial dimensions have less (or +the same) dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bbox”.

    +
    +
    + +
    +
    +openeo.processes.filter_labels(data, condition, dimension, context=<object object>)[source]
    +

    Filter dimension labels based on a condition

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • condition – A condition that is evaluated against each dimension label in the specified dimension. A +dimension label and the corresponding data is preserved for the given dimension, if the condition returns +true.

    • +
    • dimension – The name of the dimension to filter on. Fails with a DimensionNotAvailable exception if +the specified dimension does not exist.

    • +
    • context – Additional data to be passed to the condition.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the same dimensions. The dimension properties (name, type, labels, reference +system and resolution) remain unchanged, except that the given dimension has less (or the same) dimension +labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_labels”.

    +
    +
    + +
    +
    +openeo.processes.filter_spatial(data, geometries)[source]
    +

    Spatial filter using geometries

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • geometries – One or more geometries used for filtering, specified as GeoJSON.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube restricted to the specified geometries. The dimensions and dimension properties (name, +type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions have +less (or the same) dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_spatial”.

    +
    +
    + +
    +
    +openeo.processes.filter_temporal(data, extent, dimension=<object object>)[source]
    +

    Temporal filter based on temporal intervals

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • extent – Left-closed temporal interval, i.e. an array with exactly two elements: 1. The first +element is the start of the temporal interval. The specified instance in time is included in the +interval. 2. The second element is the end of the temporal interval. The specified instance in time is +excluded from the interval. The 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.

    • +
    • dimension – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_temporal”.

    +
    +
    + +
    +
    +openeo.processes.first(data, ignore_nodata=<object object>)[source]
    +

    First element

    +
    +
    Parameters:
    +
      +
    • data – An array with elements of any data type.

    • +
    • ignore_nodata – 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 returned if the first value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The first element of the input array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “first”.

    +
    +
    + +
    +
    +openeo.processes.fit_class_random_forest(predictors, target, max_variables, num_trees=<object object>, seed=<object object>)[source]
    +

    Train a random forest classification model

    +
    +
    Parameters:
    +
      +
    • predictors – The predictors for the classification model as a vector data cube. Aggregated to the +features (vectors) of the target input variable.

    • +
    • target – The training sites for the classification model as a vector data cube. This is associated +with the target variable for the Random Forest model. The geometry has to associated with a value to +predict (e.g. fractional forest canopy cover).

    • +
    • max_variables – Specifies how many split variables will be used at a node. The following options are +available: - integer: The given number of variables are considered for each split. - all: All +variables are considered for each split. - log2: The logarithm with base 2 of the number of variables are +considered for each split. - onethird: A third of the number of variables are considered for each split. +- sqrt: The square root of the number of variables are considered for each split. This is often the +default for classification.

    • +
    • num_trees – The number of trees build within the Random Forest classification.

    • +
    • seed – A randomization seed to use for the random sampling in training. If not given or null, no +seed is used and results may differ on subsequent use.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A model object that can be saved with save_ml_model() and restored with load_ml_model().

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_class_random_forest”.

    +
    +
    + +
    +
    +openeo.processes.fit_curve(data, parameters, function, dimension)[source]
    +

    Curve fitting

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • parameters – Defined the number of parameters for the model function and provides an initial guess +for them. At least one parameter is required.

    • +
    • function – The model function. It must take the parameters to fit as array through the first argument +and the independent variable x as the second argument. It is recommended to store the model function as +a user-defined process on the back-end to be able to re-use the model function with the computed optimal +values for the parameters afterwards.

    • +
    • dimension – The name of the dimension for curve fitting. Must be a dimension with labels that have a +order (i.e. numerical labels or a temporal dimension). Fails with a DimensionNotAvailable exception if +the specified dimension does not exist.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the optimal values for the parameters.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_curve”.

    +
    +
    + +
    +
    +openeo.processes.fit_regr_random_forest(predictors, target, max_variables, num_trees=<object object>, seed=<object object>)[source]
    +

    Train a random forest regression model

    +
    +
    Parameters:
    +
      +
    • predictors – The predictors for the regression model as a vector data cube. Aggregated to the +features (vectors) of the target input variable.

    • +
    • target – The training sites for the regression model as a vector data cube. This is associated with +the target variable for the Random Forest model. The geometry has to associated with a value to predict +(e.g. fractional forest canopy cover).

    • +
    • max_variables – Specifies how many split variables will be used at a node. The following options are +available: - integer: The given number of variables are considered for each split. - all: All +variables are considered for each split. - log2: The logarithm with base 2 of the number of variables are +considered for each split. - onethird: A third of the number of variables are considered for each split. +This is often the default for regression. - sqrt: The square root of the number of variables are +considered for each split.

    • +
    • num_trees – The number of trees build within the Random Forest regression.

    • +
    • seed – A randomization seed to use for the random sampling in training. If not given or null, no +seed is used and results may differ on subsequent use.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A model object that can be saved with save_ml_model() and restored with load_ml_model().

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_regr_random_forest”.

    +
    +
    + +
    +
    +openeo.processes.flatten_dimensions(data, dimensions, target_dimension, label_separator=<object object>)[source]
    +

    Combine multiple dimensions into a single dimension

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • dimensions – The names of the dimension to combine. The order of the array defines the order in which +the dimension labels and values are combined (see the example in the process description). Fails with a +DimensionNotAvailable exception if at least one of the specified dimensions does not exist.

    • +
    • target_dimension – The name of the new target dimension. A new dimensions will be created with the +given names and type other (see add_dimension()). Fails with a TargetDimensionExists exception if a +dimension with the specified name exists.

    • +
    • label_separator – The string that will be used as a separator for the concatenated dimension labels. +To unambiguously revert the dimension labels with the process unflatten_dimension(), the given string +must not be contained in any of the dimension labels.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the new shape. The dimension properties (name, type, labels, reference system and +resolution) for all other dimensions remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “flatten_dimensions”.

    +
    +
    + +
    +
    +openeo.processes.floor(x)[source]
    +

    Round fractions down

    +
    +
    Parameters:
    +

    x – A number to round down.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The number rounded down.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “floor”.

    +
    +
    + +
    +
    +openeo.processes.gt(x, y)[source]
    +

    Greater than comparison

    +
    +
    Parameters:
    +
      +
    • x – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is strictly greater than y or null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “gt”.

    +
    +
    + +
    +
    +openeo.processes.gte(x, y)[source]
    +

    Greater than or equal to comparison

    +
    +
    Parameters:
    +
      +
    • x – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is greater than or equal to y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “gte”.

    +
    +
    + +
    +
    +openeo.processes.if_(value, accept, reject=<object object>)[source]
    +

    If-Then-Else conditional

    +
    +
    Parameters:
    +
      +
    • value – A boolean value.

    • +
    • accept – A value that is returned if the boolean value is true.

    • +
    • reject – A value that is returned if the boolean value is not true. Defaults to null.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Either the accept or reject argument depending on the given boolean value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “if_”.

    +
    +
    + +
    +
    +openeo.processes.inspect(data, code=<object object>, level=<object object>, message=<object object>)[source]
    +

    Add information to the logs

    +
    +
    Parameters:
    +
      +
    • data – Data to log.

    • +
    • code – A label to help identify one or more log entries originating from this process in the list of +all log entries. It can help to group or filter log entries and is usually not unique.

    • +
    • level – The severity level of this message, defaults to info.

    • +
    • message – A message to send in addition to the data.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data as passed to the data parameter without any modification.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “inspect”.

    +
    +
    + +
    +
    +openeo.processes.int(x)[source]
    +

    Integer part of a number

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Integer part of the number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “int”.

    +
    +
    + +
    +
    +openeo.processes.is_infinite(x)[source]
    +

    Value is an infinite number

    +
    +
    Parameters:
    +

    x – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is an infinite number, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_infinite”.

    +
    +
    + +
    +
    +openeo.processes.is_nan(x)[source]
    +

    Value is not a number

    +
    +
    Parameters:
    +

    x – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is not a number, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_nan”.

    +
    +
    + +
    +
    +openeo.processes.is_nodata(x)[source]
    +

    Value is a no-data value

    +
    +
    Parameters:
    +

    x – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is a no-data value, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_nodata”.

    +
    +
    + +
    +
    +openeo.processes.is_valid(x)[source]
    +

    Value is valid data

    +
    +
    Parameters:
    +

    x – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is valid, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_valid”.

    +
    +
    + +
    +
    +openeo.processes.last(data, ignore_nodata=<object object>)[source]
    +

    Last element

    +
    +
    Parameters:
    +
      +
    • data – An array with elements of any data type.

    • +
    • ignore_nodata – 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 returned if the last value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The last element of the input array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “last”.

    +
    +
    + +
    +
    +openeo.processes.linear_scale_range(x, inputMin, inputMax, outputMin=<object object>, outputMax=<object object>)[source]
    +

    Linear transformation between two ranges

    +
    +
    Parameters:
    +
      +
    • x – A number to transform. The number gets clipped to the bounds specified in inputMin and +inputMax.

    • +
    • inputMin – Minimum value the input can obtain.

    • +
    • inputMax – Maximum value the input can obtain.

    • +
    • outputMin – Minimum value of the desired output range.

    • +
    • outputMax – Maximum value of the desired output range.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The transformed number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “linear_scale_range”.

    +
    +
    + +
    +
    +openeo.processes.ln(x)[source]
    +

    Natural logarithm

    +
    +
    Parameters:
    +

    x – A number to compute the natural logarithm for.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed natural logarithm.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ln”.

    +
    +
    + +
    +
    +openeo.processes.load_collection(id, spatial_extent, temporal_extent, bands=<object object>, properties=<object object>)[source]
    +

    Load a collection

    +
    +
    Parameters:
    +
      +
    • id – The collection id.

    • +
    • spatial_extent – Limits the data to load from the collection to the specified bounding box or +polygons. The 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). The GeoJSON +can be one of the following feature types: * A Polygon or MultiPolygon geometry, * a Feature with a +Polygon or MultiPolygon geometry, * a FeatureCollection containing at least one Feature with +Polygon or MultiPolygon geometries, or * a GeometryCollection containing Polygon or MultiPolygon +geometries. To maximize interoperability, GeometryCollection should be avoided in favour of one of the +alternatives above. Set 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.

    • +
    • temporal_extent – 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: 1. The first element is the start of the temporal interval. The specified instance in time is +included in the interval. 2. The second element is the end of the temporal interval. The specified +instance in time is excluded from the interval. The 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. Set 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.

    • +
    • bands – 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. Either 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. The 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. It is recommended to use +this parameter instead of using filter_bands() directly after loading unbounded data.

    • +
    • properties – Limits the data by metadata properties to include only data in the data cube which all +given conditions return true for (AND operation). Specify key-value-pairs with the key being the name of +the metadata property, which can be retrieved with the openEO Data Discovery for Collections. The value +must be a condition (user-defined process) to be evaluated against the collection metadata, see the +example.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube for further processing. The dimensions and dimension properties (name, type, labels, +reference system and resolution) correspond to the collection’s metadata, but the dimension labels are +restricted as specified in the parameters.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_collection”.

    +
    +
    + +
    +
    +openeo.processes.load_ml_model(id)[source]
    +

    Load a ML model

    +
    +
    Parameters:
    +

    id – The STAC Item to load the machine learning model from. The STAC Item must implement the ml- +model extension.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A machine learning model to be used with machine learning processes such as +predict_random_forest().

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_ml_model”.

    +
    +
    + +
    +
    +openeo.processes.load_result(id, spatial_extent=<object object>, temporal_extent=<object object>, bands=<object object>)[source]
    +

    Load batch job results

    +
    +
    Parameters:
    +
      +
    • id – The id of a batch job with results.

    • +
    • spatial_extent – Limits the data to load from the batch job result to the specified bounding box or +polygons. The 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). The GeoJSON +can be one of the following feature types: * A Polygon or MultiPolygon geometry, * a Feature with a +Polygon or MultiPolygon geometry, * a FeatureCollection containing at least one Feature with +Polygon or MultiPolygon geometries, or * a GeometryCollection containing Polygon or MultiPolygon +geometries. To maximize interoperability, GeometryCollection should be avoided in favour of one of the +alternatives above. Set 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.

    • +
    • temporal_extent – Limits the data to load from the batch job result 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: 1. The first element is the start of the temporal interval. The specified instance +in time is included in the interval. 2. The second element is the end of the temporal interval. The +specified instance in time is excluded from the interval. The 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. Set 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.

    • +
    • bands – 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. Either 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. The 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. It is recommended to use +this parameter instead of using filter_bands() directly after loading unbounded data.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube for further processing.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_result”.

    +
    +
    + +
    +
    +openeo.processes.load_uploaded_files(paths, format, options=<object object>)[source]
    +

    Load files from the user workspace

    +
    +
    Parameters:
    +
      +
    • paths – The files to read. Folders can’t be specified, specify all files instead. An exception is +thrown if a file can’t be read.

    • +
    • format – The file format to read from. It must be one of the values that the server reports as +supported input file formats, which usually correspond to the short GDAL/OGR codes. If the format is not +suitable for loading the data, a FormatUnsuitable exception will be thrown. This parameter is case +insensitive.

    • +
    • options – The file format parameters to be used to read the files. Must correspond to the parameters +that the server reports as supported parameters for the chosen format. The parameter names and valid +values usually correspond to the GDAL/OGR format options.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube for further processing.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_uploaded_files”.

    +
    +
    + +
    +
    +openeo.processes.log(x, base)[source]
    +

    Logarithm to a base

    +
    +
    Parameters:
    +
      +
    • x – A number to compute the logarithm for.

    • +
    • base – The numerical base.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed logarithm.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “log”.

    +
    +
    + +
    +
    +openeo.processes.lt(x, y)[source]
    +

    Less than comparison

    +
    +
    Parameters:
    +
      +
    • x – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is strictly less than y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “lt”.

    +
    +
    + +
    +
    +openeo.processes.lte(x, y)[source]
    +

    Less than or equal to comparison

    +
    +
    Parameters:
    +
      +
    • x – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is less than or equal to y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “lte”.

    +
    +
    + +
    +
    +openeo.processes.mask(data, mask, replacement=<object object>)[source]
    +

    Apply a raster mask

    +
    +
    Parameters:
    +
      +
    • data – A raster data cube.

    • +
    • mask – A mask as a raster data cube. Every pixel in data must have a corresponding element in +mask.

    • +
    • replacement – The value used to replace masked values with.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A masked raster data cube with the same dimensions. The dimension properties (name, type, labels, +reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mask”.

    +
    +
    + +
    +
    +openeo.processes.mask_polygon(data, mask, replacement=<object object>, inside=<object object>)[source]
    +

    Apply a polygon mask

    +
    +
    Parameters:
    +
      +
    • data – A raster data cube.

    • +
    • mask – A GeoJSON object containing at least one polygon. The provided feature types can be one of the +following: * A Polygon or MultiPolygon geometry, * a Feature with a Polygon or MultiPolygon +geometry, * a FeatureCollection containing at least one Feature with Polygon or MultiPolygon +geometries, or * a GeometryCollection containing Polygon or MultiPolygon geometries. To maximize +interoperability, GeometryCollection should be avoided in favour of one of the alternatives above.

    • +
    • replacement – The value used to replace masked values with.

    • +
    • inside – If set to true all pixels for which the point at the pixel center does intersect with +any polygon are replaced.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A masked raster data cube with the same dimensions. The dimension properties (name, type, labels, +reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mask_polygon”.

    +
    +
    + +
    +
    +openeo.processes.max(data, ignore_nodata=<object object>)[source]
    +

    Maximum value

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The maximum value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “max”.

    +
    +
    + +
    +
    +openeo.processes.mean(data, ignore_nodata=<object object>)[source]
    +

    Arithmetic mean (average)

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed arithmetic mean.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mean”.

    +
    +
    + +
    +
    +openeo.processes.median(data, ignore_nodata=<object object>)[source]
    +

    Statistical median

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed statistical median.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “median”.

    +
    +
    + +
    +
    +openeo.processes.merge_cubes(cube1, cube2, overlap_resolver=<object object>, context=<object object>)[source]
    +

    Merge two data cubes

    +
    +
    Parameters:
    +
      +
    • cube1 – The first data cube.

    • +
    • cube2 – The second data cube.

    • +
    • overlap_resolver – A reduction operator that resolves the conflict if the data overlaps. The reducer +must return a value of the same data type as the input values are. The reduction operator may be a single +process such as multiply() or consist of multiple sub-processes. null (the default) can be specified +if no overlap resolver is required.

    • +
    • context – Additional data to be passed to the overlap resolver.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The merged data cube. See the process description for details regarding the dimensions and +dimension properties (name, type, labels, reference system and resolution).

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “merge_cubes”.

    +
    +
    + +
    +
    +openeo.processes.min(data, ignore_nodata=<object object>)[source]
    +

    Minimum value

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The minimum value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “min”.

    +
    +
    + +
    +
    +openeo.processes.mod(x, y)[source]
    +

    Modulo

    +
    +
    Parameters:
    +
      +
    • x – A number to be used as the dividend.

    • +
    • y – A number to be used as the divisor.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The remainder after division.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mod”.

    +
    +
    + +
    +
    +openeo.processes.multiply(x, y)[source]
    +

    Multiplication of two numbers

    +
    +
    Parameters:
    +
      +
    • x – The multiplier.

    • +
    • y – The multiplicand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed product of the two numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “multiply”.

    +
    +
    + +
    +
    +openeo.processes.nan()[source]
    +

    Not a Number (NaN)

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns NaN.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “nan”.

    +
    +
    + +
    +
    +openeo.processes.ndvi(data, nir=<object object>, red=<object object>, target_band=<object object>)[source]
    +

    Normalized Difference Vegetation Index

    +
    +
    Parameters:
    +
      +
    • data – A raster data cube with two bands that have the common names red and nir assigned.

    • +
    • nir – The name of the NIR band. Defaults to the band that has the common name nir assigned. Either +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.

    • +
    • red – The name of the red band. Defaults to the band that has the common name red assigned. Either +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.

    • +
    • target_band – By default, the dimension of type bands is dropped. To keep the dimension specify a +new band name in this parameter so that a new dimension label with the specified name will be added for the +computed values.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A raster data cube containing the computed NDVI values. The structure of the data cube differs +depending on the value passed to target_band: * 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. * 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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ndvi”.

    +
    +
    + +
    +
    +openeo.processes.neq(x, y, delta=<object object>, case_sensitive=<object object>)[source]
    +

    Not equal to comparison

    +
    +
    Parameters:
    +
      +
    • x – First operand.

    • +
    • y – Second operand.

    • +
    • delta – 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. This option is +basically an alias for the following computation: gt(abs(minus([x, y]), delta)

    • +
    • case_sensitive – Only applicable for comparing two strings. Case sensitive comparison can be disabled +by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is not equal to y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “neq”.

    +
    +
    + +
    +
    +openeo.processes.normalized_difference(x, y)[source]
    +

    Normalized difference

    +
    +
    Parameters:
    +
      +
    • x – The value for the first band.

    • +
    • y – The value for the second band.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed normalized difference.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “normalized_difference”.

    +
    +
    + +
    +
    +openeo.processes.not_(x)[source]
    +

    Inverting a boolean

    +
    +
    Parameters:
    +

    x – Boolean value to invert.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Inverted boolean value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “not_”.

    +
    +
    + +
    +
    +openeo.processes.or_(x, y)[source]
    +

    Logical OR

    +
    +
    Parameters:
    +
      +
    • x – A boolean value.

    • +
    • y – A boolean value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical OR.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “or_”.

    +
    +
    + +
    +
    +openeo.processes.order(data, asc=<object object>, nodata=<object object>)[source]
    +

    Create a permutation

    +
    +
    Parameters:
    +
      +
    • data – An array to compute the order for.

    • +
    • asc – The default sort order is ascending, with smallest values first. To sort in reverse +(descending) order, set this parameter to false.

    • +
    • nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed permutation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “order”.

    +
    +
    + +
    +
    +openeo.processes.pi()[source]
    +

    Pi (π)

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The numerical value of Pi.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “pi”.

    +
    +
    + +
    +
    +openeo.processes.power(base, p)[source]
    +

    Exponentiation

    +
    +
    Parameters:
    +
      +
    • base – The numerical base.

    • +
    • p – The numerical exponent.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed value for base raised to the power of p.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “power”.

    +
    +
    + +
    +
    +openeo.processes.predict_curve(data, parameters, function, dimension, labels=<object object>)[source]
    +

    Predict values

    +
    +
    Parameters:
    +
      +
    • data – A data cube to predict values for.

    • +
    • parameters – A data cube with optimal values from a result of e.g. fit_curve().

    • +
    • function – The model function. It must take the parameters to fit as array through the first argument +and the independent variable x as the second argument. It is recommended to store the model function as +a user-defined process on the back-end.

    • +
    • dimension – The name of the dimension for predictions. Fails with a DimensionNotAvailable exception +if the specified dimension does not exist.

    • +
    • labels – The labels to predict values for. If no labels are given, predicts values only for no-data +(null) values in the data cube.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the predicted values.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “predict_curve”.

    +
    +
    + +
    +
    +openeo.processes.predict_random_forest(data, model)[source]
    +

    Predict values from a Random Forest model

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • model – A model object that can be trained with the processes fit_regr_random_forest() +(regression) and fit_class_random_forest() (classification).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The predicted value. Returns null if any of the given values in the array is a no-data value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “predict_random_forest”.

    +
    +
    + +
    +
    +openeo.processes.product(data, ignore_nodata=<object object>)[source]
    +

    Compute the product by multiplying numbers

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed product of the sequence of numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “product”.

    +
    +
    + +
    +
    +openeo.processes.quantiles(data, probabilities=<object object>, q=<object object>, ignore_nodata=<object object>)[source]
    +

    Quantiles

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • probabilities – A list of probabilities to calculate quantiles for. The probabilities must be between +0 and 1 (inclusive).

    • +
    • q – Number of intervals to calculate quantiles for. Calculates q-quantiles with equal-sized +intervals.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not. Ignores them by default. Setting +this flag to false considers no-data values so that an array with null values is returned if any +element is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed quantiles. The list has either * as many elements as the given list of +probabilities had or * `q`-1 elements. If 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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “quantiles”.

    +
    +
    + +
    +
    +openeo.processes.rearrange(data, order)[source]
    +

    Rearrange an array based on a permutation

    +
    +
    Parameters:
    +
      +
    • data – The array to rearrange.

    • +
    • order – The permutation used for rearranging.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The rearranged array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rearrange”.

    +
    +
    + +
    +
    +openeo.processes.reduce_dimension(data, reducer, dimension, context=<object object>)[source]
    +

    Reduce dimensions

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • reducer – A reducer to apply on 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.

    • +
    • dimension – The name of the dimension over which to reduce. Fails with a DimensionNotAvailable +exception if the specified dimension does not exist.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “reduce_dimension”.

    +
    +
    + +
    +
    +openeo.processes.reduce_spatial(data, reducer, context=<object object>)[source]
    +

    Reduce spatial dimensions ‘x’ and ‘y’

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • reducer – 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “reduce_spatial”.

    +
    +
    + +
    +
    +openeo.processes.rename_dimension(data, source, target)[source]
    +

    Rename a dimension

    +
    +
    Parameters:
    +
      +
    • data – The data cube.

    • +
    • source – The current name of the dimension. Fails with a DimensionNotAvailable exception if the +specified dimension does not exist.

    • +
    • target – A new Name for the dimension. Fails with a DimensionExists exception if a dimension with +the specified name exists.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the same dimensions, but the name of one of the dimensions changes. The old name +can not be referred to any longer. The dimension properties (name, type, labels, reference system and +resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rename_dimension”.

    +
    +
    + +
    +
    +openeo.processes.rename_labels(data, dimension, target, source=<object object>)[source]
    +

    Rename dimension labels

    +
    +
    Parameters:
    +
      +
    • data – The data cube.

    • +
    • dimension – The name of the dimension to rename the labels for.

    • +
    • target – The new names for the labels. If a target dimension label already exists in the data cube, +a LabelExists exception is thrown.

    • +
    • source – The original names of the labels to be renamed to corresponding array elements in the +parameter target. It is allowed to only specify a subset of labels to rename, as long as the target and +source parameter have the same length. The order of the labels doesn’t need to match the order of the +dimension labels in the data cube. By default, the array is empty so that the dimension labels in the data +cube are expected to be enumerated. If the dimension labels are not enumerated and the given array is +empty, the LabelsNotEnumerated exception is thrown. If one of the source dimension labels doesn’t exist, +the LabelNotAvailable exception is thrown.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data cube with the same dimensions. The dimension properties (name, type, labels, reference +system and resolution) remain unchanged, except that for the given dimension the labels change. The old +labels can not be referred to any longer. The number of labels remains the same.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rename_labels”.

    +
    +
    + +
    +
    +openeo.processes.resample_cube_spatial(data, target, method=<object object>)[source]
    +

    Resample the spatial dimensions to match a target data cube

    +
    +
    Parameters:
    +
      +
    • data – A data cube.

    • +
    • target – A data cube that describes the spatial target resolution.

    • +
    • method – 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): * average: average (mean) +resampling, computes the weighted average of all valid pixels * bilinear: bilinear resampling * cubic: +cubic resampling * cubicspline: cubic spline resampling * lanczos: Lanczos windowed sinc resampling * +max: maximum resampling, selects the maximum value from all valid pixels * med: median resampling, +selects the median value of all valid pixels * min: minimum resampling, selects the minimum value from +all valid pixels * mode: mode resampling, selects the value which appears most often of all the sampled +points * near: nearest neighbour resampling (default) * q1: first quartile resampling, selects the +first quartile value of all valid pixels * q3: third quartile resampling, selects the third quartile +value of all valid pixels * rms root mean square (quadratic mean) of all valid pixels * sum: compute +the weighted sum of all valid pixels Valid pixels are determined based on the function is_valid().

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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 spatial +dimensions.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “resample_cube_spatial”.

    +
    +
    + +
    +
    +openeo.processes.resample_cube_temporal(data, target, dimension=<object object>, valid_within=<object object>)[source]
    +

    Resample temporal dimensions to match a target data cube

    +
    +
    Parameters:
    +
      +
    • data – A data cube with one or more temporal dimensions.

    • +
    • target – A data cube that describes the temporal target resolution.

    • +
    • dimension – 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. The following exceptions may occur: * A dimension is +given, but it does not exist in any of the data cubes: DimensionNotAvailable * A dimension is given, but +one of them is not temporal: DimensionMismatch * No specific dimension name is given and there are no +temporal dimensions with the same name in the data: DimensionMismatch

    • +
    • valid_within – 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).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “resample_cube_temporal”.

    +
    +
    + +
    +
    +openeo.processes.resample_spatial(data, resolution=<object object>, projection=<object object>, method=<object object>, align=<object object>)[source]
    +

    Resample and warp the spatial dimensions

    +
    +
    Parameters:
    +
      +
    • data – A raster data cube.

    • +
    • resolution – 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).

    • +
    • projection – Warps the data cube to the target projection, specified as as [EPSG +code](http://www.epsg-registry.org/), [WKT2 (ISO 19162) +string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html), [PROJ definition +(deprecated)](https://proj.org/usage/quickstart.html). By default (null), the projection is not changed.

    • +
    • method – 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): * average: average (mean) +resampling, computes the weighted average of all valid pixels * bilinear: bilinear resampling * cubic: +cubic resampling * cubicspline: cubic spline resampling * lanczos: Lanczos windowed sinc resampling * +max: maximum resampling, selects the maximum value from all valid pixels * med: median resampling, +selects the median value of all valid pixels * min: minimum resampling, selects the minimum value from +all valid pixels * mode: mode resampling, selects the value which appears most often of all the sampled +points * near: nearest neighbour resampling (default) * q1: first quartile resampling, selects the +first quartile value of all valid pixels * q3: third quartile resampling, selects the third quartile +value of all valid pixels * rms root mean square (quadratic mean) of all valid pixels * sum: compute +the weighted sum of all valid pixels Valid pixels are determined based on the function is_valid().

    • +
    • align – Specifies to which corner of the spatial extent the new resampled data is aligned to.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A raster data cube with values warped onto the new projection. It has the same dimensions and the +same dimension properties (name, type, labels, reference system and resolution) for all non-spatial or +vertical spatial dimensions. For the horizontal spatial dimensions the name and type remain unchanged, but +reference system, labels and resolution may change depending on the given parameters.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “resample_spatial”.

    +
    +
    + +
    +
    +openeo.processes.round(x, p=<object object>)[source]
    +

    Round to a specified precision

    +
    +
    Parameters:
    +
      +
    • x – A number to round.

    • +
    • p – A positive number specifies the number of digits after the decimal point to round to. A negative +number means rounding to a power of ten, so for example -2 rounds to the nearest hundred. Defaults to +0.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The rounded number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “round”.

    +
    +
    + +
    +
    +openeo.processes.run_udf(data, udf, runtime, version=<object object>, context=<object object>)[source]
    +

    Run a UDF

    +
    +
    Parameters:
    +
      +
    • data – The data to be passed to the UDF.

    • +
    • udf – Either source code, an absolute URL or a path to a UDF script.

    • +
    • runtime – A UDF runtime identifier available at the back-end.

    • +
    • version – An UDF runtime version. If set to null, the default runtime version specified for each +runtime is used.

    • +
    • context – Additional data such as configuration options to be passed to the UDF.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data processed by the UDF. The returned value can be of any data type and is exactly what the +UDF code returns.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “run_udf”.

    +
    +
    + +
    +
    +openeo.processes.run_udf_externally(data, url, context=<object object>)[source]
    +

    Run an externally hosted UDF container

    +
    +
    Parameters:
    +
      +
    • data – The data to be passed to the UDF.

    • +
    • url – Absolute URL to a remote UDF service.

    • +
    • context – Additional data such as configuration options to be passed to the UDF.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data processed by the UDF. The returned value can in principle be of any data type, but it +depends on what is returned by the UDF code. Please see the implemented UDF interface for details.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “run_udf_externally”.

    +
    +
    + +
    +
    +openeo.processes.sar_backscatter(data, coefficient=<object object>, elevation_model=<object object>, mask=<object object>, contributing_area=<object object>, local_incidence_angle=<object object>, ellipsoid_incidence_angle=<object object>, noise_removal=<object object>, options=<object object>)[source]
    +

    Computes backscatter from SAR input

    +
    +
    Parameters:
    +
      +
    • data – The source data cube containing SAR input.

    • +
    • coefficient – Select the radiometric correction coefficient. The following options are available: * +beta0: radar brightness * sigma0-ellipsoid: ground area computed with ellipsoid earth model * +sigma0-terrain: ground area computed with terrain earth model * gamma0-ellipsoid: ground area computed +with ellipsoid earth model in sensor line of sight * gamma0-terrain: ground area computed with terrain +earth model in sensor line of sight (default) * null: non-normalized backscatter

    • +
    • elevation_model – 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.

    • +
    • mask – 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).

    • +
    • contributing_area – If set to true, a DEM-based local contributing area band named +contributing_area is added. The values are given in square meters.

    • +
    • local_incidence_angle – If set to true, a DEM-based local incidence angle band named +local_incidence_angle is added. The values are given in degrees.

    • +
    • ellipsoid_incidence_angle – If set to true, an ellipsoidal incidence angle band named +ellipsoid_incidence_angle is added. The values are given in degrees.

    • +
    • noise_removal – If set to false, no noise removal is applied. Defaults to true, which removes +noise.

    • +
    • options – Proprietary options for the backscatter computations. Specifying proprietary options will +reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Backscatter values corresponding to the chosen parametrization. The values are given in linear +scale.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sar_backscatter”.

    +
    +
    + +
    +
    +openeo.processes.save_ml_model(data, options=<object object>)[source]
    +

    Save a ML model

    +
    +
    Parameters:
    +
      +
    • data – The data to store as a machine learning model.

    • +
    • options – Additional parameters to create the file(s).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns false if the process failed to store the model, true otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “save_ml_model”.

    +
    +
    + +
    +
    +openeo.processes.save_result(data, format, options=<object object>)[source]
    +

    Save processed data

    +
    +
    Parameters:
    +
      +
    • data – The data to deliver in the given file format.

    • +
    • format – The file format to use. It must be one of the values that the server reports as supported +output file formats, which usually correspond to the short GDAL/OGR codes. If the format is not suitable +for storing the underlying data structure, a FormatUnsuitable exception will be thrown. This parameter is +case insensitive.

    • +
    • options – The file format parameters to be used to create the file(s). Must correspond to the +parameters that the server reports as supported parameters for the chosen format. The parameter names and +valid values usually correspond to the GDAL/OGR format options.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns false if the process failed to make the data available, true otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “save_result”.

    +
    +
    + +
    +
    +openeo.processes.sd(data, ignore_nodata=<object object>)[source]
    +

    Standard deviation

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sample standard deviation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sd”.

    +
    +
    + +
    +
    +openeo.processes.sgn(x)[source]
    +

    Signum

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed signum value of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sgn”.

    +
    +
    + +
    +
    +openeo.processes.sin(x)[source]
    +

    Sine

    +
    +
    Parameters:
    +

    x – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sin”.

    +
    +
    + +
    +
    +openeo.processes.sinh(x)[source]
    +

    Hyperbolic sine

    +
    +
    Parameters:
    +

    x – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed hyperbolic sine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sinh”.

    +
    +
    + +
    +
    +openeo.processes.sort(data, asc=<object object>, nodata=<object object>)[source]
    +

    Sort data

    +
    +
    Parameters:
    +
      +
    • data – An array with data to sort.

    • +
    • asc – The default sort order is ascending, with smallest values first. To sort in reverse +(descending) order, set this parameter to false.

    • +
    • nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The sorted array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sort”.

    +
    +
    + +
    +
    +openeo.processes.sqrt(x)[source]
    +

    Square root

    +
    +
    Parameters:
    +

    x – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed square root.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sqrt”.

    +
    +
    + +
    +
    +openeo.processes.subtract(x, y)[source]
    +

    Subtraction of two numbers

    +
    +
    Parameters:
    +
      +
    • x – The minuend.

    • +
    • y – The subtrahend.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed result.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “subtract”.

    +
    +
    + +
    +
    +openeo.processes.sum(data, ignore_nodata=<object object>)[source]
    +

    Compute the sum by adding up numbers

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sum of the sequence of numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sum”.

    +
    +
    + +
    +
    +openeo.processes.tan(x)[source]
    +

    Tangent

    +
    +
    Parameters:
    +

    x – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed tangent of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “tan”.

    +
    +
    + +
    +
    +openeo.processes.tanh(x)[source]
    +

    Hyperbolic tangent

    +
    +
    Parameters:
    +

    x – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed hyperbolic tangent of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “tanh”.

    +
    +
    + +
    +
    +openeo.processes.text_begins(data, pattern, case_sensitive=<object object>)[source]
    +

    Text begins with another text

    +
    +
    Parameters:
    +
      +
    • data – Text in which to find something at the beginning.

    • +
    • pattern – Text to find at the beginning of data. Regular expressions are not supported.

    • +
    • case_sensitive – Case sensitive comparison can be disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if data begins with pattern, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_begins”.

    +
    +
    + +
    +
    +openeo.processes.text_concat(data, separator=<object object>)[source]
    +

    Concatenate elements to a single text

    +
    +
    Parameters:
    +
      +
    • data – A set of elements. Numbers, boolean values and null values get converted to their (lower case) +string representation. For example: 1 (integer), -1.5 (number), true / false (boolean values)

    • +
    • separator – A separator to put between each of the individual texts. Defaults to an empty string.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A string containing a string representation of all the array elements in the same order, with the +separator between each element.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_concat”.

    +
    +
    + +
    +
    +openeo.processes.text_contains(data, pattern, case_sensitive=<object object>)[source]
    +

    Text contains another text

    +
    +
    Parameters:
    +
      +
    • data – Text in which to find something in.

    • +
    • pattern – Text to find in data. Regular expressions are not supported.

    • +
    • case_sensitive – Case sensitive comparison can be disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if data contains the pattern, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_contains”.

    +
    +
    + +
    +
    +openeo.processes.text_ends(data, pattern, case_sensitive=<object object>)[source]
    +

    Text ends with another text

    +
    +
    Parameters:
    +
      +
    • data – Text in which to find something at the end.

    • +
    • pattern – Text to find at the end of data. Regular expressions are not supported.

    • +
    • case_sensitive – Case sensitive comparison can be disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if data ends with pattern, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_ends”.

    +
    +
    + +
    +
    +openeo.processes.trim_cube(data)[source]
    +

    Remove dimension labels with no-data values

    +
    +
    Parameters:
    +

    data – A raster data cube to trim.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A trimmed raster data cube with the same dimensions. The dimension properties name, type, +reference system and resolution remain unchanged. The number of dimension labels may decrease.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “trim_cube”.

    +
    +
    + +
    +
    +openeo.processes.unflatten_dimension(data, dimension, target_dimensions, label_separator=<object object>)[source]
    +

    Split a single dimensions into multiple dimensions

    +
    +
    Parameters:
    +
      +
    • data – A data cube that is consistently structured so that operation can execute flawlessly (e.g. the +dimension labels need to contain the label_separator exactly 1 time for two target dimensions, 2 times +for three target dimensions etc.).

    • +
    • dimension – The name of the dimension to split.

    • +
    • target_dimensions – The names of the new target dimensions. New dimensions will be created with the +given names and type other (see add_dimension()). Fails with a TargetDimensionExists exception if +any of the dimensions exists. The order of the array defines the order in which the dimensions and +dimension labels are added to the data cube (see the example in the process description).

    • +
    • label_separator – The string that will be used as a separator to split the dimension labels.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the new shape. The dimension properties (name, type, labels, reference system and +resolution) for all other dimensions remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “unflatten_dimension”.

    +
    +
    + +
    +
    +openeo.processes.variance(data, ignore_nodata=<object object>)[source]
    +

    Variance

    +
    +
    Parameters:
    +
      +
    • data – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sample variance.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “variance”.

    +
    +
    + +
    +
    +openeo.processes.vector_buffer(geometries, distance)[source]
    +

    Buffer geometries by distance

    +
    +
    Parameters:
    +
      +
    • geometries – Geometries to apply the buffer on. Vector properties are preserved for vector data cubes +and all GeoJSON Features. To 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).

    • +
    • distance – The distance of the buffer in the unit of the spatial reference system. A positive +distance expands the geometries and results in outward buffering (dilation) while a negative distance +shrinks the geometries and results in inward buffering (erosion).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns a vector data cube with the computed new geometries.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “vector_buffer”.

    +
    +
    + +
    +
    +openeo.processes.vector_to_random_points(data, geometry_count=<object object>, total_count=<object object>, group=<object object>, seed=<object object>)[source]
    +

    Sample random points from geometries

    +
    +
    Parameters:
    +
      +
    • data – Input geometries for sample extraction. To 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).

    • +
    • geometry_count – The maximum number of points to compute per geometry. Points in the input +geometries can be selected only once by the sampling.

    • +
    • total_count – The maximum number of points to compute overall. Throws a CountMismatch exception if +the specified value is less than the provided number of geometries.

    • +
    • group – Specifies whether the sampled points should be grouped by input geometry (default) or be +generated as independent points. * If the sampled points are grouped, the process generates a MultiPoint +per geometry given which keeps the original identifier if present. * Otherwise, each sampled point is +generated as a distinct Point geometry without identifier.

    • +
    • seed – A randomization seed to use for random sampling. If not given or null, no seed is used and +results may differ on subsequent use.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns a vector data cube with the sampled points.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “vector_to_random_points”.

    +
    +
    + +
    +
    +openeo.processes.vector_to_regular_points(data, distance, group=<object object>)[source]
    +

    Sample regular points from geometries

    +
    +
    Parameters:
    +
      +
    • data – Input geometries for sample extraction. To 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).

    • +
    • distance – Defines the minimum distance in the unit of the reference system that is required between +two samples generated inside a single geometry. - For polygons, the distance defines the cell sizes +of a regular grid that starts at the upper-left bound of each polygon. The centroid of each cell is then a +sample point. If the centroid is not enclosed in the polygon, no point is sampled. If no point can be +sampled for the geometry at all, the first coordinate of the geometry is returned as point. - For lines +(line strings), the sampling starts with a point at the first coordinate of the line and then walks along +the line and samples a new point each time the distance to the previous point has been reached again. - For +points, the point is returned as given.

    • +
    • group – Specifies whether the sampled points should be grouped by input geometry (default) or be +generated as independent points. * If the sampled points are grouped, the process generates a MultiPoint +per geometry given which keeps the original identifier if present. * Otherwise, each sampled point is +generated as a distinct Point geometry without identifier.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns a vector data cube with the sampled points.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “vector_to_regular_points”.

    +
    +
    + +
    +
    +openeo.processes.xor(x, y)[source]
    +

    Logical XOR (exclusive or)

    +
    +
    Parameters:
    +
      +
    • x – A boolean value.

    • +
    • y – A boolean value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical XOR.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “xor”.

    +
    +
    + +
    +
    +

    ProcessBuilder helper class

    +
    +
    +class openeo.processes.ProcessBuilder(pgnode)[source]
    +

    The ProcessBuilder class +is a helper class that implements +(much like the openEO process functions) +each openEO process as a method. +On top of that it also adds syntactic sugar to support Python operators as well +(e.g. + is translated to the add process).

    +
    +

    Attention

    +

    As normal user, you should never create a +ProcessBuilder instance +directly.

    +

    You should only interact with this class inside a callback +function/lambda while building a child callback process graph +as discussed at Callback as a callable.

    +
    +

    For example, let’s start from this simple usage snippet +where we want to reduce the temporal dimension +by taking the temporal mean of each timeseries:

    +
    def my_reducer(data):
    +    return data.mean()
    +
    +cube.reduce_dimension(reducer=my_reducer, dimension="t")
    +
    +
    +

    Note that this my_reducer function has a data argument, +which conceptually corresponds to an array of pixel values +(along the temporal dimension). +However, it’s important to understand that the my_reducer function +is actually not evaluated when you execute your process graph +on an openEO back-end, e.g. as a batch jobs. +Instead, my_reducer is evaluated +while building your process graph client-side +(at the time you execute that cube.reduce_dimension() statement to be precise). +This means that that data argument is actually not a concrete array of EO data, +but some kind of virtual placeholder, +a ProcessBuilder instance, +that keeps track of the operations you intend to do on the EO data.

    +

    To make that more concrete, it helps to add type hints +which will make it easier to discover what you can do with the argument +(depending on which editor or IDE you are using):

    +
    from openeo.processes import ProcessBuilder
    +
    +def my_reducer(data: ProcessBuilder) -> ProcessBuilder:
    +    return data.mean()
    +
    +cube.reduce_dimension(reducer=my_reducer, dimension="t")
    +
    +
    +

    Because ProcessBuilder methods +return new ProcessBuilder instances, +and because it support syntactic sugar to use Python operators on it, +and because openeo.process functions +also accept and return ProcessBuilder instances, +we can mix methods, functions and operators in the callback function like this:

    +
    from openeo.processes import ProcessBuilder, cos
    +
    +def my_reducer(data: ProcessBuilder) -> ProcessBuilder:
    +    return cos(data.mean()) + 1.23
    +
    +cube.reduce_dimension(reducer=my_reducer, dimension="t")
    +
    +
    +

    or compactly, using an anonymous lambda expression:

    +
    from openeo.processes import cos
    +
    +cube.reduce_dimension(
    +    reducer=lambda data: cos(data.mean())) + 1.23,
    +    dimension="t"
    +)
    +
    +
    +
    +
    +absolute()[source]
    +

    Absolute value

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed absolute value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “absolute”.

    +
    +
    + +
    +
    +add(y)[source]
    +

    Addition of two numbers

    +
    +
    Parameters:
    +
      +
    • self – The first summand.

    • +
    • y – The second summand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sum of the two numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “add”.

    +
    +
    + +
    +
    +add_dimension(name, label, type=<object object>)[source]
    +

    Add a new dimension

    +
    +
    Parameters:
    +
      +
    • self – A data cube to add the dimension to.

    • +
    • name – Name for the dimension.

    • +
    • label – A dimension label.

    • +
    • type – The type of dimension, defaults to other.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data cube with a newly added dimension. The new dimension has exactly one dimension label. +All other dimensions remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “add_dimension”.

    +
    +
    + +
    +
    +aggregate_spatial(geometries, reducer, target_dimension=<object object>, context=<object object>)[source]
    +

    Zonal statistics for geometries

    +
    +
    Parameters:
    +
      +
    • self – A raster data cube. The 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. 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.

    • +
    • geometries – Geometries as GeoJSON on which the aggregation will be based. Vector properties are +preserved for vector data cubes and all GeoJSON Features. One 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. - +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). - For +points, the process considers the closest pixel center. - For lines (line strings), the process +considers all the pixels whose centers are closest to at least one point on the line. Thus, pixels may +be part of multiple geometries and be part of multiple aggregations. To 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).

    • +
    • reducer – A reducer to be applied on all values of each geometry. 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.

    • +
    • target_dimension – The name of a new dimensions that is used to store the results. A new +dimension will be created with the given name and type other (see add_dimension()). Defaults to +the dimension name result. Fails with a TargetDimensionExists exception if a dimension with the +specified name exists.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A vector data cube with the computed results and restricted to the bounds of the geometries. +The computed value is used for the dimension with the name that was specified in the parameter +target_dimension. The 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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_spatial”.

    +
    +
    + +
    +
    +aggregate_spatial_window(reducer, size, boundary=<object object>, align=<object object>, context=<object object>)[source]
    +

    Zonal statistics for rectangular windows

    +
    +
    Parameters:
    +
      +
    • self – 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.

    • +
    • reducer – 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.

    • +
    • size – Window size in pixels along the horizontal spatial dimensions. The first value +corresponds to the x axis, the second value corresponds to the y axis.

    • +
    • boundary – 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: - pad (default): pad the data cube +with the no-data value null to fit the required window size. - trim: trim the data cube to fit the +required window size. Set the parameter align to specifies to which corner the data is aligned to.

    • +
    • align – 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The 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. The +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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_spatial_window”.

    +
    +
    + +
    +
    +aggregate_temporal(intervals, reducer, labels=<object object>, dimension=<object object>, context=<object object>)[source]
    +

    Temporal aggregations

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • intervals – Left-closed temporal intervals, which are allowed to overlap. Each temporal interval +in the array has exactly two elements: 1. The first element is the start of the temporal interval. The +specified instance in time is included in the interval. 2. The second element is the end of the +temporal interval. The specified instance in time is excluded from the interval. The 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.

    • +
    • reducer – 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.

    • +
    • labels – Distinct labels for the intervals, which can contain dates and/or times. Is only +required to be specified if the values for the start of the temporal intervals are not distinct and +thus the default labels would not be unique. The number of labels and the number of groups need to be +equal.

    • +
    • dimension – 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_temporal”.

    +
    +
    + +
    +
    +aggregate_temporal_period(period, reducer, dimension=<object object>, context=<object object>)[source]
    +

    Temporal aggregations based on calendar hierarchies

    +
    +
    Parameters:
    +
      +
    • self – The source data cube.

    • +
    • period – The time intervals to aggregate. The following pre-defined values are available: * +hour: Hour of the day * day: Day of the year * week: Week of the year * 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. * month: Month of the year * season: Three month periods of the calendar seasons (December - +February, March - May, June - August, September - November). * tropical-season: Six month periods of +the tropical seasons (November - April, May - October). * year: Proleptic years * 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. * 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.

    • +
    • reducer – 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.

    • +
    • dimension – 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 source 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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): * hour: YYYY-MM- +DD-00 - YYYY-MM-DD-23 * day: YYYY-001 - YYYY-365 * week: YYYY-01 - YYYY-52 * dekad: +YYYY-00 - YYYY-36 * month: YYYY-01 - YYYY-12 * season: YYYY-djf (December - February), +YYYY-mam (March - May), YYYY-jja (June - August), YYYY-son (September - November). * tropical- +season: YYYY-ndjfma (November - April), YYYY-mjjaso (May - October). * year: YYYY * decade: +YYY0 * decade-ad: YYY1 The dimension labels in the new data cube are complete for the whole +extent of the source data cube. For example, if period is set to day and the source data cube has +two dimension labels at the beginning of the year (2020-01-01) and the end of a year (2020-12-31), +the process returns a data cube with 365 dimension labels (2020-001, 2020-002, …, 2020-365). In +contrast, if period is set to day and the source data cube has just one dimension label +2020-01-05, the process returns a data cube with just a single dimension label (2020-005).

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_temporal_period”.

    +
    +
    + +
    +
    +all(ignore_nodata=<object object>)[source]
    +

    Are all of the values true?

    +
    +
    Parameters:
    +
      +
    • self – A set of boolean values.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not and ignores them by default.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical operation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “all”.

    +
    +
    + +
    +
    +and_(y)[source]
    +

    Logical AND

    +
    +
    Parameters:
    +
      +
    • self – A boolean value.

    • +
    • y – A boolean value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical AND.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “and_”.

    +
    +
    + +
    +
    +anomaly(normals, period)[source]
    +

    Compute anomalies

    +
    +
    Parameters:
    +
      +
    • self – A data cube with exactly one temporal dimension and the following dimension labels for the +given period (YYYY = four-digit year, MM = two-digit month, DD two-digit day of month): * +hour: YYYY-MM-DD-00 - YYYY-MM-DD-23 * day: YYYY-001 - YYYY-365 * week: YYYY-01 - +YYYY-52 * dekad: YYYY-00 - YYYY-36 * month: YYYY-01 - YYYY-12 * season: YYYY-djf +(December - February), YYYY-mam (March - May), YYYY-jja (June - August), YYYY-son (September - +November). * tropical-season: YYYY-ndjfma (November - April), YYYY-mjjaso (May - October). * +year: YYYY * decade: YYY0 * decade-ad: YYY1 * single-period / climatology-period: Any +aggregate_temporal_period() can compute such a data cube.

    • +
    • normals – A data cube with normals, e.g. daily, monthly or yearly values computed from a process +such as climatological_normal(). Must contain exactly one temporal dimension with the following +dimension labels for the given period: * hour: 00 - 23 * day: 001 - 365 * week: 01 - +52 * dekad: 00 - 36 * month: 01 - 12 * season: djf (December - February), mam +(March - May), jja (June - August), son (September - November) * tropical-season: ndjfma +(November - April), mjjaso (May - October) * year: Four-digit year numbers * decade: Four-digit +year numbers, the last digit being a 0 * decade-ad: Four-digit year numbers, the last digit being a +1 * single-period / climatology-period: A single dimension label with any name is expected.

    • +
    • period – Specifies the time intervals available in the normals data cube. The following options +are available: * hour: Hour of the day * day: Day of the year * week: Week of the year * +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. * month: Month of the year * season: Three month periods of the +calendar seasons (December - February, March - May, June - August, September - November). * tropical- +season: Six month periods of the tropical seasons (November - April, May - October). * year: +Proleptic years * 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. * 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. * single-period / +climatology-period: A single period of arbitrary length

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the same dimensions. The dimension properties (name, type, labels, reference +system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “anomaly”.

    +
    +
    + +
    +
    +any(ignore_nodata=<object object>)[source]
    +

    Is at least one value true?

    +
    +
    Parameters:
    +
      +
    • self – A set of boolean values.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not and ignores them by default.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical operation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “any”.

    +
    +
    + +
    +
    +apply(process, context=<object object>)[source]
    +

    Apply a process to each pixel

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • process – 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 absolute() or linear_scale_range().

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The dimension properties +(name, type, labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply”.

    +
    +
    + +
    +
    +apply_dimension(process, dimension, target_dimension=<object object>, context=<object object>)[source]
    +

    Apply a process to pixels along a dimension

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • process – 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.

    • +
    • dimension – The name of the source dimension to apply the process on. Fails with a +DimensionNotAvailable exception if the specified dimension does not exist.

    • +
    • target_dimension – The name of the target dimension or null (the default) to use the source +dimension specified in the parameter dimension. By 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.

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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 dimensions can change: +1. The source dimension is the target dimension: - The (number of) dimensions remain unchanged as +the source dimension is the target dimension. - The source dimension properties name and type remain +unchanged. - 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. 2. The source +dimension is not the target dimension and the latter exists: - The number of dimensions decreases by +one as the source dimension is dropped. - The target dimension properties name and type remain +unchanged. All other dimension properties change as defined in the list below. 3. The source dimension +is not the target dimension and the latter does not exist: - The number of dimensions remain +unchanged, but the source dimension is replaced with the target dimension. - The target dimension +has the specified name and the type other. All other dimension properties are set as defined in the +list below. Unless otherwise stated above, for the given (target) dimension the following applies: - +the number of dimension labels is equal to the number of values computed by the process, - the +dimension labels are incrementing integers starting from zero, - the resolution changes, and - the +reference system is undefined.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_dimension”.

    +
    +
    + +
    +
    +apply_kernel(kernel, factor=<object object>, border=<object object>, replace_invalid=<object object>)[source]
    +

    Apply a spatial convolution with a kernel

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • kernel – 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.

    • +
    • factor – A factor that is multiplied to each value after the kernel has been applied. This is +basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often +required for some kernel-based algorithms such as the Gaussian blur.

    • +
    • border – Determines how the data is extended when the kernel overlaps with the borders. Defaults +to fill the border with zeroes. The following options are available: * numeric value - fill with a +user-defined constant number n: nnnnnn|abcdefgh|nnnnnn (default, with n = 0) * replicate - +repeat the value from the pixel at the border: aaaaaa|abcdefgh|hhhhhh * reflect - mirror/reflect +from the border: fedcba|abcdefgh|hgfedc * reflect_pixel - mirror/reflect from the center of the +pixel at the border: gfedcb|abcdefgh|gfedcb * wrap - repeat/wrap the image: +cdefgh|abcdefgh|abcdef

    • +
    • replace_invalid – This parameter specifies the value to replace non-numerical or infinite +numerical values with. By default, those values are replaced with zeroes.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The dimension properties +(name, type, labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_kernel”.

    +
    +
    + +
    +
    +apply_neighborhood(process, size, overlap=<object object>, context=<object object>)[source]
    +

    Apply a process to pixels in a n-dimensional neighborhood

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • process – Process to be applied on all neighborhoods.

    • +
    • size – Neighborhood sizes along each dimension. This 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.

    • +
    • overlap – Overlap of neighborhoods along each dimension to avoid border effects. By default no +overlap is provided. For 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. Be aware that large overlaps increase the need for computational resources and modifying +overlapping data in subsequent operations have no effect.

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions. The dimension properties +(name, type, labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_neighborhood”.

    +
    +
    + +
    +
    +arccos()[source]
    +

    Inverse cosine

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arccos”.

    +
    +
    + +
    +
    +arcosh()[source]
    +

    Inverse hyperbolic cosine

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arcosh”.

    +
    +
    + +
    +
    +arcsin()[source]
    +

    Inverse sine

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arcsin”.

    +
    +
    + +
    +
    +arctan()[source]
    +

    Inverse tangent

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arctan”.

    +
    +
    + +
    +
    +arctan2(x)[source]
    +

    Inverse tangent of two numbers

    +
    +
    Parameters:
    +
      +
    • self – A number to be used as the dividend.

    • +
    • x – A number to be used as the divisor.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arctan2”.

    +
    +
    + +
    +
    +ard_normalized_radar_backscatter(elevation_model=<object object>, contributing_area=<object object>, ellipsoid_incidence_angle=<object object>, noise_removal=<object object>, options=<object object>)[source]
    +

    CARD4L compliant SAR NRB generation

    +
    +
    Parameters:
    +
      +
    • self – The source data cube containing SAR input.

    • +
    • elevation_model – 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.

    • +
    • contributing_area – If set to true, a DEM-based local contributing area band named +contributing_area is added. The values are given in square meters.

    • +
    • ellipsoid_incidence_angle – If set to true, an ellipsoidal incidence angle band named +ellipsoid_incidence_angle is added. The values are given in degrees.

    • +
    • noise_removal – If set to false, no noise removal is applied. Defaults to true, which removes +noise.

    • +
    • options – Proprietary options for the backscatter computations. Specifying proprietary options +will reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Backscatter values expressed as gamma0 in linear scale. In 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: - mask: A data mask that +indicates which values are valid (1), invalid (0) or contain no-data (null). - local_incidence_angle: +A band with DEM-based local incidence angles in degrees. The data returned is CARD4L compliant with +corresponding metadata.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ard_normalized_radar_backscatter”.

    +
    +
    + +
    +
    +ard_surface_reflectance(atmospheric_correction_method, cloud_detection_method, elevation_model=<object object>, atmospheric_correction_options=<object object>, cloud_detection_options=<object object>)[source]
    +

    CARD4L compliant Surface Reflectance generation

    +
    +
    Parameters:
    +
      +
    • self – The source data cube containing multi-spectral optical top of the atmosphere (TOA) +reflectances. There must be a single dimension of type bands available.

    • +
    • atmospheric_correction_method – The atmospheric correction method to use.

    • +
    • cloud_detection_method – The cloud detection method to use. Each method supports detecting +different atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water +vapour in optical imagery.

    • +
    • elevation_model – 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.

    • +
    • atmospheric_correction_options – Proprietary options for the atmospheric correction method. +Specifying proprietary options will reduce portability.

    • +
    • cloud_detection_options – Proprietary options for the cloud detection method. Specifying +proprietary options will reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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: 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. Depending on the +methods used, several additional bands will be added to the data cube: - date (optional): Specifies +per-pixel acquisition timestamps. - 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. - 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. - 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. - 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. - 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. - incidence-angle (optional): Specifies per-pixel incidence angles in degrees. - azimuth +(optional): Specifies per-pixel azimuth angles in degrees. - sun-azimuth: (optional): Specifies per- +pixel sun azimuth angles in degrees. - sun-elevation (optional): Specifies per-pixel sun elevation +angles in degrees. - 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. - 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. - terrain-illumination (optional): +Contains coefficients used for terrain illumination correction are provided for each pixel. The data +returned is CARD4L compliant with corresponding metadata.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ard_surface_reflectance”.

    +
    +
    + +
    +
    +array_append(value, label=<object object>)[source]
    +

    Append a value to an array

    +
    +
    Parameters:
    +
      +
    • self – An array.

    • +
    • value – Value to append to the array.

    • +
    • label – If the given array is a labeled array, a new label for the new value should be given. If +not given or null, the array index as string is used as the label. If in any case the label exists, a +LabelExists exception is thrown.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The new array with the value being appended.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_append”.

    +
    +
    + +
    +
    +array_apply(process, context=<object object>)[source]
    +

    Apply a process to each array element

    +
    +
    Parameters:
    +
      +
    • self – An array.

    • +
    • process – 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 absolute() or linear_scale_range().

    • +
    • context – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the newly computed values. The number of elements are the same as for the +original array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_apply”.

    +
    +
    + +
    +
    +array_concat(array2)[source]
    +

    Merge two arrays

    +
    +
    Parameters:
    +
      +
    • self – The first array.

    • +
    • array2 – The second array.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The merged array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_concat”.

    +
    +
    + +
    +
    +array_contains(value)[source]
    +

    Check whether the array contains a given value

    +
    +
    Parameters:
    +
      +
    • self – List to find the value in.

    • +
    • value – Value to find in data. If the value is null, this process returns always false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the list contains the value, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_contains”.

    +
    +
    + +
    +
    +array_create(repeat=<object object>)[source]
    +

    Create an array

    +
    +
    Parameters:
    +
      +
    • self – A (native) array to fill the newly created array with. Defaults to an empty array.

    • +
    • repeat – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The newly created array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_create”.

    +
    +
    + +
    +
    +array_create_labeled(labels)[source]
    +

    Create a labeled array

    +
    +
    Parameters:
    +
      +
    • self – An array of values to be used.

    • +
    • labels – An array of labels to be used.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The newly created labeled array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_create_labeled”.

    +
    +
    + +
    +
    +array_element(index=<object object>, label=<object object>, return_nodata=<object object>)[source]
    +

    Get an element from an array

    +
    +
    Parameters:
    +
      +
    • self – An array.

    • +
    • index – The zero-based index of the element to retrieve.

    • +
    • label – 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.

    • +
    • return_nodata – By default this process throws an ArrayElementNotAvailable exception if the +index or label is invalid. If you want to return null instead, set this flag to true.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The value of the requested element.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_element”.

    +
    +
    + +
    +
    +array_filter(condition, context=<object object>)[source]
    +

    Filter an array based on a condition

    +
    +
    Parameters:
    +
      +
    • self – An array.

    • +
    • condition – 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.

    • +
    • context – Additional data to be passed to the condition.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array filtered by the specified condition. The number of elements are less than or equal +compared to the original array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_filter”.

    +
    +
    + +
    +
    +array_find(value, reverse=<object object>)[source]
    +

    Get the index for a value in an array

    +
    +
    Parameters:
    +
      +
    • self – List to find the value in.

    • +
    • value – Value to find in data. If the value is null, this process returns always null.

    • +
    • reverse – By default, this process finds the index of the first match. To return the index of the +last match instead, set this flag to true.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The index of the first element with the specified value. If no element was found, null is +returned.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_find”.

    +
    +
    + +
    +
    +array_find_label(label)[source]
    +

    Get the index for a label in a labeled array

    +
    +
    Parameters:
    +
      +
    • self – List to find the label in.

    • +
    • label – Label to find in data.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The index of the element with the specified label assigned. If no such label was found, null +is returned.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_find_label”.

    +
    +
    + +
    +
    +array_interpolate_linear()[source]
    +

    One-dimensional linear interpolation for arrays

    +
    +
    Parameters:
    +

    self – An array of numbers and no-data values. If 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.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_interpolate_linear”.

    +
    +
    + +
    +
    +array_labels()[source]
    +

    Get the labels for an array

    +
    +
    Parameters:
    +

    self – An array.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The labels or indices as array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_labels”.

    +
    +
    + +
    +
    +array_modify(values, index, length=<object object>)[source]
    +

    Change the content of an array (remove, insert, update)

    +
    +
    Parameters:
    +
      +
    • self – The array to modify.

    • +
    • values – The values to insert into the data array.

    • +
    • index – The index in the data array of the element to insert the value(s) before. If the index +is greater than the number of elements in the data array, the process throws an +ArrayElementNotAvailable exception. To insert after the last element, there are two options: 1. Use +the simpler processes array_append() to append a single value or array_concat() to append +multiple values. 2. 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.

    • +
    • length – The number of elements in the data array to remove (or replace) starting from the +given index. If the array contains fewer elements, the process simply removes all elements up to the +end.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with values added, updated or removed.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “array_modify”.

    +
    +
    + +
    +
    +arsinh()[source]
    +

    Inverse hyperbolic sine

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “arsinh”.

    +
    +
    + +
    +
    +artanh()[source]
    +

    Inverse hyperbolic tangent

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed angle in radians.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “artanh”.

    +
    +
    + +
    +
    +atmospheric_correction(method, elevation_model=<object object>, options=<object object>)[source]
    +

    Apply atmospheric correction

    +
    +
    Parameters:
    +
      +
    • self – Data cube containing multi-spectral optical top of atmosphere reflectances to be +corrected.

    • +
    • method – The atmospheric correction method to use. To get reproducible results, you have to set a +specific method. Set 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.

    • +
    • elevation_model – 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.

    • +
    • options – Proprietary options for the atmospheric correction method. Specifying proprietary +options will reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Data cube containing bottom of atmosphere reflectances.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “atmospheric_correction”.

    +
    +
    + +
    +
    +between(min, max, exclude_max=<object object>)[source]
    +

    Between comparison

    +
    +
    Parameters:
    +
      +
    • self – The value to check.

    • +
    • min – Lower boundary (inclusive) to check against.

    • +
    • max – Upper boundary (inclusive) to check against.

    • +
    • exclude_max – Exclude the upper boundary max if set to true. Defaults to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is between the specified bounds, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “between”.

    +
    +
    + +
    +
    +ceil()[source]
    +

    Round fractions up

    +
    +
    Parameters:
    +

    self – A number to round up.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The number rounded up.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ceil”.

    +
    +
    + +
    +
    +climatological_normal(period, climatology_period=<object object>)[source]
    +

    Compute climatology normals

    +
    +
    Parameters:
    +
      +
    • self – A data cube with exactly one temporal dimension. The data cube must span at least the +temporal interval specified in the parameter climatology-period. Seasonal periods may span two +consecutive years, e.g. temporal winter that includes months December, January and February. If the +required months before the actual climate period are available, the season is taken into account. If +not available, the first season is not taken into account and the seasonal mean is based on one year +less than the other seasonal normals. The incomplete season at the end of the last year is never taken +into account.

    • +
    • period – The time intervals to aggregate the average value for. The following pre-defined +frequencies are supported: * day: Day of the year * month: Month of the year * climatology- +period: The period specified in the climatology-period. * season: Three month periods of the +calendar seasons (December - February, March - May, June - August, September - November). * tropical- +season: Six month periods of the tropical seasons (November - April, May - October).

    • +
    • climatology_period – 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).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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 temporal +dimension. The temporal dimension has the following dimension labels: * day: 001 - 365 * +month: 01 - 12 * climatology-period: climatology-period * season: djf (December - +February), mam (March - May), jja (June - August), son (September - November) * tropical- +season: ndjfma (November - April), mjjaso (May - October)

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “climatological_normal”.

    +
    +
    + +
    +
    +clip(min, max)[source]
    +

    Clip a value between a minimum and a maximum

    +
    +
    Parameters:
    +
      +
    • self – A number.

    • +
    • min – Minimum value. If the value is lower than this value, the process will return the value of +this parameter.

    • +
    • max – Maximum value. If the value is greater than this value, the process will return the value +of this parameter.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The value clipped to the specified range.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “clip”.

    +
    +
    + +
    +
    +cloud_detection(method, options=<object object>)[source]
    +

    Create cloud masks

    +
    +
    Parameters:
    +
      +
    • self – The source data cube containing multi-spectral optical top of the atmosphere (TOA) +reflectances on which to perform cloud detection.

    • +
    • method – The cloud detection method to use. To get reproducible results, you have to set a +specific method. Set 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.

    • +
    • options – Proprietary options for the cloud detection method. Specifying proprietary options will +reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cloud_detection”.

    +
    +
    + +
    +
    +constant()[source]
    +

    Define a constant value

    +
    +
    Parameters:
    +

    self – The value of the constant.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The value of the constant.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “constant”.

    +
    +
    + +
    +
    +cos()[source]
    +

    Cosine

    +
    +
    Parameters:
    +

    self – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed cosine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cos”.

    +
    +
    + +
    +
    +cosh()[source]
    +

    Hyperbolic cosine

    +
    +
    Parameters:
    +

    self – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed hyperbolic cosine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cosh”.

    +
    +
    + +
    +
    +count(condition=<object object>, context=<object object>)[source]
    +

    Count the number of elements

    +
    +
    Parameters:
    +
      +
    • self – An array with elements of any data type.

    • +
    • condition – 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.

    • +
    • context – Additional data to be passed to the condition.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The counted number of elements.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “count”.

    +
    +
    + +
    +
    +create_raster_cube()[source]
    +

    Create an empty raster data cube

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An empty raster data cube with zero dimensions.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “create_raster_cube”.

    +
    +
    + +
    +
    +cummax(ignore_nodata=<object object>)[source]
    +

    Cumulative maxima

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative maxima.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cummax”.

    +
    +
    + +
    +
    +cummin(ignore_nodata=<object object>)[source]
    +

    Cumulative minima

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative minima.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cummin”.

    +
    +
    + +
    +
    +cumproduct(ignore_nodata=<object object>)[source]
    +

    Cumulative products

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative products.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cumproduct”.

    +
    +
    + +
    +
    +cumsum(ignore_nodata=<object object>)[source]
    +

    Cumulative sums

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed cumulative sums.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “cumsum”.

    +
    +
    + +
    +
    +date_shift(value, unit)[source]
    +

    Manipulates dates and times by addition or subtraction

    +
    +
    Parameters:
    +
      +
    • self – The date (and optionally time) to manipulate. If 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.

    • +
    • value – 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.

    • +
    • unit – The unit for the value given. The following pre-defined units are available: - +millisecond: Milliseconds - second: Seconds - leap seconds are ignored in computations. - minute: +Minutes - hour: Hours - day: Days - changes only the the day part of a date - week: Weeks (equivalent +to 7 days) - month: Months - year: Years Manipulations 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The manipulated date. If a time component was given in the parameter date, the time +component is returned with the date.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “date_shift”.

    +
    +
    + +
    +
    +dimension_labels(dimension)[source]
    +

    Get the dimension labels

    +
    +
    Parameters:
    +
      +
    • self – The data cube.

    • +
    • dimension – The name of the dimension to get the labels for.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The labels as an array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “dimension_labels”.

    +
    +
    + +
    +
    +divide(y)[source]
    +

    Division of two numbers

    +
    +
    Parameters:
    +
      +
    • self – The dividend.

    • +
    • y – The divisor.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed result.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “divide”.

    +
    +
    + +
    +
    +drop_dimension(name)[source]
    +

    Remove a dimension

    +
    +
    Parameters:
    +
      +
    • self – The data cube to drop a dimension from.

    • +
    • name – Name of the dimension to drop.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube without the specified dimension. The number of dimensions decreases by one, but +the dimension properties (name, type, labels, reference system and resolution) for all other dimensions +remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “drop_dimension”.

    +
    +
    + +
    +
    +e()[source]
    +

    Euler’s number (e)

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The numerical value of Euler’s number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “e”.

    +
    +
    + +
    +
    +eq(y, delta=<object object>, case_sensitive=<object object>)[source]
    +

    Equal to comparison

    +
    +
    Parameters:
    +
      +
    • self – First operand.

    • +
    • y – Second operand.

    • +
    • delta – 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. +This option is basically an alias for the following computation: lte(abs(minus([x, y]), delta)

    • +
    • case_sensitive – Only applicable for comparing two strings. Case sensitive comparison can be +disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is equal to y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “eq”.

    +
    +
    + +
    +
    +exp()[source]
    +

    Exponentiation to the base e

    +
    +
    Parameters:
    +

    self – The numerical exponent.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed value for e raised to the power of p.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “exp”.

    +
    +
    + +
    +
    +extrema(ignore_nodata=<object object>)[source]
    +

    Minimum and maximum values

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not. Ignores them by default. +Setting this flag to false considers no-data values so that an array with two null values is +returned if any value is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array containing the minimum and maximum values for the specified numbers. The first +element is the minimum, the second element is the maximum. If the input array is empty both elements +are set to null.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “extrema”.

    +
    +
    + +
    +
    +filter_bands(bands=<object object>, wavelengths=<object object>)[source]
    +

    Filter the bands by names

    +
    +
    Parameters:
    +
      +
    • self – A data cube with bands.

    • +
    • bands – 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. The 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.

    • +
    • wavelengths – 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). The 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube limited to a subset of its original bands. The dimensions and dimension properties +(name, type, labels, reference system and resolution) remain unchanged, except that the dimension of +type bands has less (or the same) dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bands”.

    +
    +
    + +
    +
    +filter_bbox(extent)[source]
    +

    Spatial filter using a bounding box

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • extent – A bounding box, which may include a vertical axis (see base and height).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube restricted to the bounding box. The dimensions and dimension properties (name, +type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions +have less (or the same) dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bbox”.

    +
    +
    + +
    +
    +filter_labels(condition, dimension, context=<object object>)[source]
    +

    Filter dimension labels based on a condition

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • condition – A condition that is evaluated against each dimension label in the specified +dimension. A dimension label and the corresponding data is preserved for the given dimension, if the +condition returns true.

    • +
    • dimension – The name of the dimension to filter on. Fails with a DimensionNotAvailable +exception if the specified dimension does not exist.

    • +
    • context – Additional data to be passed to the condition.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the same dimensions. The dimension properties (name, type, labels, reference +system and resolution) remain unchanged, except that the given dimension has less (or the same) +dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_labels”.

    +
    +
    + +
    +
    +filter_spatial(geometries)[source]
    +

    Spatial filter using geometries

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • geometries – One or more geometries used for filtering, specified as GeoJSON.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube restricted to the specified geometries. The dimensions and dimension properties +(name, type, labels, reference system and resolution) remain unchanged, except that the spatial +dimensions have less (or the same) dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_spatial”.

    +
    +
    + +
    +
    +filter_temporal(extent, dimension=<object object>)[source]
    +

    Temporal filter based on temporal intervals

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • extent – Left-closed temporal interval, i.e. an array with exactly two elements: 1. The first +element is the start of the temporal interval. The specified instance in time is included in the +interval. 2. The second element is the end of the temporal interval. The specified instance in time is +excluded from the interval. The 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.

    • +
    • dimension – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_temporal”.

    +
    +
    + +
    +
    +first(ignore_nodata=<object object>)[source]
    +

    First element

    +
    +
    Parameters:
    +
      +
    • self – An array with elements of any data type.

    • +
    • ignore_nodata – 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 returned if the first value is +such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The first element of the input array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “first”.

    +
    +
    + +
    +
    +fit_class_random_forest(target, max_variables, num_trees=<object object>, seed=<object object>)[source]
    +

    Train a random forest classification model

    +
    +
    Parameters:
    +
      +
    • self – The predictors for the classification model as a vector data cube. Aggregated to the +features (vectors) of the target input variable.

    • +
    • target – The training sites for the classification model as a vector data cube. This is +associated with the target variable for the Random Forest model. The geometry has to associated with a +value to predict (e.g. fractional forest canopy cover).

    • +
    • max_variables – Specifies how many split variables will be used at a node. The following options +are available: - integer: The given number of variables are considered for each split. - all: All +variables are considered for each split. - log2: The logarithm with base 2 of the number of variables +are considered for each split. - onethird: A third of the number of variables are considered for each +split. - sqrt: The square root of the number of variables are considered for each split. This is +often the default for classification.

    • +
    • num_trees – The number of trees build within the Random Forest classification.

    • +
    • seed – A randomization seed to use for the random sampling in training. If not given or null, +no seed is used and results may differ on subsequent use.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A model object that can be saved with save_ml_model() and restored with +load_ml_model().

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_class_random_forest”.

    +
    +
    + +
    +
    +fit_curve(parameters, function, dimension)[source]
    +

    Curve fitting

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • parameters – Defined the number of parameters for the model function and provides an initial +guess for them. At least one parameter is required.

    • +
    • function – The model function. It must take the parameters to fit as array through the first +argument and the independent variable x as the second argument. It is recommended to store the model +function as a user-defined process on the back-end to be able to re-use the model function with the +computed optimal values for the parameters afterwards.

    • +
    • dimension – The name of the dimension for curve fitting. Must be a dimension with labels that +have a order (i.e. numerical labels or a temporal dimension). Fails with a DimensionNotAvailable +exception if the specified dimension does not exist.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the optimal values for the parameters.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_curve”.

    +
    +
    + +
    +
    +fit_regr_random_forest(target, max_variables, num_trees=<object object>, seed=<object object>)[source]
    +

    Train a random forest regression model

    +
    +
    Parameters:
    +
      +
    • self – The predictors for the regression model as a vector data cube. Aggregated to the features +(vectors) of the target input variable.

    • +
    • target – The training sites for the regression model as a vector data cube. This is associated +with the target variable for the Random Forest model. The geometry has to associated with a value to +predict (e.g. fractional forest canopy cover).

    • +
    • max_variables – Specifies how many split variables will be used at a node. The following options +are available: - integer: The given number of variables are considered for each split. - all: All +variables are considered for each split. - log2: The logarithm with base 2 of the number of variables +are considered for each split. - onethird: A third of the number of variables are considered for each +split. This is often the default for regression. - sqrt: The square root of the number of variables +are considered for each split.

    • +
    • num_trees – The number of trees build within the Random Forest regression.

    • +
    • seed – A randomization seed to use for the random sampling in training. If not given or null, +no seed is used and results may differ on subsequent use.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A model object that can be saved with save_ml_model() and restored with +load_ml_model().

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_regr_random_forest”.

    +
    +
    + +
    +
    +flatten_dimensions(dimensions, target_dimension, label_separator=<object object>)[source]
    +

    Combine multiple dimensions into a single dimension

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • dimensions – The names of the dimension to combine. The order of the array defines the order in +which the dimension labels and values are combined (see the example in the process description). Fails +with a DimensionNotAvailable exception if at least one of the specified dimensions does not exist.

    • +
    • target_dimension – The name of the new target dimension. A new dimensions will be created with +the given names and type other (see add_dimension()). Fails with a TargetDimensionExists +exception if a dimension with the specified name exists.

    • +
    • label_separator – The string that will be used as a separator for the concatenated dimension +labels. To unambiguously revert the dimension labels with the process unflatten_dimension(), the +given string must not be contained in any of the dimension labels.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the new shape. The dimension properties (name, type, labels, reference system +and resolution) for all other dimensions remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “flatten_dimensions”.

    +
    +
    + +
    +
    +floor()[source]
    +

    Round fractions down

    +
    +
    Parameters:
    +

    self – A number to round down.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The number rounded down.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “floor”.

    +
    +
    + +
    +
    +gt(y)[source]
    +

    Greater than comparison

    +
    +
    Parameters:
    +
      +
    • self – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is strictly greater than y or null if any operand is null, otherwise +false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “gt”.

    +
    +
    + +
    +
    +gte(y)[source]
    +

    Greater than or equal to comparison

    +
    +
    Parameters:
    +
      +
    • self – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is greater than or equal to y, null if any operand is null, otherwise +false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “gte”.

    +
    +
    + +
    +
    +if_(accept, reject=<object object>)[source]
    +

    If-Then-Else conditional

    +
    +
    Parameters:
    +
      +
    • self – A boolean value.

    • +
    • accept – A value that is returned if the boolean value is true.

    • +
    • reject – A value that is returned if the boolean value is not true. Defaults to null.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Either the accept or reject argument depending on the given boolean value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “if_”.

    +
    +
    + +
    +
    +inspect(code=<object object>, level=<object object>, message=<object object>)[source]
    +

    Add information to the logs

    +
    +
    Parameters:
    +
      +
    • self – Data to log.

    • +
    • code – A label to help identify one or more log entries originating from this process in the list +of all log entries. It can help to group or filter log entries and is usually not unique.

    • +
    • level – The severity level of this message, defaults to info.

    • +
    • message – A message to send in addition to the data.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data as passed to the data parameter without any modification.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “inspect”.

    +
    +
    + +
    +
    +int()[source]
    +

    Integer part of a number

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Integer part of the number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “int”.

    +
    +
    + +
    +
    +is_infinite()[source]
    +

    Value is an infinite number

    +
    +
    Parameters:
    +

    self – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is an infinite number, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_infinite”.

    +
    +
    + +
    +
    +is_nan()[source]
    +

    Value is not a number

    +
    +
    Parameters:
    +

    self – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is not a number, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_nan”.

    +
    +
    + +
    +
    +is_nodata()[source]
    +

    Value is a no-data value

    +
    +
    Parameters:
    +

    self – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is a no-data value, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_nodata”.

    +
    +
    + +
    +
    +is_valid()[source]
    +

    Value is valid data

    +
    +
    Parameters:
    +

    self – The data to check.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if the data is valid, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “is_valid”.

    +
    +
    + +
    +
    +last(ignore_nodata=<object object>)[source]
    +

    Last element

    +
    +
    Parameters:
    +
      +
    • self – An array with elements of any data type.

    • +
    • ignore_nodata – 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 returned if the last value is +such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The last element of the input array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “last”.

    +
    +
    + +
    +
    +linear_scale_range(inputMin, inputMax, outputMin=<object object>, outputMax=<object object>)[source]
    +

    Linear transformation between two ranges

    +
    +
    Parameters:
    +
      +
    • self – A number to transform. The number gets clipped to the bounds specified in inputMin and +inputMax.

    • +
    • inputMin – Minimum value the input can obtain.

    • +
    • inputMax – Maximum value the input can obtain.

    • +
    • outputMin – Minimum value of the desired output range.

    • +
    • outputMax – Maximum value of the desired output range.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The transformed number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “linear_scale_range”.

    +
    +
    + +
    +
    +ln()[source]
    +

    Natural logarithm

    +
    +
    Parameters:
    +

    self – A number to compute the natural logarithm for.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed natural logarithm.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ln”.

    +
    +
    + +
    +
    +load_collection(spatial_extent, temporal_extent, bands=<object object>, properties=<object object>)[source]
    +

    Load a collection

    +
    +
    Parameters:
    +
      +
    • self – The collection id.

    • +
    • spatial_extent – Limits the data to load from the collection to the specified bounding box or +polygons. The 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). The +GeoJSON can be one of the following feature types: * A Polygon or MultiPolygon geometry, * a +Feature with a Polygon or MultiPolygon geometry, * a FeatureCollection containing at least one +Feature with Polygon or MultiPolygon geometries, or * a GeometryCollection containing Polygon +or MultiPolygon geometries. To maximize interoperability, GeometryCollection should be avoided in +favour of one of the alternatives above. Set 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.

    • +
    • temporal_extent – 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: 1. The first element is the start of the temporal interval. The specified +instance in time is included in the interval. 2. The second element is the end of the temporal +interval. The specified instance in time is excluded from the interval. The 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. Set 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.

    • +
    • bands – 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. Either 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. The 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. It is +recommended to use this parameter instead of using filter_bands() directly after loading unbounded +data.

    • +
    • properties – Limits the data by metadata properties to include only data in the data cube which +all given conditions return true for (AND operation). Specify key-value-pairs with the key being the +name of the metadata property, which can be retrieved with the openEO Data Discovery for Collections. +The value must be a condition (user-defined process) to be evaluated against the collection metadata, +see the example.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube for further processing. The dimensions and dimension properties (name, type, +labels, reference system and resolution) correspond to the collection’s metadata, but the dimension +labels are restricted as specified in the parameters.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_collection”.

    +
    +
    + +
    +
    +load_ml_model()[source]
    +

    Load a ML model

    +
    +
    Parameters:
    +

    self – The STAC Item to load the machine learning model from. The STAC Item must implement the +ml-model extension.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A machine learning model to be used with machine learning processes such as +predict_random_forest().

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_ml_model”.

    +
    +
    + +
    +
    +load_result(spatial_extent=<object object>, temporal_extent=<object object>, bands=<object object>)[source]
    +

    Load batch job results

    +
    +
    Parameters:
    +
      +
    • self – The id of a batch job with results.

    • +
    • spatial_extent – Limits the data to load from the batch job result to the specified bounding box +or polygons. The 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). +The GeoJSON can be one of the following feature types: * A Polygon or MultiPolygon geometry, * a +Feature with a Polygon or MultiPolygon geometry, * a FeatureCollection containing at least one +Feature with Polygon or MultiPolygon geometries, or * a GeometryCollection containing Polygon +or MultiPolygon geometries. To maximize interoperability, GeometryCollection should be avoided in +favour of one of the alternatives above. Set 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.

    • +
    • temporal_extent – Limits the data to load from the batch job result 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: 1. The first element is the start of the temporal interval. The specified +instance in time is included in the interval. 2. The second element is the end of the temporal +interval. The specified instance in time is excluded from the interval. The 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. Set 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.

    • +
    • bands – 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. Either 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. The 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. It is +recommended to use this parameter instead of using filter_bands() directly after loading unbounded +data.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube for further processing.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_result”.

    +
    +
    + +
    +
    +load_uploaded_files(format, options=<object object>)[source]
    +

    Load files from the user workspace

    +
    +
    Parameters:
    +
      +
    • self – The files to read. Folders can’t be specified, specify all files instead. An exception is +thrown if a file can’t be read.

    • +
    • format – The file format to read from. It must be one of the values that the server reports as +supported input file formats, which usually correspond to the short GDAL/OGR codes. If the format is +not suitable for loading the data, a FormatUnsuitable exception will be thrown. This parameter is +case insensitive.

    • +
    • options – The file format parameters to be used to read the files. Must correspond to the +parameters that the server reports as supported parameters for the chosen format. The parameter names +and valid values usually correspond to the GDAL/OGR format options.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube for further processing.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_uploaded_files”.

    +
    +
    + +
    +
    +log(base)[source]
    +

    Logarithm to a base

    +
    +
    Parameters:
    +
      +
    • self – A number to compute the logarithm for.

    • +
    • base – The numerical base.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed logarithm.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “log”.

    +
    +
    + +
    +
    +lt(y)[source]
    +

    Less than comparison

    +
    +
    Parameters:
    +
      +
    • self – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is strictly less than y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “lt”.

    +
    +
    + +
    +
    +lte(y)[source]
    +

    Less than or equal to comparison

    +
    +
    Parameters:
    +
      +
    • self – First operand.

    • +
    • y – Second operand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is less than or equal to y, null if any operand is null, otherwise +false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “lte”.

    +
    +
    + +
    +
    +mask(mask, replacement=<object object>)[source]
    +

    Apply a raster mask

    +
    +
    Parameters:
    +
      +
    • self – A raster data cube.

    • +
    • mask – A mask as a raster data cube. Every pixel in data must have a corresponding element in +mask.

    • +
    • replacement – The value used to replace masked values with.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A masked raster data cube with the same dimensions. The dimension properties (name, type, +labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mask”.

    +
    +
    + +
    +
    +mask_polygon(mask, replacement=<object object>, inside=<object object>)[source]
    +

    Apply a polygon mask

    +
    +
    Parameters:
    +
      +
    • self – A raster data cube.

    • +
    • mask – A GeoJSON object containing at least one polygon. The provided feature types can be one of +the following: * A Polygon or MultiPolygon geometry, * a Feature with a Polygon or +MultiPolygon geometry, * a FeatureCollection containing at least one Feature with Polygon or +MultiPolygon geometries, or * a GeometryCollection containing Polygon or MultiPolygon +geometries. To maximize interoperability, GeometryCollection should be avoided in favour of one of +the alternatives above.

    • +
    • replacement – The value used to replace masked values with.

    • +
    • inside – If set to true all pixels for which the point at the pixel center does intersect +with any polygon are replaced.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A masked raster data cube with the same dimensions. The dimension properties (name, type, +labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mask_polygon”.

    +
    +
    + +
    +
    +max(ignore_nodata=<object object>)[source]
    +

    Maximum value

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The maximum value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “max”.

    +
    +
    + +
    +
    +mean(ignore_nodata=<object object>)[source]
    +

    Arithmetic mean (average)

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed arithmetic mean.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mean”.

    +
    +
    + +
    +
    +median(ignore_nodata=<object object>)[source]
    +

    Statistical median

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed statistical median.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “median”.

    +
    +
    + +
    +
    +merge_cubes(cube2, overlap_resolver=<object object>, context=<object object>)[source]
    +

    Merge two data cubes

    +
    +
    Parameters:
    +
      +
    • self – The first data cube.

    • +
    • cube2 – The second data cube.

    • +
    • overlap_resolver – A reduction operator that resolves the conflict if the data overlaps. The +reducer must return a value of the same data type as the input values are. The reduction operator may +be a single process such as multiply() or consist of multiple sub-processes. null (the default) +can be specified if no overlap resolver is required.

    • +
    • context – Additional data to be passed to the overlap resolver.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The merged data cube. See the process description for details regarding the dimensions and +dimension properties (name, type, labels, reference system and resolution).

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “merge_cubes”.

    +
    +
    + +
    +
    +min(ignore_nodata=<object object>)[source]
    +

    Minimum value

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The minimum value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “min”.

    +
    +
    + +
    +
    +mod(y)[source]
    +

    Modulo

    +
    +
    Parameters:
    +
      +
    • self – A number to be used as the dividend.

    • +
    • y – A number to be used as the divisor.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The remainder after division.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mod”.

    +
    +
    + +
    +
    +multiply(y)[source]
    +

    Multiplication of two numbers

    +
    +
    Parameters:
    +
      +
    • self – The multiplier.

    • +
    • y – The multiplicand.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed product of the two numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “multiply”.

    +
    +
    + +
    +
    +nan()[source]
    +

    Not a Number (NaN)

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns NaN.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “nan”.

    +
    +
    + +
    +
    +ndvi(nir=<object object>, red=<object object>, target_band=<object object>)[source]
    +

    Normalized Difference Vegetation Index

    +
    +
    Parameters:
    +
      +
    • self – A raster data cube with two bands that have the common names red and nir assigned.

    • +
    • nir – The name of the NIR band. Defaults to the band that has the common name nir assigned. +Either 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.

    • +
    • red – The name of the red band. Defaults to the band that has the common name red assigned. +Either 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.

    • +
    • target_band – By default, the dimension of type bands is dropped. To keep the dimension specify +a new band name in this parameter so that a new dimension label with the specified name will be added +for the computed values.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A raster data cube containing the computed NDVI values. The structure of the data cube differs +depending on the value passed to target_band: * 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. * 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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ndvi”.

    +
    +
    + +
    +
    +neq(y, delta=<object object>, case_sensitive=<object object>)[source]
    +

    Not equal to comparison

    +
    +
    Parameters:
    +
      +
    • self – First operand.

    • +
    • y – Second operand.

    • +
    • delta – 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. +This option is basically an alias for the following computation: gt(abs(minus([x, y]), delta)

    • +
    • case_sensitive – Only applicable for comparing two strings. Case sensitive comparison can be +disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if x is not equal to y, null if any operand is null, otherwise false.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “neq”.

    +
    +
    + +
    +
    +normalized_difference(y)[source]
    +

    Normalized difference

    +
    +
    Parameters:
    +
      +
    • self – The value for the first band.

    • +
    • y – The value for the second band.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed normalized difference.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “normalized_difference”.

    +
    +
    + +
    +
    +not_()[source]
    +

    Inverting a boolean

    +
    +
    Parameters:
    +

    self – Boolean value to invert.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Inverted boolean value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “not_”.

    +
    +
    + +
    +
    +or_(y)[source]
    +

    Logical OR

    +
    +
    Parameters:
    +
      +
    • self – A boolean value.

    • +
    • y – A boolean value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical OR.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “or_”.

    +
    +
    + +
    +
    +order(asc=<object object>, nodata=<object object>)[source]
    +

    Create a permutation

    +
    +
    Parameters:
    +
      +
    • self – An array to compute the order for.

    • +
    • asc – The default sort order is ascending, with smallest values first. To sort in reverse +(descending) order, set this parameter to false.

    • +
    • nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed permutation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “order”.

    +
    +
    + +
    +
    +pi()[source]
    +

    Pi (π)

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The numerical value of Pi.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “pi”.

    +
    +
    + +
    +
    +power(p)[source]
    +

    Exponentiation

    +
    +
    Parameters:
    +
      +
    • self – The numerical base.

    • +
    • p – The numerical exponent.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed value for base raised to the power of p.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “power”.

    +
    +
    + +
    +
    +predict_curve(parameters, function, dimension, labels=<object object>)[source]
    +

    Predict values

    +
    +
    Parameters:
    +
      +
    • self – A data cube to predict values for.

    • +
    • parameters – A data cube with optimal values from a result of e.g. fit_curve().

    • +
    • function – The model function. It must take the parameters to fit as array through the first +argument and the independent variable x as the second argument. It is recommended to store the model +function as a user-defined process on the back-end.

    • +
    • dimension – The name of the dimension for predictions. Fails with a DimensionNotAvailable +exception if the specified dimension does not exist.

    • +
    • labels – The labels to predict values for. If no labels are given, predicts values only for no- +data (null) values in the data cube.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the predicted values.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “predict_curve”.

    +
    +
    + +
    +
    +predict_random_forest(model)[source]
    +

    Predict values from a Random Forest model

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • model – A model object that can be trained with the processes fit_regr_random_forest() +(regression) and fit_class_random_forest() (classification).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The predicted value. Returns null if any of the given values in the array is a no-data +value.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “predict_random_forest”.

    +
    +
    + +
    +
    +product(ignore_nodata=<object object>)[source]
    +

    Compute the product by multiplying numbers

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed product of the sequence of numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “product”.

    +
    +
    + +
    +
    +quantiles(probabilities=<object object>, q=<object object>, ignore_nodata=<object object>)[source]
    +

    Quantiles

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • probabilities – A list of probabilities to calculate quantiles for. The probabilities must be +between 0 and 1 (inclusive).

    • +
    • q – Number of intervals to calculate quantiles for. Calculates q-quantiles with equal-sized +intervals.

    • +
    • ignore_nodata – Indicates whether no-data values are ignored or not. Ignores them by default. +Setting this flag to false considers no-data values so that an array with null values is returned +if any element is such a value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    An array with the computed quantiles. The list has either * as many elements as the given +list of probabilities had or * `q`-1 elements. If 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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “quantiles”.

    +
    +
    + +
    +
    +rearrange(order)[source]
    +

    Rearrange an array based on a permutation

    +
    +
    Parameters:
    +
      +
    • self – The array to rearrange.

    • +
    • order – The permutation used for rearranging.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The rearranged array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rearrange”.

    +
    +
    + +
    +
    +reduce_dimension(reducer, dimension, context=<object object>)[source]
    +

    Reduce dimensions

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • reducer – A reducer to apply on 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.

    • +
    • dimension – The name of the dimension over which to reduce. Fails with a DimensionNotAvailable +exception if the specified dimension does not exist.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “reduce_dimension”.

    +
    +
    + +
    +
    +reduce_spatial(reducer, context=<object object>)[source]
    +

    Reduce spatial dimensions ‘x’ and ‘y’

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • reducer – 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.

    • +
    • context – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “reduce_spatial”.

    +
    +
    + +
    +
    +rename_dimension(source, target)[source]
    +

    Rename a dimension

    +
    +
    Parameters:
    +
      +
    • self – The data cube.

    • +
    • source – The current name of the dimension. Fails with a DimensionNotAvailable exception if the +specified dimension does not exist.

    • +
    • target – A new Name for the dimension. Fails with a DimensionExists exception if a dimension +with the specified name exists.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the same dimensions, but the name of one of the dimensions changes. The old +name can not be referred to any longer. The dimension properties (name, type, labels, reference system +and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rename_dimension”.

    +
    +
    + +
    +
    +rename_labels(dimension, target, source=<object object>)[source]
    +

    Rename dimension labels

    +
    +
    Parameters:
    +
      +
    • self – The data cube.

    • +
    • dimension – The name of the dimension to rename the labels for.

    • +
    • target – The new names for the labels. If a target dimension label already exists in the data +cube, a LabelExists exception is thrown.

    • +
    • source – The original names of the labels to be renamed to corresponding array elements in the +parameter target. It is allowed to only specify a subset of labels to rename, as long as the target +and source parameter have the same length. The order of the labels doesn’t need to match the order of +the dimension labels in the data cube. By default, the array is empty so that the dimension labels in +the data cube are expected to be enumerated. If the dimension labels are not enumerated and the given +array is empty, the LabelsNotEnumerated exception is thrown. If one of the source dimension labels +doesn’t exist, the LabelNotAvailable exception is thrown.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data cube with the same dimensions. The dimension properties (name, type, labels, +reference system and resolution) remain unchanged, except that for the given dimension the labels +change. The old labels can not be referred to any longer. The number of labels remains the same.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rename_labels”.

    +
    +
    + +
    +
    +resample_cube_spatial(target, method=<object object>)[source]
    +

    Resample the spatial dimensions to match a target data cube

    +
    +
    Parameters:
    +
      +
    • self – A data cube.

    • +
    • target – A data cube that describes the spatial target resolution.

    • +
    • method – 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): * average: average +(mean) resampling, computes the weighted average of all valid pixels * bilinear: bilinear resampling +* cubic: cubic resampling * cubicspline: cubic spline resampling * lanczos: Lanczos windowed sinc +resampling * max: maximum resampling, selects the maximum value from all valid pixels * med: median +resampling, selects the median value of all valid pixels * min: minimum resampling, selects the +minimum value from all valid pixels * mode: mode resampling, selects the value which appears most +often of all the sampled points * near: nearest neighbour resampling (default) * q1: first quartile +resampling, selects the first quartile value of all valid pixels * q3: third quartile resampling, +selects the third quartile value of all valid pixels * rms root mean square (quadratic mean) of all +valid pixels * sum: compute the weighted sum of all valid pixels Valid pixels are determined based +on the function is_valid().

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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 spatial +dimensions.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “resample_cube_spatial”.

    +
    +
    + +
    +
    +resample_cube_temporal(target, dimension=<object object>, valid_within=<object object>)[source]
    +

    Resample temporal dimensions to match a target data cube

    +
    +
    Parameters:
    +
      +
    • self – A data cube with one or more temporal dimensions.

    • +
    • target – A data cube that describes the temporal target resolution.

    • +
    • dimension – 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. The following exceptions may occur: * A +dimension is given, but it does not exist in any of the data cubes: DimensionNotAvailable * A +dimension is given, but one of them is not temporal: DimensionMismatch * No specific dimension name +is given and there are no temporal dimensions with the same name in the data: DimensionMismatch

    • +
    • valid_within – 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).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    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.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “resample_cube_temporal”.

    +
    +
    + +
    +
    +resample_spatial(resolution=<object object>, projection=<object object>, method=<object object>, align=<object object>)[source]
    +

    Resample and warp the spatial dimensions

    +
    +
    Parameters:
    +
      +
    • self – A raster data cube.

    • +
    • resolution – 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).

    • +
    • projection – Warps the data cube to the target projection, specified as as [EPSG +code](http://www.epsg-registry.org/), [WKT2 (ISO 19162) +string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html), [PROJ definition +(deprecated)](https://proj.org/usage/quickstart.html). By default (null), the projection is not +changed.

    • +
    • method – 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): * average: average +(mean) resampling, computes the weighted average of all valid pixels * bilinear: bilinear resampling +* cubic: cubic resampling * cubicspline: cubic spline resampling * lanczos: Lanczos windowed sinc +resampling * max: maximum resampling, selects the maximum value from all valid pixels * med: median +resampling, selects the median value of all valid pixels * min: minimum resampling, selects the +minimum value from all valid pixels * mode: mode resampling, selects the value which appears most +often of all the sampled points * near: nearest neighbour resampling (default) * q1: first quartile +resampling, selects the first quartile value of all valid pixels * q3: third quartile resampling, +selects the third quartile value of all valid pixels * rms root mean square (quadratic mean) of all +valid pixels * sum: compute the weighted sum of all valid pixels Valid pixels are determined based +on the function is_valid().

    • +
    • align – Specifies to which corner of the spatial extent the new resampled data is aligned to.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A raster data cube with values warped onto the new projection. It has the same dimensions and +the same dimension properties (name, type, labels, reference system and resolution) for all non-spatial +or vertical spatial dimensions. For the horizontal spatial dimensions the name and type remain +unchanged, but reference system, labels and resolution may change depending on the given parameters.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “resample_spatial”.

    +
    +
    + +
    +
    +round(p=<object object>)[source]
    +

    Round to a specified precision

    +
    +
    Parameters:
    +
      +
    • self – A number to round.

    • +
    • p – A positive number specifies the number of digits after the decimal point to round to. A +negative number means rounding to a power of ten, so for example -2 rounds to the nearest hundred. +Defaults to 0.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The rounded number.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “round”.

    +
    +
    + +
    +
    +run_udf(udf, runtime, version=<object object>, context=<object object>)[source]
    +

    Run a UDF

    +
    +
    Parameters:
    +
      +
    • self – The data to be passed to the UDF.

    • +
    • udf – Either source code, an absolute URL or a path to a UDF script.

    • +
    • runtime – A UDF runtime identifier available at the back-end.

    • +
    • version – An UDF runtime version. If set to null, the default runtime version specified for +each runtime is used.

    • +
    • context – Additional data such as configuration options to be passed to the UDF.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data processed by the UDF. The returned value can be of any data type and is exactly what +the UDF code returns.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “run_udf”.

    +
    +
    + +
    +
    +run_udf_externally(url, context=<object object>)[source]
    +

    Run an externally hosted UDF container

    +
    +
    Parameters:
    +
      +
    • self – The data to be passed to the UDF.

    • +
    • url – Absolute URL to a remote UDF service.

    • +
    • context – Additional data such as configuration options to be passed to the UDF.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The data processed by the UDF. The returned value can in principle be of any data type, but it +depends on what is returned by the UDF code. Please see the implemented UDF interface for details.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “run_udf_externally”.

    +
    +
    + +
    +
    +sar_backscatter(coefficient=<object object>, elevation_model=<object object>, mask=<object object>, contributing_area=<object object>, local_incidence_angle=<object object>, ellipsoid_incidence_angle=<object object>, noise_removal=<object object>, options=<object object>)[source]
    +

    Computes backscatter from SAR input

    +
    +
    Parameters:
    +
      +
    • self – The source data cube containing SAR input.

    • +
    • coefficient – Select the radiometric correction coefficient. The following options are available: +* beta0: radar brightness * sigma0-ellipsoid: ground area computed with ellipsoid earth model * +sigma0-terrain: ground area computed with terrain earth model * gamma0-ellipsoid: ground area +computed with ellipsoid earth model in sensor line of sight * gamma0-terrain: ground area computed +with terrain earth model in sensor line of sight (default) * null: non-normalized backscatter

    • +
    • elevation_model – 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.

    • +
    • mask – 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).

    • +
    • contributing_area – If set to true, a DEM-based local contributing area band named +contributing_area is added. The values are given in square meters.

    • +
    • local_incidence_angle – If set to true, a DEM-based local incidence angle band named +local_incidence_angle is added. The values are given in degrees.

    • +
    • ellipsoid_incidence_angle – If set to true, an ellipsoidal incidence angle band named +ellipsoid_incidence_angle is added. The values are given in degrees.

    • +
    • noise_removal – If set to false, no noise removal is applied. Defaults to true, which removes +noise.

    • +
    • options – Proprietary options for the backscatter computations. Specifying proprietary options +will reduce portability.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Backscatter values corresponding to the chosen parametrization. The values are given in linear +scale.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sar_backscatter”.

    +
    +
    + +
    +
    +save_ml_model(options=<object object>)[source]
    +

    Save a ML model

    +
    +
    Parameters:
    +
      +
    • self – The data to store as a machine learning model.

    • +
    • options – Additional parameters to create the file(s).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns false if the process failed to store the model, true otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “save_ml_model”.

    +
    +
    + +
    +
    +save_result(format, options=<object object>)[source]
    +

    Save processed data

    +
    +
    Parameters:
    +
      +
    • self – The data to deliver in the given file format.

    • +
    • format – The file format to use. It must be one of the values that the server reports as +supported output file formats, which usually correspond to the short GDAL/OGR codes. If the format is +not suitable for storing the underlying data structure, a FormatUnsuitable exception will be thrown. +This parameter is case insensitive.

    • +
    • options – The file format parameters to be used to create the file(s). Must correspond to the +parameters that the server reports as supported parameters for the chosen format. The parameter names +and valid values usually correspond to the GDAL/OGR format options.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns false if the process failed to make the data available, true otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “save_result”.

    +
    +
    + +
    +
    +sd(ignore_nodata=<object object>)[source]
    +

    Standard deviation

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sample standard deviation.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sd”.

    +
    +
    + +
    +
    +sgn()[source]
    +

    Signum

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed signum value of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sgn”.

    +
    +
    + +
    +
    +sin()[source]
    +

    Sine

    +
    +
    Parameters:
    +

    self – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sin”.

    +
    +
    + +
    +
    +sinh()[source]
    +

    Hyperbolic sine

    +
    +
    Parameters:
    +

    self – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed hyperbolic sine of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sinh”.

    +
    +
    + +
    +
    +sort(asc=<object object>, nodata=<object object>)[source]
    +

    Sort data

    +
    +
    Parameters:
    +
      +
    • self – An array with data to sort.

    • +
    • asc – The default sort order is ascending, with smallest values first. To sort in reverse +(descending) order, set this parameter to false.

    • +
    • nodata – 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.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The sorted array.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sort”.

    +
    +
    + +
    +
    +sqrt()[source]
    +

    Square root

    +
    +
    Parameters:
    +

    self – A number.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed square root.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sqrt”.

    +
    +
    + +
    +
    +subtract(y)[source]
    +

    Subtraction of two numbers

    +
    +
    Parameters:
    +
      +
    • self – The minuend.

    • +
    • y – The subtrahend.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed result.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “subtract”.

    +
    +
    + +
    +
    +sum(ignore_nodata=<object object>)[source]
    +

    Compute the sum by adding up numbers

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sum of the sequence of numbers.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “sum”.

    +
    +
    + +
    +
    +tan()[source]
    +

    Tangent

    +
    +
    Parameters:
    +

    self – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed tangent of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “tan”.

    +
    +
    + +
    +
    +tanh()[source]
    +

    Hyperbolic tangent

    +
    +
    Parameters:
    +

    self – An angle in radians.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed hyperbolic tangent of x.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “tanh”.

    +
    +
    + +
    +
    +text_begins(pattern, case_sensitive=<object object>)[source]
    +

    Text begins with another text

    +
    +
    Parameters:
    +
      +
    • self – Text in which to find something at the beginning.

    • +
    • pattern – Text to find at the beginning of data. Regular expressions are not supported.

    • +
    • case_sensitive – Case sensitive comparison can be disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if data begins with pattern, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_begins”.

    +
    +
    + +
    +
    +text_concat(separator=<object object>)[source]
    +

    Concatenate elements to a single text

    +
    +
    Parameters:
    +
      +
    • self – A set of elements. Numbers, boolean values and null values get converted to their (lower +case) string representation. For example: 1 (integer), -1.5 (number), true / false (boolean +values)

    • +
    • separator – A separator to put between each of the individual texts. Defaults to an empty string.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A string containing a string representation of all the array elements in the same order, with +the separator between each element.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_concat”.

    +
    +
    + +
    +
    +text_contains(pattern, case_sensitive=<object object>)[source]
    +

    Text contains another text

    +
    +
    Parameters:
    +
      +
    • self – Text in which to find something in.

    • +
    • pattern – Text to find in data. Regular expressions are not supported.

    • +
    • case_sensitive – Case sensitive comparison can be disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if data contains the pattern, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_contains”.

    +
    +
    + +
    +
    +text_ends(pattern, case_sensitive=<object object>)[source]
    +

    Text ends with another text

    +
    +
    Parameters:
    +
      +
    • self – Text in which to find something at the end.

    • +
    • pattern – Text to find at the end of data. Regular expressions are not supported.

    • +
    • case_sensitive – Case sensitive comparison can be disabled by setting this parameter to false.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    true if data ends with pattern, false` otherwise.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “text_ends”.

    +
    +
    + +
    +
    +trim_cube()[source]
    +

    Remove dimension labels with no-data values

    +
    +
    Parameters:
    +

    self – A raster data cube to trim.

    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A trimmed raster data cube with the same dimensions. The dimension properties name, type, +reference system and resolution remain unchanged. The number of dimension labels may decrease.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “trim_cube”.

    +
    +
    + +
    +
    +unflatten_dimension(dimension, target_dimensions, label_separator=<object object>)[source]
    +

    Split a single dimensions into multiple dimensions

    +
    +
    Parameters:
    +
      +
    • self – A data cube that is consistently structured so that operation can execute flawlessly (e.g. +the dimension labels need to contain the label_separator exactly 1 time for two target dimensions, 2 +times for three target dimensions etc.).

    • +
    • dimension – The name of the dimension to split.

    • +
    • target_dimensions – The names of the new target dimensions. New dimensions will be created with +the given names and type other (see add_dimension()). Fails with a TargetDimensionExists +exception if any of the dimensions exists. The order of the array defines the order in which the +dimensions and dimension labels are added to the data cube (see the example in the process +description).

    • +
    • label_separator – The string that will be used as a separator to split the dimension labels.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    A data cube with the new shape. The dimension properties (name, type, labels, reference system +and resolution) for all other dimensions remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “unflatten_dimension”.

    +
    +
    + +
    +
    +variance(ignore_nodata=<object object>)[source]
    +

    Variance

    +
    +
    Parameters:
    +
      +
    • self – An array of numbers.

    • +
    • ignore_nodata – 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 returned if any value is such a +value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    The computed sample variance.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “variance”.

    +
    +
    + +
    +
    +vector_buffer(distance)[source]
    +

    Buffer geometries by distance

    +
    +
    Parameters:
    +
      +
    • self – Geometries to apply the buffer on. Vector properties are preserved for vector data cubes +and all GeoJSON Features. To 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).

    • +
    • distance – The distance of the buffer in the unit of the spatial reference system. A positive +distance expands the geometries and results in outward buffering (dilation) while a negative distance +shrinks the geometries and results in inward buffering (erosion).

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns a vector data cube with the computed new geometries.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “vector_buffer”.

    +
    +
    + +
    +
    +vector_to_random_points(geometry_count=<object object>, total_count=<object object>, group=<object object>, seed=<object object>)[source]
    +

    Sample random points from geometries

    +
    +
    Parameters:
    +
      +
    • self – Input geometries for sample extraction. To 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).

    • +
    • geometry_count – The maximum number of points to compute per geometry. Points in the input +geometries can be selected only once by the sampling.

    • +
    • total_count – The maximum number of points to compute overall. Throws a CountMismatch +exception if the specified value is less than the provided number of geometries.

    • +
    • group – Specifies whether the sampled points should be grouped by input geometry (default) or be +generated as independent points. * If the sampled points are grouped, the process generates a +MultiPoint per geometry given which keeps the original identifier if present. * Otherwise, each +sampled point is generated as a distinct Point geometry without identifier.

    • +
    • seed – A randomization seed to use for random sampling. If not given or null, no seed is used +and results may differ on subsequent use.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns a vector data cube with the sampled points.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “vector_to_random_points”.

    +
    +
    + +
    +
    +vector_to_regular_points(distance, group=<object object>)[source]
    +

    Sample regular points from geometries

    +
    +
    Parameters:
    +
      +
    • self – Input geometries for sample extraction. To 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).

    • +
    • distance – Defines the minimum distance in the unit of the reference system that is required +between two samples generated inside a single geometry. - For polygons, the distance defines the +cell sizes of a regular grid that starts at the upper-left bound of each polygon. The centroid of each +cell is then a sample point. If the centroid is not enclosed in the polygon, no point is sampled. If no +point can be sampled for the geometry at all, the first coordinate of the geometry is returned as +point. - For lines (line strings), the sampling starts with a point at the first coordinate of the +line and then walks along the line and samples a new point each time the distance to the previous point +has been reached again. - For points, the point is returned as given.

    • +
    • group – Specifies whether the sampled points should be grouped by input geometry (default) or be +generated as independent points. * If the sampled points are grouped, the process generates a +MultiPoint per geometry given which keeps the original identifier if present. * Otherwise, each +sampled point is generated as a distinct Point geometry without identifier.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Returns a vector data cube with the sampled points.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “vector_to_regular_points”.

    +
    +
    + +
    +
    +xor(y)[source]
    +

    Logical XOR (exclusive or)

    +
    +
    Parameters:
    +
      +
    • self – A boolean value.

    • +
    • y – A boolean value.

    • +
    +
    +
    Return type:
    +

    ProcessBuilder

    +
    +
    Returns:
    +

    Boolean result of the logical XOR.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “xor”.

    +
    +
    + +
    + +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/api.html b/api.html new file mode 100644 index 000000000..a95b91eba --- /dev/null +++ b/api.html @@ -0,0 +1,6062 @@ + + + + + + + + API (General) — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    API (General)

    +
    +

    High level Interface

    +

    The high-level interface tries to provide an opinionated, Pythonic, API +to interact with openEO back-ends. It’s aim is to hide some of the details +of using a web service, so the user can produce concise and readable code.

    +

    Users that want to interact with openEO on a lower level, and have more control, can +use the lower level classes.

    +
    +
    +

    openeo

    +
    +
    +openeo.connect(url=None, *, auth_type=None, auth_options=None, session=None, default_timeout=None, auto_validate=True)[source]
    +

    This method is the entry point to OpenEO. +You typically create one connection object in your script or application +and re-use it for all calls to that backend.

    +

    If the backend requires authentication, you can pass authentication data directly to this function, +but it could be easier to authenticate as follows:

    +
    >>> # For basic authentication
    +>>> conn = connect(url).authenticate_basic(username="john", password="foo")
    +>>> # For OpenID Connect authentication
    +>>> conn = connect(url).authenticate_oidc(client_id="myclient")
    +
    +
    +
    +
    Parameters:
    +
      +
    • url (Optional[str]) – The http url of the OpenEO back-end.

    • +
    • auth_type (Optional[str]) – Which authentication to use: None, “basic” or “oidc” (for OpenID Connect)

    • +
    • auth_options (Optional[dict]) – Options/arguments specific to the authentication type

    • +
    • default_timeout (Optional[int]) – default timeout (in seconds) for requests

    • +
    • auto_validate (bool) – toggle to automatically validate process graphs before execution

    • +
    +
    +
    Return type:
    +

    Connection

    +
    +
    +
    +

    New in version 0.24.0: added auto_validate argument

    +
    +
    + +
    +
    +

    openeo.rest.datacube

    +

    The main module for creating earth observation processes. It aims to easily build complex process chains, that can +be evaluated by an openEO backend.

    +
    +
    +openeo.rest.datacube.THIS
    +

    Symbolic reference to the current data cube, to be used as argument in DataCube.process() calls

    +
    + +
    +
    +class openeo.rest.datacube.DataCube(graph, connection, metadata=None)[source]
    +

    Class representing a openEO (raster) data cube.

    +

    The data cube is represented by its corresponding openeo “process graph” +and this process graph can be “grown” to a desired workflow by calling the appropriate methods.

    +
    +
    +__init__(graph, connection, metadata=None)[source]
    +
    + +
    +
    +add(other, reverse=False)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “add”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +add_dimension(name, label, type=None)[source]
    +

    Adds a new named dimension to the data cube. +Afterwards, 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.

    +

    This call does not modify the datacube in place, but returns a new datacube with the additional dimension.

    +
    +
    Parameters:
    +
      +
    • name (str) – The name of the dimension to add

    • +
    • label (str) – The dimension label.

    • +
    • type (Optional[str]) – Dimension type, allowed values: ‘spatial’, ‘temporal’, ‘bands’, ‘other’, default value is ‘other’

    • +
    +
    +
    Returns:
    +

    The data cube with a newly added dimension. The new dimension has exactly one dimension label. All other dimensions remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “add_dimension”.

    +
    +
    + +
    +
    +aggregate_spatial(geometries, reducer, target_dimension=None, crs=None, context=None)[source]
    +

    Aggregates statistics for one or more geometries (e.g. zonal statistics for polygons) +over the spatial dimensions.

    +
    +
    Parameters:
    +
      +
    • geometries (Union[BaseGeometry, dict, str, Path, Parameter, VectorCube]) – a shapely geometry, a GeoJSON-style dictionary, +a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file.

    • +
    • reducer (Union[str, Callable, PGNode]) –

      the “child callback”: +the name of a single openEO process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

      +

      The callback should correspond to a process that +receives an array of numerical values +and returns a single numerical value. +For example:

      + +

    • +
    • target_dimension (Optional[str]) – The new dimension name to be used for storing the results.

    • +
    • crs (Union[int, str, None]) – The spatial reference system of the provided polygon. +By default, longitude-latitude (EPSG:4326) is assumed. +See openeo.util.normalize_crs() for more details about additional normalization that is applied to this argument.

    • +
    • context (Optional[dict]) –

      Additional data to be passed to the reducer process.

      +
      +

      Note

      +

      this crs argument is a non-standard/experimental feature, only supported by specific back-ends. +See https://github.com/Open-EO/openeo-processes/issues/235 for details.

      +
      +

    • +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_spatial”.

    +
    +
    + +
    +
    +aggregate_spatial_window(reducer, size, boundary='pad', align='upper-left', context=None)[source]
    +

    Aggregates statistics over the horizontal spatial dimensions (axes x and y) of the data cube.

    +

    The 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. For each of these windows, the reducer process computes the result.

    +
    +
    Parameters:
    +
      +
    • reducer (Union[str, Callable, PGNode]) – the “child callback”: +the name of a single openEO process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

    • +
    • size (List[int]) – Window size in pixels along the horizontal spatial dimensions. +The first value corresponds to the x axis, the second value corresponds to the y axis.

    • +
    • boundary (str) –

      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:

      +
      +
        +
      • pad (default): pad the data cube with the no-data value null to fit the required window size.

      • +
      • trim: trim the data cube to fit the required window size.

      • +
      +
      +

      Use the parameter align to align the data to the desired corner.

      +

    • +
    • align (str) – 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.

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A data cube with the newly computed values and the same dimensions.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_spatial_window”.

    +
    +
    + +
    +
    +aggregate_temporal(intervals, reducer, labels=None, dimension=None, context=None)[source]
    +

    Computes a temporal aggregation based on an array of date and/or time intervals.

    +

    Calendar hierarchies such as year, month, week etc. must be transformed into specific intervals by the clients. For each interval, all data along the dimension will be passed through the reducer. The computed values will be projected to the labels, so the number of labels and the number of intervals need to be equal.

    +

    If the dimension is not set, the data cube is expected to only have one temporal dimension.

    +
    +
    Parameters:
    +
      +
    • intervals (List[list]) – Temporal left-closed intervals so that the start time is contained, but not the end time.

    • +
    • reducer (Union[str, Callable, PGNode]) –

      the “child callback”: +the name of a single openEO process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

      +

      The callback should correspond to a process that +receives an array of numerical values +and returns a single numerical value. +For example:

      + +

    • +
    • labels (Optional[List[str]]) – Labels for the intervals. The number of labels and the number of groups need to be equal.

    • +
    • dimension (Optional[str]) – The temporal dimension for aggregation. All data along the dimension will be passed through the specified reducer. If the dimension is not set, the data cube is expected to only have one temporal dimension.

    • +
    • context (Optional[dict]) – Additional data to be passed to the reducer. Not set by default.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A DataCube containing a result for each time window

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_temporal”.

    +
    +
    + +
    +
    +aggregate_temporal_period(period, reducer, dimension=None, context=None)[source]
    +

    Computes a temporal aggregation based on calendar hierarchies such as years, months or seasons. For other calendar hierarchies aggregate_temporal can be used.

    +

    For each interval, all data along the dimension will be passed through the reducer.

    +

    If the dimension is not set or is set to null, the data cube is expected to only have one temporal dimension.

    +

    The period argument specifies the time intervals to aggregate. The following pre-defined values are available:

    +
      +
    • hour: Hour of the day

    • +
    • day: Day of the year

    • +
    • week: Week of the year

    • +
    • 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.

    • +
    • month: Month of the year

    • +
    • season: Three month periods of the calendar seasons (December - February, March - May, June - August, September - November).

    • +
    • tropical-season: Six month periods of the tropical seasons (November - April, May - October).

    • +
    • year: Proleptic years

    • +
    • decade: Ten year periods (0-to-9 decade), from a year ending in a 0 to the next year ending in a 9.

    • +
    • decade-ad: Ten year periods (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.

    • +
    +
    +
    Parameters:
    +
      +
    • period (str) – The period of the time intervals to aggregate.

    • +
    • reducer (Union[str, PGNode, Callable]) – A reducer to be applied on all values along the specified dimension. The reducer must be a callable process (or a set processes) that accepts an array and computes a single return value of the same type as the input values, for example median.

    • +
    • dimension (Optional[str]) – The temporal dimension for aggregation. All data along the dimension will be passed through the specified reducer. If the dimension is not set, the data cube is expected to only have one temporal dimension.

    • +
    • context (Optional[Dict]) – Additional data to be passed to the reducer.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A data cube with the same dimensions. The dimension properties (name, type, labels, reference system and resolution) remain unchanged.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “aggregate_temporal_period”.

    +
    +
    + +
    +
    +apply(process, context=None)[source]
    +

    Applies a unary process (a local operation) to each value of the specified or all dimensions in the data cube.

    +
    +
    Parameters:
    +
      +
    • process (Union[str, Callable, UDF, PGNode]) –

      the “child callback”: +the name of a single process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

      +

      The callback should correspond to a process that +receives a single numerical value +and returns a single numerical value. +For example:

      + +

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A data cube with the newly computed values. The resolution, cardinality and the number of dimensions are the same as for the original data cube.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply”.

    +
    +
    + +
    +
    +apply_dimension(code=None, runtime=None, process=None, version=None, dimension='t', target_dimension=None, context=None)[source]
    +

    Applies a process to all pixel values along a dimension of a raster data cube. For example, +if the temporal dimension is specified the process will work on a time series of pixel values.

    +

    The process to apply is specified by either code and runtime in case of a UDF, or by providing a callback function +in the process argument.

    +

    The process reduce_dimension also applies a process to pixel values along a dimension, but drops +the dimension afterwards. The process apply applies a process to each pixel value in the data cube.

    +

    The target dimension is the source dimension if not specified otherwise in the target_dimension parameter. +The pixel values in the target dimension get replaced by the computed pixel values. The name, type and +reference system are preserved.

    +

    The dimension labels are preserved when the target dimension is the source dimension and the number of +pixel values in the source dimension is equal to the number of values computed by the process. Otherwise, +the dimension labels will be incrementing integers starting from zero, which can be changed using +rename_labels afterwards. The number of labels will equal to the number of values computed by the process.

    +
    +
    Parameters:
    +
      +
    • code (Optional[str]) – [deprecated] UDF code or process identifier (optional)

    • +
    • runtime – [deprecated] UDF runtime to use (optional)

    • +
    • process (Union[str, Callable, UDF, PGNode]) –

      the “child callback”: +the name of a single process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

      +

      The callback should correspond to a process that +receives an array of numerical values +and returns an array of numerical values. +For example:

      + +

    • +
    • version (Optional[str]) – [deprecated] Version of the UDF runtime to use

    • +
    • dimension (str) – The name of the source dimension to apply the process on. Fails with a DimensionNotAvailable error if the specified dimension does not exist.

    • +
    • target_dimension (Optional[str]) – The name of the target dimension or null (the default) to use the source dimension +specified in the parameter dimension. By 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.

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A datacube with the UDF applied to the given dimension.

    +
    +
    Raises:
    +

    DimensionNotAvailable

    +
    +
    +
    +

    Changed in version 0.13.0: arguments code, runtime and version are deprecated if favor of the standard approach +of using an UDF object in the process argument. +See openeo.UDF API and usage changes in version 0.13.0 for more background about the changes.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_dimension”.

    +
    +
    + +
    +
    +apply_kernel(kernel, factor=1.0, border=0, replace_invalid=0)[source]
    +

    Applies a focal operation based on a weighted kernel to each value of the specified dimensions in the data cube.

    +

    The border parameter determines how the data is extended when the kernel overlaps with the borders. +The following options are available:

    +
      +
    • numeric value - fill with a user-defined constant number n: nnnnnn|abcdefgh|nnnnnn (default, with n = 0)

    • +
    • replicate - repeat the value from the pixel at the border: aaaaaa|abcdefgh|hhhhhh

    • +
    • reflect - mirror/reflect from the border: fedcba|abcdefgh|hgfedc

    • +
    • reflect_pixel - mirror/reflect from the center of the pixel at the border: gfedcb|abcdefgh|gfedcb

    • +
    • wrap - repeat/wrap the image: cdefgh|abcdefgh|abcdef

    • +
    +
    +
    Parameters:
    +
      +
    • kernel (Union[ndarray, List[List[float]]]) – The kernel to be applied on the data cube. The kernel has to be as many dimensions as the data cube has dimensions.

    • +
    • factor – A factor that is multiplied to each value computed by the focal operation. This is basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often required for some kernel-based algorithms such as the Gaussian blur.

    • +
    • border – Determines how the data is extended when the kernel overlaps with the borders. Defaults to fill the border with zeroes.

    • +
    • replace_invalid – This parameter specifies the value to replace non-numerical or infinite numerical values with. By default, those values are replaced with zeroes.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A data cube with the newly computed values. The resolution, cardinality and the number of dimensions are the same as for the original data cube.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_kernel”.

    +
    +
    + +
    +
    +apply_neighborhood(process, size, overlap=None, context=None)[source]
    +

    Applies a focal process to a data cube.

    +

    A 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.

    +

    An 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 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.

    +

    The process must not add new dimensions, or remove entire dimensions, but the result can have different dimension labels.

    +

    For the special case of 2D convolution, it is recommended to use apply_kernel().

    +
    +
    Parameters:
    +
      +
    • size (List[Dict]) –

    • +
    • overlap (List[dict]) –

    • +
    • process (Union[str, PGNode, Callable, UDF]) – a callback function that creates a process graph, see Processes with child “callbacks”

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_neighborhood”.

    +
    +
    + +
    +
    +apply_polygon(polygons, process, mask_value=None, context=None)[source]
    +

    Apply a process to segments of the data cube that are defined by the given polygons. +For each polygon provided, all pixels for which the point at the pixel center intersects +with the polygon (as defined in the Simple Features standard by the OGC) are collected into sub data cubes. +If a pixel is part of multiple of the provided polygons (e.g., when the polygons overlap), +the GeometriesOverlap exception is thrown. +Each sub data cube is passed individually to the given process.

    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change.

    +
    +
    +
    Parameters:
    +
      +
    • polygons (Union[BaseGeometry, dict, str, Path, Parameter, VectorCube]) – Polygons, provided as a shapely geometry, a GeoJSON-style dictionary, +a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file.

    • +
    • process (Union[str, PGNode, Callable, UDF]) – “child callback” function, see Processes with child “callbacks”

    • +
    • mask_value (Optional[float]) – The value used for pixels outside the polygon.

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_polygon”.

    +
    +
    + +
    +
    +ard_normalized_radar_backscatter(elevation_model=None, contributing_area=False, ellipsoid_incidence_angle=False, noise_removal=True)[source]
    +

    Computes CARD4L compliant backscatter (gamma0) from SAR input. +This method is a variant of sar_backscatter(), +with restricted parameters to generate backscatter according to CARD4L specifications.

    +

    Note 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.

    +
    +
    Parameters:
    +
      +
    • elevation_model (str) – The digital elevation model to use. Set to None (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility.

    • +
    • contributing_area – If set to true, a DEM-based local contributing area band named contributing_area +is added. The values are given in square meters.

    • +
    • ellipsoid_incidence_angle (bool) – If set to True, an ellipsoidal incidence angle band named ellipsoid_incidence_angle is added. The values are given in degrees.

    • +
    • noise_removal (bool) – If set to false, no noise removal is applied. Defaults to True, which removes noise.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    Backscatter values expressed as gamma0. The data returned is CARD4L compliant and contains metadata. By default, the backscatter values are given in linear scale.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ard_normalized_radar_backscatter”.

    +
    +
    + +
    +
    +ard_surface_reflectance(atmospheric_correction_method, cloud_detection_method, elevation_model=None, atmospheric_correction_options=None, cloud_detection_options=None)[source]
    +

    Computes CARD4L compliant surface reflectance values from optical input.

    +
    +
    Parameters:
    +
      +
    • atmospheric_correction_method (str) – The atmospheric correction method to use.

    • +
    • cloud_detection_method (str) – The cloud detection method to use.

    • +
    • elevation_model (str) – The digital elevation model to use, leave empty to allow the back-end to make a suitable choice.

    • +
    • atmospheric_correction_options (dict) – Proprietary options for the atmospheric correction method.

    • +
    • cloud_detection_options (dict) – Proprietary options for the cloud detection method.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    Data cube containing bottom of atmosphere reflectances with atmospheric disturbances like clouds and cloud shadows removed. The data returned is CARD4L compliant and contains metadata.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ard_surface_reflectance”.

    +
    +
    + +
    +
    +atmospheric_correction(method=None, elevation_model=None, options=None)[source]
    +

    Applies an atmospheric correction that converts top of atmosphere reflectance values into bottom of atmosphere/top of canopy reflectance values.

    +

    Note that multiple atmospheric methods exist, but may not be supported by all backends. The method parameter gives +you the option of requiring a specific method, but this may result in an error if the backend does not support it.

    +
    +
    Parameters:
    +
      +
    • method (str) – The atmospheric correction method to use. To get reproducible results, you have to set a specific method. Set 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.

    • +
    • elevation_model (str) – The digital elevation model to use, leave empty to allow the back-end to make a suitable choice.

    • +
    • options (dict) – Proprietary options for the atmospheric correction method.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    datacube with bottom of atmosphere reflectances

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “atmospheric_correction”.

    +
    +
    + +
    +
    +band(band)[source]
    +

    Filter out a single band

    +
    +
    Parameters:
    +

    band (Union[str, int]) – band name, band common name or band index.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    + +
    +
    +band_filter(bands)
    +
    +

    Deprecated since version 0.1.0: Usage of this legacy method is deprecated. Use +filter_bands() instead.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +chunk_polygon(chunks, process, mask_value=None, context=None)[source]
    +

    Apply a process to spatial chunks of a data cube.

    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change.

    +
    +
    +
    Parameters:
    +
      +
    • chunks (Union[BaseGeometry, dict, str, Path, Parameter, VectorCube]) – Polygons, provided as a shapely geometry, a GeoJSON-style dictionary, +a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file.

    • +
    • process (Union[str, PGNode, Callable, UDF]) – “child callback” function, see Processes with child “callbacks”

    • +
    • mask_value (float) – The value used for cells outside the polygon. +This provides a distinction between NoData cells within the polygon (due to e.g. clouds) +and masked cells outside it. If no value is provided, NoData cells are used outside the polygon.

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    Deprecated since version 0.26.0: Use apply_polygon().

    +
    +
    + +
    +
    +count_time()[source]
    +

    Counts the number of images with a valid mask in a time series for all bands of the input dataset.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “count”.

    +
    +
    + +
    +
    +classmethod create_collection(cls, collection_id, connection=None, spatial_extent=None, temporal_extent=None, bands=None, fetch_metadata=True, properties=None, max_cloud_cover=None)
    +
    +

    Deprecated since version 0.4.6: Usage of this legacy class method is deprecated. Use +load_collection() instead.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +create_job(out_format=None, *, title=None, description=None, plan=None, budget=None, job_options=None, validate=None, **format_options)[source]
    +

    Sends the datacube’s process graph as a batch job to the back-end +and return a BatchJob instance.

    +

    Note that the batch job will just be created at the back-end, +it still needs to be started and tracked explicitly. +Use execute_batch() instead to have the openEO Python client take care of that job management.

    +
    +
    Parameters:
    +
      +
    • out_format (Optional[str]) – output file format.

    • +
    • title (Optional[str]) – job title

    • +
    • description (Optional[str]) – job description

    • +
    • plan (Optional[str]) – billing plan

    • +
    • budget (Optional[float]) – maximum cost the request is allowed to produce

    • +
    • job_options (Optional[dict]) – custom job options.

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    Returns:
    +

    Created job.

    +
    +
    +
    + +
    +
    +dimension_labels(dimension)[source]
    +

    Gives all labels for a dimension in the data cube. The labels have the same order as in the data cube.

    +
    +
    Parameters:
    +

    dimension (str) – The name of the dimension to get the labels for.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “dimension_labels”.

    +
    +
    + +
    +
    +divide(other, reverse=False)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “divide”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +download(outputfile=None, format=None, options=None, *, validate=None)[source]
    +

    Execute synchronously and download the raster data cube, e.g. as GeoTIFF.

    +

    If outputfile is provided, the result is stored on disk locally, otherwise, a bytes object is returned. +The bytes object can be passed on to a suitable decoder for decoding.

    +
    +
    Parameters:
    +
      +
    • outputfile (Union[str, Path, None]) – Optional, an output file if the result needs to be stored on disk.

    • +
    • format (Optional[str]) – Optional, an output format supported by the backend.

    • +
    • options (Optional[dict]) – Optional, file format options

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    Optional[bytes]

    +
    +
    Returns:
    +

    None if the result is stored to disk, or a bytes object returned by the backend.

    +
    +
    +
    + +
    +
    +drop_dimension(name)[source]
    +

    Drops a dimension from the data cube. +Dropping 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.

    +
    +
    Parameters:
    +

    name (str) – The name of the dimension to drop

    +
    +
    Returns:
    +

    The data cube with the given dimension dropped.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “drop_dimension”.

    +
    +
    + +
    +
    +execute(*, validate=None)[source]
    +

    Executes the process graph.

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +execute_batch(outputfile=None, out_format=None, *, print=<built-in function print>, max_poll_interval=60, connection_retry_interval=30, job_options=None, validate=None, **format_options)[source]
    +

    Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. +This method is mostly recommended if the batch job is expected to run in a reasonable amount of time.

    +

    For very long-running jobs, you probably do not want to keep the client running.

    +
    +
    Parameters:
    +
      +
    • outputfile (Union[str, Path, None]) – The path of a file to which a result can be written

    • +
    • out_format (Optional[str]) – (optional) File format to use for the job result.

    • +
    • job_options (Optional[dict]) –

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    +
    + +
    +
    +static execute_local_udf(udf, datacube=None, fmt='netcdf')[source]
    +
    +

    Deprecated since version 0.7.0: Use openeo.udf.run_code.execute_local_udf() instead

    +
    +
    + +
    +
    +filter_bands(bands)[source]
    +

    Filter the data cube by the given bands

    +
    +
    Parameters:
    +

    bands (Union[List[Union[str, int]], str]) – list of band names, common names or band indices. Single band name can also be given as string.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bands”.

    +
    +
    + +
    +
    +filter_bbox(*args, west=None, south=None, east=None, north=None, crs=None, base=None, height=None, bbox=None)[source]
    +

    Limits the data cube to the specified bounding box.

    +

    The bounding box can be specified in multiple ways.

    +
    +
      +
    • With keyword arguments:

      +
      >>> cube.filter_bbox(west=3, south=51, east=4, north=52, crs=4326)
      +
      +
      +
    • +
    • With a (west, south, east, north) list or tuple +(note that EPSG:4326 is the default CRS, so it’s not necessary to specify it explicitly):

      +
      >>> cube.filter_bbox([3, 51, 4, 52])
      +>>> cube.filter_bbox(bbox=[3, 51, 4, 52])
      +
      +
      +
    • +
    • With a bbox dictionary:

      +
      >>> bbox = {"west": 3, "south": 51, "east": 4, "north": 52, "crs": 4326}
      +>>> cube.filter_bbox(bbox)
      +>>> cube.filter_bbox(bbox=bbox)
      +>>> cube.filter_bbox(**bbox)
      +
      +
      +
    • +
    • With a shapely geometry (of which the bounding box will be used):

      +
      >>> cube.filter_bbox(geometry)
      +>>> cube.filter_bbox(bbox=geometry)
      +
      +
      +
    • +
    • Passing a parameter:

      +
      >>> bbox_param = Parameter(name="my_bbox", schema="object")
      +>>> cube.filter_bbox(bbox_param)
      +>>> cube.filter_bbox(bbox=bbox_param)
      +
      +
      +
    • +
    • With a CRS other than EPSG 4326:

      +
      >>> cube.filter_bbox(
      +... west=652000, east=672000, north=5161000, south=5181000,
      +... crs=32632
      +... )
      +
      +
      +
    • +
    • Deprecated: positional arguments are also supported, +but follow a non-standard order for legacy reasons:

      +
      >>> west, east, north, south = 3, 4, 52, 51
      +>>> cube.filter_bbox(west, east, north, south)
      +
      +
      +
    • +
    +
    +
    +
    Parameters:
    +

    crs (Union[int, str, None]) – value describing the coordinate reference system. +Typically just an int (interpreted as EPSG code, e.g. 4326) +or a string (handled as authority string, e.g. "EPSG:4326"). +See openeo.util.normalize_crs() for more details about additional normalization that is applied to this argument.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bbox”.

    +
    +
    + +
    +
    +filter_spatial(geometries)[source]
    +

    Limits the data cube over the spatial dimensions to the specified geometries.

    +
    +
      +
    • For polygons, the filter retains a pixel in the data cube if the point at the pixel center intersects with +at least one of the polygons (as defined in the Simple Features standard by the OGC).

    • +
    • For points, the process considers the closest pixel center.

    • +
    • For lines (line strings), the process considers all the pixels whose centers are closest to at least one +point on the line.

    • +
    +
    +

    More specifically, pixels outside of the bounding box of the given geometry will not be available after filtering. +All pixels inside the bounding box that are not retained will be set to null (no data).

    +
    +
    Parameters:
    +

    geometries – One or more geometries used for filtering, specified as GeoJSON in EPSG:4326.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A data cube restricted to the specified geometries. The dimensions and dimension properties (name, +type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions have less +(or the same) dimension labels.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_spatial”.

    +
    +
    + +
    +
    +filter_temporal(*args, start_date=None, end_date=None, extent=None)[source]
    +

    Limit the DataCube to a certain date range, which can be specified in several ways:

    +
    >>> cube.filter_temporal("2019-07-01", "2019-08-01")
    +>>> cube.filter_temporal(["2019-07-01", "2019-08-01"])
    +>>> cube.filter_temporal(extent=["2019-07-01", "2019-08-01"])
    +>>> cube.filter_temporal(start_date="2019-07-01", end_date="2019-08-01"])
    +
    +
    +

    See Filter on temporal extent for more details on temporal extent handling and shorthand notation.

    +
    +
    Parameters:
    +
      +
    • start_date (Union[str, date, Parameter, PGNode, ProcessBuilderBase, None]) – start date of the filter (inclusive), as a string or date object

    • +
    • end_date (Union[str, date, Parameter, PGNode, ProcessBuilderBase, None]) – end date of the filter (exclusive), as a string or date object

    • +
    • extent (Union[Sequence[Union[str, date, Parameter, PGNode, ProcessBuilderBase, None]], Parameter, str, None]) – temporal extent. +Typically, specified as a two-item list or tuple containing start and end date.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    Changed in version 0.23.0: Arguments start_date, end_date and extent: +add support for year/month shorthand notation as discussed at Year/month shorthand notation.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_temporal”.

    +
    +
    + +
    +
    +fit_curve(parameters, function, dimension)[source]
    +

    Use non-linear least squares to fit a model function y = f(x, parameters) to data.

    +

    The process throws an InvalidValues exception if invalid values are encountered. +Invalid values are finite numbers (see also is_valid()).

    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change. +https://github.com/Open-EO/openeo-processes/pull/240

    +
    +
    +
    Parameters:
    +
    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_curve”.

    +
    +
    + +
    +
    +flat_graph()
    +

    Get the process graph in internal flat dict representation. +:rtype: Dict[str, dict]

    +
    +

    Warning

    +

    This method is mainly intended for internal use. +It is not recommended for general use and is subject to change.

    +

    Instead, it is recommended to use +to_json() or print_json() +to obtain a standardized, interoperable JSON representation of the process graph. +See Export a process graph for more information.

    +
    +
    + +
    +
    +flatten_dimensions(dimensions, target_dimension, label_separator=None)[source]
    +

    Combines multiple given dimensions into a single dimension by flattening the values +and merging the dimension labels with the given label_separator. Non-string dimension labels will +be converted to strings. This process is the opposite of the process unflatten_dimension() +but executing both processes subsequently doesn’t necessarily create a data cube that +is equal to the original data cube.

    +
    +
    Parameters:
    +
      +
    • dimensions (List[str]) – The names of the dimension to combine.

    • +
    • target_dimension (str) – The name of a target dimension with a single dimension label to replace.

    • +
    • label_separator (Optional[str]) – The string that will be used as a separator for the concatenated dimension labels.

    • +
    +
    +
    Returns:
    +

    A data cube with the new shape.

    +
    +
    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change.

    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “flatten_dimensions”.

    +
    +
    + +
    +
    +graph_add_node(process_id, arguments=None, metadata=None, namespace=None, **kwargs)
    +
    +

    Deprecated since version 0.1.1: Usage of this legacy method is deprecated. Use +process() instead.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +linear_scale_range(input_min, input_max, output_min, output_max)[source]
    +

    Performs a linear transformation between the input and output range.

    +

    The 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.

    +
    +

    Potential use case include 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 or calculating percentages (0 - 100).

    +

    The no-data value null is passed through and therefore gets propagated.

    +
    +
    Parameters:
    +
      +
    • input_min – Minimum input value

    • +
    • input_max – Maximum input value

    • +
    • output_min – Minimum value of the desired output range.

    • +
    • output_max – Maximum value of the desired output range.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “linear_scale_range”.

    +
    +
    + +
    +
    +ln()[source]
    +
    +

    See also

    +

    openeo.org documentation on process “ln”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +classmethod load_collection(collection_id, connection=None, spatial_extent=None, temporal_extent=None, bands=None, fetch_metadata=True, properties=None, max_cloud_cover=None)[source]
    +

    Create a new Raster Data cube.

    +
    +
    Parameters:
    +
      +
    • collection_id (Union[str, Parameter]) – image collection identifier

    • +
    • connection (Connection) – The connection to use to connect with the backend.

    • +
    • spatial_extent (Union[Dict[str, float], Parameter, None]) – limit data to specified bounding box or polygons

    • +
    • temporal_extent (Union[Sequence[Union[str, date, Parameter, PGNode, ProcessBuilderBase, None]], Parameter, str, None]) – limit data to specified temporal interval. +Typically, just a two-item list or tuple containing start and end date. +See Filter on temporal extent for more details on temporal extent handling and shorthand notation.

    • +
    • bands (Union[None, List[str], Parameter]) – only add the specified bands.

    • +
    • properties (Union[None, Dict[str, Union[str, PGNode, Callable]], List[CollectionProperty], CollectionProperty]) – limit data by metadata property predicates. +See collection_property() for easy construction of such predicates.

    • +
    • max_cloud_cover (Optional[float]) – shortcut to set maximum cloud cover (“eo:cloud_cover” collection property)

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    new DataCube containing the collection

    +
    +
    +
    +

    Changed in version 0.13.0: added the max_cloud_cover argument.

    +
    +
    +

    Changed in version 0.23.0: Argument temporal_extent: add support for year/month shorthand notation +as discussed at Year/month shorthand notation.

    +
    +
    +

    Changed in version 0.26.0: Add collection_property() support to properties argument.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_collection”.

    +
    +
    + +
    +
    +classmethod load_disk_collection(connection, file_format, glob_pattern, **options)[source]
    +

    Loads image data from disk as a DataCube. +This is backed by a non-standard process (‘load_disk_data’). This will eventually be replaced by standard options such as +https://processes.openeo.org/#load_uploaded_files

    +
    +
    Parameters:
    +
      +
    • connection (Connection) – The connection to use to connect with the backend.

    • +
    • file_format (str) – the file format, e.g. ‘GTiff’

    • +
    • glob_pattern (str) – a glob pattern that matches the files to load from disk

    • +
    • options – options specific to the file format

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    the data as a DataCube

    +
    +
    +
    + +
    +
    +log10()[source]
    +
    +

    See also

    +

    openeo.org documentation on process “log”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +log2()[source]
    +
    +

    See also

    +

    openeo.org documentation on process “log”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +logarithm(base)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “log”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +logical_and(other)[source]
    +

    Apply element-wise logical and operation

    +
    +
    Parameters:
    +

    other (DataCube) –

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    logical_and(this, other)

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “and”.

    +
    +
    + +
    +
    +logical_or(other)[source]
    +

    Apply element-wise logical or operation

    +
    +
    Parameters:
    +

    other (DataCube) –

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    logical_or(this, other)

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “or”.

    +
    +
    + +
    +
    +mask(mask=None, replacement=None)[source]
    +

    Applies a mask to a raster data cube. To apply a vector mask use mask_polygon.

    +

    A 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).

    +
    +
    Parameters:
    +
      +
    • mask (DataCube) – the raster mask

    • +
    • replacement – the value to replace the masked pixels with

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mask”.

    +
    +
    + +
    +
    +mask_polygon(mask, srs=None, replacement=None, inside=None)[source]
    +

    Applies a polygon mask to a raster data cube. To apply a raster mask use mask.

    +

    All 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.

    +

    The pixel values are replaced with the value specified for replacement, +which defaults to no data.

    +
    +
    Parameters:
    +
      +
    • mask (Union[BaseGeometry, dict, str, Path, Parameter, VectorCube]) – The geometry to mask with: a shapely geometry, a GeoJSON-style dictionary, +a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file.

    • +
    • srs (str) –

      The spatial reference system of the provided polygon. +By default longitude-latitude (EPSG:4326) is assumed.

      +
      +

      Note

      +

      this srs argument is a non-standard/experimental feature, only supported by specific back-ends. +See https://github.com/Open-EO/openeo-processes/issues/235 for details.

      +
      +

    • +
    • replacement – the value to replace the masked pixels with

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mask_polygon”.

    +
    +
    + +
    +
    +max_time()[source]
    +

    Finds the maximum value of a time series for all bands of the input dataset.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “max”.

    +
    +
    + +
    +
    +mean_time()[source]
    +

    Finds the mean value of a time series for all bands of the input dataset.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “mean”.

    +
    +
    + +
    +
    +median_time()[source]
    +

    Finds the median value of a time series for all bands of the input dataset.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “median”.

    +
    +
    + +
    +
    +merge(other, overlap_resolver=None, context=None)
    +
    +

    Deprecated since version 0.4.6: Usage of this legacy method is deprecated. Use +merge_cubes() instead.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +merge_cubes(other, overlap_resolver=None, context=None)[source]
    +

    Merging two data cubes

    +

    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. +An 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.

    +

    Examples for merging two data cubes:

    +
      +
    1. 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.

    2. +
    3. 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.

    4. +
    5. +
      Data cubes with the dimensions x, y and t have the same dimension labels in x,y and t. There are two options:
        +
      • 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.

      • +
      • 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.

      • +
      +
      +
      +
    6. +
    7. 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.

    8. +
    +
    +
    Parameters:
    +
      +
    • other (DataCube) – The data cube to merge with.

    • +
    • overlap_resolver (Union[str, PGNode, Callable]) – A reduction operator that resolves the conflict if the data overlaps. The reducer must return a value of the same data type as the input values are. The reduction operator may be a single process such as multiply or consist of multiple sub-processes. null (the default) can be specified if no overlap resolver is required.

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    The merged data cube.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “merge_cubes”.

    +
    +
    + +
    +
    +min_time()[source]
    +

    Finds the minimum value of a time series for all bands of the input dataset.

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “min”.

    +
    +
    + +
    +
    +multiply(other, reverse=False)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “multiply”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +ndvi(nir=None, red=None, target_band=None)[source]
    +

    Normalized Difference Vegetation Index (NDVI)

    +
    +
    Parameters:
    +
      +
    • nir (str) – (optional) name of NIR band

    • +
    • red (str) – (optional) name of red band

    • +
    • target_band (str) – (optional) name of the newly created band

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “ndvi”.

    +
    +
    + +
    +
    +normalized_difference(other)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “normalized_difference”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +polygonal_histogram_timeseries(polygon)[source]
    +

    Extract a histogram time series for the given (multi)polygon. Its points are +expected to be in the EPSG:4326 coordinate +reference system.

    +
    +
    Parameters:
    +

    polygon (Union[Polygon, MultiPolygon, str]) – The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file

    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    +

    Deprecated since version 0.10.0: Use aggregate_spatial() with reducer 'histogram'.

    +
    +
    + +
    +
    +polygonal_mean_timeseries(polygon)[source]
    +

    Extract a mean time series for the given (multi)polygon. Its points are +expected to be in the EPSG:4326 coordinate +reference system.

    +
    +
    Parameters:
    +

    polygon (Union[Polygon, MultiPolygon, str]) – The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file

    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    +

    Deprecated since version 0.10.0: Use aggregate_spatial() with reducer 'mean'.

    +
    +
    + +
    +
    +polygonal_median_timeseries(polygon)[source]
    +

    Extract a median time series for the given (multi)polygon. Its points are +expected to be in the EPSG:4326 coordinate +reference system.

    +
    +
    Parameters:
    +

    polygon (Union[Polygon, MultiPolygon, str]) – The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file

    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    +

    Deprecated since version 0.10.0: Use aggregate_spatial() with reducer 'median'.

    +
    +
    + +
    +
    +polygonal_standarddeviation_timeseries(polygon)[source]
    +

    Extract a time series of standard deviations for the given (multi)polygon. Its points are +expected to be in the EPSG:4326 coordinate +reference system.

    +
    +
    Parameters:
    +

    polygon (Union[Polygon, MultiPolygon, str]) – The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file

    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    +

    Deprecated since version 0.10.0: Use aggregate_spatial() with reducer 'sd'.

    +
    +
    + +
    +
    +power(p)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “power”.

    +
    +
    + +
    +
    +predict_curve(parameters, function, dimension, labels=None)[source]
    +

    Predict values using a model function and pre-computed parameters.

    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change. +https://github.com/Open-EO/openeo-processes/pull/240

    +
    +
    +
    Parameters:
    +
    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “predict_curve”.

    +
    +
    + +
    +
    +predict_random_forest(model, dimension='bands')[source]
    +

    Apply reduce_dimension process with a predict_random_forest reducer.

    +
    +
    Parameters:
    +
      +
    • model (Union[str, BatchJob, MlModel]) –

      a reference to a trained model, one of

      +
        +
      • a MlModel instance (e.g. loaded from Connection.load_ml_model())

      • +
      • a BatchJob instance of a batch job that saved a single random forest model

      • +
      • a job id (str) of a batch job that saved a single random forest model

      • +
      • a STAC item URL (str) to load the random forest from. +(The STAC Item must implement the ml-model extension.)

      • +
      +

    • +
    • dimension (str) – dimension along which to apply the reduce_dimension process.

    • +
    +
    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “predict_random_forest”.

    +
    +
    + +
    +
    +preview(center=None, zoom=None)[source]
    +

    Creates a service with the process graph and displays a map widget. Only supports XYZ.

    +
    +
    Parameters:
    +
      +
    • center (Optional[Iterable]) – (optional) Map center. Default is (0,0).

    • +
    • zoom (Optional[int]) – (optional) Zoom level of the map. Default is 1.

    • +
    +
    +
    Returns:
    +

    ipyleaflet Map object and the displayed Service

    +
    +
    +
    +

    Warning

    +

    experimental feature, subject to change.

    +
    +
    +

    New in version 0.19.0.

    +
    +
    + +
    +
    +print_json(*, file=None, indent=2, separators=None, end='\\n')
    +

    Print interoperable JSON representation of the process graph.

    +

    See DataCube.to_json() to get the JSON representation as a string +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • file – file-like object (stream) to print to (current sys.stdout by default). +Or a path (string or pathlib.Path) to a file to write to.

    • +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    • end (str) – additional string to be printed at the end (newline by default).

    • +
    +
    +
    +
    +

    New in version 0.12.0.

    +
    +
    +

    New in version 0.23.0: added the end argument.

    +
    +
    + +
    +
    +process(process_id, arguments=None, metadata=None, namespace=None, **kwargs)[source]
    +

    Generic helper to create a new DataCube by applying a process.

    +
    +
    Parameters:
    +
      +
    • process_id (str) – process id of the process.

    • +
    • arguments (Optional[dict]) – argument dictionary for the process.

    • +
    • metadata (Optional[CollectionMetadata]) – optional: metadata to override original cube metadata (e.g. when reducing dimensions)

    • +
    • namespace (Optional[str]) – optional: process namespace

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    new DataCube instance

    +
    +
    +
    + +
    +
    +process_with_node(pg, metadata=None)[source]
    +

    Generic helper to create a new DataCube by applying a process (given as process graph node)

    +
    +
    Parameters:
    +
      +
    • pg (PGNode) – process graph node (containing process id and arguments)

    • +
    • metadata (Optional[CollectionMetadata]) – optional: metadata to override original cube metadata (e.g. when reducing dimensions)

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    new DataCube instance

    +
    +
    +
    + +
    +
    +raster_to_vector()[source]
    +

    Converts this raster data cube into a VectorCube. +The bounding polygon of homogenous areas of pixels is constructed.

    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change.

    +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    Returns:
    +

    a VectorCube

    +
    +
    +
    + +
    +
    +reduce_bands(reducer)[source]
    +

    Shortcut for reduce_dimension() along the band dimension

    +
    +
    Parameters:
    +

    reducer (Union[str, PGNode, Callable, UDF]) – “child callback” function, see Processes with child “callbacks”

    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +reduce_bands_udf(code, runtime=None, version=None)[source]
    +

    Use reduce_dimension process with given UDF along band/spectral dimension. +:rtype: DataCube

    +
    +

    Deprecated since version 0.13.0: Use reduce_bands() with UDF as reducer.

    +
    +
    + +
    +
    +reduce_dimension(dimension, reducer, context=None, process_id='reduce_dimension', band_math_mode=False)[source]
    +

    Add a reduce process with given reducer callback along given dimension

    +
    +
    Parameters:
    +
      +
    • dimension (str) – the label of the dimension to reduce

    • +
    • reducer (Union[str, Callable, UDF, PGNode]) –

      the “child callback”: +the name of a single openEO process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

      +

      The callback should correspond to a process that +receives an array of numerical values +and returns a single numerical value. +For example:

      + +

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “reduce_dimension”.

    +
    +
    + +
    +
    +reduce_spatial(reducer, context=None)[source]
    +

    Add a reduce process with given reducer callback along the spatial dimensions

    +
    +
    Parameters:
    +
      +
    • reducer (Union[str, Callable, UDF, PGNode]) –

      the “child callback”: +the name of a single openEO process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

      +

      The callback should correspond to a process that +receives an array of numerical values +and returns a single numerical value. +For example:

      + +

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “reduce_spatial”.

    +
    +
    + +
    +
    +reduce_temporal(reducer)[source]
    +

    Shortcut for reduce_dimension() along the temporal dimension

    +
    +
    Parameters:
    +

    reducer (Union[str, PGNode, Callable, UDF]) – “child callback” function, see Processes with child “callbacks”

    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +reduce_temporal_simple(reducer)
    +
    +

    Deprecated since version 0.13.0: Usage of this legacy method is deprecated. Use +reduce_temporal() instead.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +reduce_temporal_udf(code, runtime='Python', version='latest')[source]
    +

    Apply reduce (reduce_dimension) process with given UDF along temporal dimension.

    +
    +
    Parameters:
    +
      +
    • code (str) – The UDF code, compatible with the given runtime and version

    • +
    • runtime – The UDF runtime

    • +
    • version – The UDF runtime version

    • +
    +
    +
    +
    +

    Deprecated since version 0.13.0: Use reduce_temporal() with UDF as reducer

    +
    +
    + +
    +
    +reduce_tiles_over_time(code, runtime='Python', version='latest')
    +
    +

    Deprecated since version 0.1.1: Usage of this legacy method is deprecated. Use +reduce_temporal_udf() instead.

    +
    +
    + +
    +
    +rename_dimension(source, target)[source]
    +

    Renames a dimension in the data cube while preserving all other properties.

    +
    +
    Parameters:
    +
      +
    • source (str) – The current name of the dimension. Fails with a DimensionNotAvailable error if the specified dimension does not exist.

    • +
    • target (str) – A new Name for the dimension. Fails with a DimensionExists error if a dimension with the specified name exists.

    • +
    +
    +
    Returns:
    +

    A new datacube with the dimension renamed.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rename_dimension”.

    +
    +
    + +
    +
    +rename_labels(dimension, target, source=None)[source]
    +

    Renames the labels of the specified dimension in the data cube from source to target.

    +
    +
    Parameters:
    +
      +
    • dimension (str) – Dimension name

    • +
    • target (list) – The new names for the labels.

    • +
    • source (list) – The names of the labels as they are currently in the data cube.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    An DataCube instance

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “rename_labels”.

    +
    +
    + +
    +
    +resample_cube_spatial(target, method='near')[source]
    +

    Resamples the spatial dimensions (x,y) from a source data cube to align with the corresponding +dimensions of the given target data cube. +Returns a new data cube with the resampled dimensions.

    +

    To resample a data cube to a specific resolution or projection regardless of an existing target +data cube, refer to resample_spatial().

    +
    +
    Parameters:
    +
      +
    • target (DataCube) – A data cube that describes the spatial target resolution.

    • +
    • method (str) – Resampling method to use.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    +
    +
    +
    + +
    +
    +resample_cube_temporal(target, dimension=None, valid_within=None)[source]
    +

    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.

    +

    By 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.

    +

    The rare case of ties is resolved by choosing the earlier timestamps.

    +
    +
    Parameters:
    +
      +
    • target (DataCube) – A data cube that describes the temporal target resolution.

    • +
    • dimension (Optional[str]) – The name of the temporal dimension to resample.

    • +
    • valid_within (Optional[int]) –

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    +
    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “resample_cube_temporal”.

    +
    +
    + +
    +
    +resample_spatial(resolution, projection=None, method='near', align='upper-left')[source]
    +
    +

    See also

    +

    openeo.org documentation on process “resample_spatial”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +resolution_merge(high_resolution_bands, low_resolution_bands, method=None)[source]
    +

    Resolution merging algorithms try to improve the spatial resolution of lower resolution bands +(e.g. Sentinel-2 20M) based on higher resolution bands. (e.g. Sentinel-2 10M).

    +

    External references:

    +

    Pansharpening explained

    +

    Example publication: ‘Improving the Spatial Resolution of Land Surface Phenology by Fusing Medium- and +Coarse-Resolution Inputs’

    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change.

    +
    +
    +
    Parameters:
    +
      +
    • high_resolution_bands (List[str]) – A list of band names to use as ‘high-resolution’ band. 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. The 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. These bands will remain unmodified.

    • +
    • low_resolution_bands (List[str]) – A list of band names for which the spatial resolution should be increased. 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. The 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. These bands will be modified by the process.

    • +
    • method (str) – The method to use. The supported algorithms can vary between back-ends. Set to null (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility..

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A datacube with the same bands and metadata as the input, but algorithmically increased spatial resolution for the selected bands.

    +
    +
    +
    +

    See also

    +

    openeo.org documentation on process “resolution_merge”.

    +
    +
    + +
    +
    +result_node()
    +

    Get the current result node (PGNode) of the process graph. +:rtype: PGNode

    +
    +

    New in version 0.10.1.

    +
    +
    + +
    +
    +sar_backscatter(coefficient='gamma0-terrain', elevation_model=None, mask=False, contributing_area=False, local_incidence_angle=False, ellipsoid_incidence_angle=False, noise_removal=True, options=None)[source]
    +

    Computes backscatter from SAR input.

    +

    Note 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.

    +
    +
    Parameters:
    +
      +
    • coefficient (Optional[str]) –

      Select the radiometric correction coefficient. +The following options are available:

      +
        +
      • ”beta0”: radar brightness

      • +
      • ”sigma0-ellipsoid”: ground area computed with ellipsoid earth model

      • +
      • ”sigma0-terrain”: ground area computed with terrain earth model

      • +
      • ”gamma0-ellipsoid”: ground area computed with ellipsoid earth model in sensor line of sight

      • +
      • ”gamma0-terrain”: ground area computed with terrain earth model in sensor line of sight (default)

      • +
      • None: non-normalized backscatter

      • +
      +

    • +
    • elevation_model (Optional[str]) – The digital elevation model to use. Set to None (the default) to allow +the back-end to choose, which will improve portability, but reduce reproducibility.

    • +
    • mask (bool) – 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).

    • +
    • contributing_area (bool) – If set to true, a DEM-based local contributing area band named contributing_area +is added. The values are given in square meters.

    • +
    • local_incidence_angle (bool) – If set to true, a DEM-based local incidence angle band named +local_incidence_angle is added. The values are given in degrees.

    • +
    • ellipsoid_incidence_angle (bool) – If set to true, an ellipsoidal incidence angle band named +ellipsoid_incidence_angle is added. The values are given in degrees.

    • +
    • noise_removal (bool) – If set to false, no noise removal is applied. Defaults to true, which removes noise.

    • +
    • options (Optional[dict]) – dictionary with additional (backend-specific) options.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    +
    +
    +
    +

    New in version 0.4.9.

    +
    +
    +

    Changed in version 0.4.10: replace orthorectify and rtc arguments with coefficient.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “sar_backscatter”.

    +
    +
    + +
    +
    +save_result(format='GTiff', options=None)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “save_result”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +save_user_defined_process(user_defined_process_id, public=False, summary=None, description=None, returns=None, categories=None, examples=None, links=None)[source]
    +

    Saves this process graph in the backend as a user-defined process for the authenticated user.

    +
    +
    Parameters:
    +
      +
    • user_defined_process_id (str) – unique identifier for the process

    • +
    • public (bool) – visible to other users?

    • +
    • summary (Optional[str]) – A short summary of what the process does.

    • +
    • description (Optional[str]) – Detailed description to explain the entity. CommonMark 0.29 syntax MAY be used for rich text representation.

    • +
    • returns (Optional[dict]) – Description and schema of the return value.

    • +
    • categories (Optional[List[str]]) – A list of categories.

    • +
    • examples (Optional[List[dict]]) – A list of examples.

    • +
    • links (Optional[List[dict]]) – A list of links.

    • +
    +
    +
    Return type:
    +

    RESTUserDefinedProcess

    +
    +
    Returns:
    +

    a RESTUserDefinedProcess instance

    +
    +
    +
    + +
    +
    +send_job(out_format=None, *, title=None, description=None, plan=None, budget=None, job_options=None, validate=None, **format_options)
    +
    +

    Deprecated since version 0.10.0: Usage of this legacy method is deprecated. Use +create_job() instead.

    +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    +
    + +
    +
    +subtract(other, reverse=False)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “subtract”.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +to_json(*, indent=2, separators=None)
    +

    Get interoperable JSON representation of the process graph.

    +

    See DataCube.print_json() to directly print the JSON representation +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    +
    +
    Return type:
    +

    str

    +
    +
    Returns:
    +

    JSON string

    +
    +
    +
    + +
    +
    +unflatten_dimension(dimension, target_dimensions, label_separator=None)[source]
    +

    Splits a single dimension into multiple dimensions by systematically extracting values and splitting +the dimension labels by the given label_separator. +This process is the opposite of the process flatten_dimensions() but executing both processes +subsequently doesn’t necessarily create a data cube that is equal to the original data cube.

    +
    +
    Parameters:
    +
      +
    • dimension (str) – The name of the dimension to split.

    • +
    • target_dimensions (List[str]) – The names of the target dimensions.

    • +
    • label_separator (Optional[str]) – The string that will be used as a separator to split the dimension labels.

    • +
    +
    +
    Returns:
    +

    A data cube with the new shape.

    +
    +
    +
    +

    Warning

    +

    experimental process: not generally supported, API subject to change.

    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “unflatten_dimension”.

    +
    +
    + +
    +
    +validate()[source]
    +

    Validate a process graph without executing it.

    +
    +
    Return type:
    +

    List[dict]

    +
    +
    Returns:
    +

    list of errors (dictionaries with “code” and “message” fields)

    +
    +
    +
    + +
    + +
    +
    +class openeo.rest._datacube.UDF(code, runtime=None, data=None, version=None, context=None, _source=None)[source]
    +

    Helper class to load UDF code (e.g. from file) and embed them as “callback” or child process in a process graph.

    +

    Usage example:

    +
    udf = UDF.from_file("my-udf-code.py")
    +cube = cube.apply(process=udf)
    +
    +
    +
    +

    Changed in version 0.13.0: Added auto-detection of runtime. +Specifying the data argument is not necessary anymore, and actually deprecated. +Added from_file() to simplify loading UDF code from a file. +See openeo.UDF API and usage changes in version 0.13.0 for more background about the changes.

    +
    +
    +
    +classmethod from_file(path, runtime=None, version=None, context=None)[source]
    +

    Load a UDF from a local file.

    +
    +

    See also

    +

    from_url() for loading from a URL.

    +
    +
    +
    Parameters:
    +
      +
    • path (Union[str, Path]) – path to the local file with UDF source code

    • +
    • runtime (Optional[str]) – optional UDF runtime identifier, will be auto-detected from source code if omitted.

    • +
    • version (Optional[str]) – optional UDF runtime version string

    • +
    • context (Optional[dict]) – optional additional UDF context data

    • +
    +
    +
    Return type:
    +

    UDF

    +
    +
    +
    + +
    +
    +classmethod from_url(url, runtime=None, version=None, context=None)[source]
    +

    Load a UDF from a URL.

    +
    +

    See also

    +

    from_file() for loading from a local file.

    +
    +
    +
    Parameters:
    +
      +
    • url (str) – URL path to load the UDF source code from

    • +
    • runtime (Optional[str]) – optional UDF runtime identifier, will be auto-detected from source code if omitted.

    • +
    • version (Optional[str]) – optional UDF runtime version string

    • +
    • context (Optional[dict]) – optional additional UDF context data

    • +
    +
    +
    Return type:
    +

    UDF

    +
    +
    +
    + +
    +
    +get_run_udf_callback(connection=None, data_parameter='data')[source]
    +

    For internal use: construct run_udf node to be used as callback in apply, reduce_dimension, …

    +
    +
    Return type:
    +

    PGNode

    +
    +
    +
    + +
    + +
    +
    +

    openeo.rest.vectorcube

    +
    +
    +class openeo.rest.vectorcube.VectorCube(graph, connection, metadata=None)[source]
    +

    A Vector Cube, or ‘Vector Collection’ is a data structure containing ‘Features’: +https://www.w3.org/TR/sdw-bp/#dfn-feature

    +

    The features in this cube are restricted to have a geometry. Geometries can be points, lines, polygons etcetera. +A geometry is specified in a ‘coordinate reference system’. https://www.w3.org/TR/sdw-bp/#dfn-coordinate-reference-system-(crs)

    +
    +
    +apply_dimension(process, dimension, target_dimension=None, context=None)[source]
    +

    Applies a process to all values along a dimension of a data cube. +For example, if the temporal dimension is specified the process will work on the values of a time series.

    +

    The process to apply is specified by providing a callback function in the process argument.

    +
    +
    Parameters:
    +
      +
    • process (Union[str, Callable, UDF, PGNode]) –

      the “child callback”: +the name of a single process, +or a callback function as discussed in Processes with child “callbacks”, +or a UDF instance.

      +

      The callback should correspond to a process that +receives an array of numerical values +and returns an array of numerical values. +For example:

      + +

    • +
    • dimension (str) – The name of the source dimension to apply the process on. Fails with a DimensionNotAvailable error if the specified dimension does not exist.

    • +
    • target_dimension (Optional[str]) – The name of the target dimension or null (the default) to use the source dimension +specified in the parameter dimension. By 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.

    • +
    • context (Optional[dict]) – Additional data to be passed to the process.

    • +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    Returns:
    +

    A datacube with the UDF applied to the given dimension.

    +
    +
    Raises:
    +

    DimensionNotAvailable

    +
    +
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “apply_dimension”.

    +
    +
    + +
    +
    +create_job(out_format=None, *, title=None, description=None, plan=None, budget=None, job_options=None, validate=None, **format_options)[source]
    +

    Sends a job to the backend and returns a ClientJob instance.

    +
    +
    Parameters:
    +
      +
    • out_format (Optional[str]) – String Format of the job result.

    • +
    • title (Optional[str]) – job title

    • +
    • description (Optional[str]) – job description

    • +
    • plan (Optional[str]) – billing plan

    • +
    • budget (Optional[float]) – maximum cost the request is allowed to produce

    • +
    • job_options (Optional[dict]) – A dictionary containing (custom) job options

    • +
    • format_options – String Parameters for the job result format

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    Returns:
    +

    Created job.

    +
    +
    +
    + +
    +
    +download(outputfile=None, format=None, options=None, *, validate=None)[source]
    +

    Execute synchronously and download the vector cube.

    +

    The result will be stored to the output path, when specified. +If no output path (or None) is given, the raw download content will be returned as bytes object.

    +
    +
    Parameters:
    +
      +
    • outputfile (Union[str, Path, None]) – (optional) output file to store the result to

    • +
    • format (Optional[str]) – (optional) output format to use.

    • +
    • options (Optional[dict]) – (optional) additional output format options.

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    Optional[bytes]

    +
    +
    +
    +

    Changed in version 0.21.0: When not specified explicitly, output format is guessed from output file extension.

    +
    +
    + +
    +
    +execute(*, validate=None)[source]
    +

    Executes the process graph.

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +execute_batch(outputfile=None, out_format=None, *, print=<built-in function print>, max_poll_interval=60, connection_retry_interval=30, job_options=None, validate=None, **format_options)[source]
    +

    Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. +This method is mostly recommended if the batch job is expected to run in a reasonable amount of time.

    +

    For very long running jobs, you probably do not want to keep the client running.

    +
    +
    Parameters:
    +
      +
    • job_options (Optional[dict]) –

    • +
    • outputfile (Union[str, Path, None]) – The path of a file to which a result can be written

    • +
    • out_format (Optional[str]) – (optional) output format to use.

    • +
    • format_options – (optional) additional output format options

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    +
    +

    Changed in version 0.21.0: When not specified explicitly, output format is guessed from output file extension.

    +
    +
    + +
    +
    +filter_bands(bands)[source]
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bands”.

    +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    + +
    +
    +filter_bbox(*, west=None, south=None, east=None, north=None, extent=None, crs=None)[source]
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_bbox”.

    +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    + +
    +
    +filter_labels(condition, dimension, context=None)[source]
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_labels”.

    +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    + +
    +
    +filter_vector(geometries, relation='intersects')[source]
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “filter_vector”.

    +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    + +
    +
    +fit_class_random_forest(target, max_variables=None, num_trees=100, seed=None)[source]
    +

    Executes the fit of a random forest classification based on the user input of target and predictors. +The Random Forest classification model is based on the approach by Breiman (2001).

    +
    +

    Warning

    +

    EXPERIMENTAL: not generally supported, API subject to change.

    +
    +
    +
    Parameters:
    +
      +
    • target (dict) – The training sites for the classification model as a vector data cube. This is associated with the target +variable for the Random Forest model. The geometry has to be associated with a value to predict (e.g. fractional +forest canopy cover).

    • +
    • max_variables (Optional[int]) – Specifies how many split variables will be used at a node. Default value is null, which corresponds to the +number of predictors divided by 3.

    • +
    • num_trees (int) – The number of trees build within the Random Forest classification.

    • +
    • seed (Optional[int]) – A randomization seed to use for the random sampling in training.

    • +
    +
    +
    Return type:
    +

    MlModel

    +
    +
    +
    +

    New in version 0.16.0: Originally added in version 0.10.0 as DataCube method, +but moved to VectorCube in version 0.16.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_class_random_forest”.

    +
    +
    + +
    +
    +fit_regr_random_forest(target, max_variables=None, num_trees=100, seed=None)[source]
    +

    Executes the fit of a random forest regression based on training data. +The Random Forest regression model is based on the approach by Breiman (2001).

    +
    +

    Warning

    +

    EXPERIMENTAL: not generally supported, API subject to change.

    +
    +
    +
    Parameters:
    +
      +
    • target (dict) – The training sites for the regression model as a vector data cube. +This is associated with the target variable for the Random Forest model. +The geometry has to associated with a value to predict (e.g. fractional forest canopy cover).

    • +
    • max_variables (Optional[int]) – Specifies how many split variables will be used at a node. Default value is null, which corresponds to the +number of predictors divided by 3.

    • +
    • num_trees (int) – The number of trees build within the Random Forest classification.

    • +
    • seed (Optional[int]) – A randomization seed to use for the random sampling in training.

    • +
    +
    +
    Return type:
    +

    MlModel

    +
    +
    +
    +

    New in version 0.16.0: Originally added in version 0.10.0 as DataCube method, +but moved to VectorCube in version 0.16.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “fit_regr_random_forest”.

    +
    +
    + +
    +
    +flat_graph()
    +

    Get the process graph in internal flat dict representation. +:rtype: Dict[str, dict]

    +
    +

    Warning

    +

    This method is mainly intended for internal use. +It is not recommended for general use and is subject to change.

    +

    Instead, it is recommended to use +to_json() or print_json() +to obtain a standardized, interoperable JSON representation of the process graph. +See Export a process graph for more information.

    +
    +
    + +
    +
    +classmethod load_geojson(connection, data, properties=None)[source]
    +

    Converts GeoJSON data as defined by RFC 7946 into a vector data cube.

    +
    +
    Parameters:
    +
      +
    • connection (Connection) – the connection to use to connect with the openEO back-end.

    • +
    • data (Union[dict, str, Path, BaseGeometry, Parameter]) –

      the geometry to load. One of:

      +
        +
      • GeoJSON-style data structure: e.g. a dictionary with "type": "Polygon" and "coordinates" fields

      • +
      • a path to a local GeoJSON file

      • +
      • a GeoJSON string

      • +
      • a shapely geometry object

      • +
      +

    • +
    • properties (Optional[List[str]]) – A list of properties from the GeoJSON file to construct an additional dimension from.

    • +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    Returns:
    +

    new VectorCube instance

    +
    +
    +
    +

    Warning

    +

    EXPERIMENTAL: this process is experimental with the potential for major things to change.

    +
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_geojson”.

    +
    +
    + +
    +
    +classmethod load_url(connection, url, format, options=None)[source]
    +

    Loads a file from a URL

    +
    +
    Parameters:
    +
      +
    • connection (Connection) – the connection to use to connect with the openEO back-end.

    • +
    • url (str) – The URL to read from. Authentication details such as API keys or tokens may need to be included in the URL.

    • +
    • format (str) – The file format to use when loading the data.

    • +
    • options (Optional[dict]) – The file format parameters to use when reading the data. +Must correspond to the parameters that the server reports as supported parameters for the chosen format

    • +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    Returns:
    +

    new VectorCube instance

    +
    +
    +
    +

    Warning

    +

    EXPERIMENTAL: this process is experimental with the potential for major things to change.

    +
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_url”.

    +
    +
    + +
    +
    +print_json(*, file=None, indent=2, separators=None, end='\\n')
    +

    Print interoperable JSON representation of the process graph.

    +

    See DataCube.to_json() to get the JSON representation as a string +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • file – file-like object (stream) to print to (current sys.stdout by default). +Or a path (string or pathlib.Path) to a file to write to.

    • +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    • end (str) – additional string to be printed at the end (newline by default).

    • +
    +
    +
    +
    +

    New in version 0.12.0.

    +
    +
    +

    New in version 0.23.0: added the end argument.

    +
    +
    + +
    +
    +process(process_id, arguments=None, metadata=None, namespace=None, **kwargs)[source]
    +

    Generic helper to create a new DataCube by applying a process.

    +
    +
    Parameters:
    +
      +
    • process_id (str) – process id of the process.

    • +
    • args – argument dictionary for the process.

    • +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    Returns:
    +

    new VectorCube instance

    +
    +
    +
    + +
    +
    +result_node()
    +

    Get the current result node (PGNode) of the process graph. +:rtype: PGNode

    +
    +

    New in version 0.10.1.

    +
    +
    + +
    +
    +run_udf(udf, runtime=None, version=None, context=None)[source]
    +

    Run a UDF on the vector cube.

    +

    It is recommended to provide the UDF just as UDF instance. +(the other arguments could be used to override UDF parameters if necessary).

    +
    +
    Parameters:
    +
      +
    • udf (Union[str, UDF]) – UDF code as a string or UDF instance

    • +
    • runtime (Optional[str]) – UDF runtime

    • +
    • version (Optional[str]) – UDF version

    • +
    • context (Optional[dict]) – UDF context

    • +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    +
    +

    Warning

    +

    EXPERIMENTAL: not generally supported, API subject to change.

    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    Changed in version 0.16.0: Added support to pass self-contained UDF instance.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “run_udf”.

    +
    +
    + +
    +
    +save_result(format='GeoJSON', options=None)[source]
    +
    +

    See also

    +

    openeo.org documentation on process “save_result”.

    +
    +
    + +
    +
    +send_job(out_format=None, *, title=None, description=None, plan=None, budget=None, job_options=None, validate=None, **format_options)
    +
    +

    Deprecated since version 0.10.0: Usage of this legacy method is deprecated. Use +create_job() instead.

    +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    +
    + +
    +
    +to_json(*, indent=2, separators=None)
    +

    Get interoperable JSON representation of the process graph.

    +

    See DataCube.print_json() to directly print the JSON representation +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    +
    +
    Return type:
    +

    str

    +
    +
    Returns:
    +

    JSON string

    +
    +
    +
    + +
    + +
    +
    +

    openeo.rest.mlmodel

    +
    +
    +class openeo.rest.mlmodel.MlModel(graph, connection)[source]
    +

    A machine learning model.

    +

    It is the result of a training procedure, e.g. output of a fit_... process, +and can be used for prediction (classification or regression) with the corresponding predict_... process.

    +
    +

    New in version 0.10.0.

    +
    +
    +
    +create_job(*, title=None, description=None, plan=None, budget=None, job_options=None)[source]
    +

    Sends a job to the backend and returns a ClientJob instance.

    +
    +
    Parameters:
    +
      +
    • title (Optional[str]) – job title

    • +
    • description (Optional[str]) – job description

    • +
    • plan (Optional[str]) – billing plan

    • +
    • budget (Optional[float]) – maximum cost the request is allowed to produce

    • +
    • job_options (Optional[dict]) – A dictionary containing (custom) job options

    • +
    • format_options – String Parameters for the job result format

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    Returns:
    +

    Created job.

    +
    +
    +
    + +
    +
    +execute_batch(outputfile, print=<built-in function print>, max_poll_interval=60, connection_retry_interval=30, job_options=None)[source]
    +

    Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. +This method is mostly recommended if the batch job is expected to run in a reasonable amount of time.

    +

    For very long running jobs, you probably do not want to keep the client running.

    +
    +
    Parameters:
    +
      +
    • job_options

    • +
    • outputfile (Union[str, Path]) – The path of a file to which a result can be written

    • +
    • out_format – (optional) Format of the job result.

    • +
    • format_options – String Parameters for the job result format

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    +
    + +
    +
    +flat_graph()
    +

    Get the process graph in internal flat dict representation. +:rtype: Dict[str, dict]

    +
    +

    Warning

    +

    This method is mainly intended for internal use. +It is not recommended for general use and is subject to change.

    +

    Instead, it is recommended to use +to_json() or print_json() +to obtain a standardized, interoperable JSON representation of the process graph. +See Export a process graph for more information.

    +
    +
    + +
    +
    +static load_ml_model(connection, id)[source]
    +

    Loads a machine learning model from a STAC Item.

    +
    +
    Parameters:
    +
      +
    • connection (Connection) – connection object

    • +
    • id (Union[str, BatchJob]) – STAC item reference, as URL, batch job (id) or user-uploaded file

    • +
    +
    +
    Return type:
    +

    MlModel

    +
    +
    Returns:
    +

    +
    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_ml_model”.

    +
    +
    + +
    +
    +print_json(*, file=None, indent=2, separators=None, end='\\n')
    +

    Print interoperable JSON representation of the process graph.

    +

    See DataCube.to_json() to get the JSON representation as a string +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • file – file-like object (stream) to print to (current sys.stdout by default). +Or a path (string or pathlib.Path) to a file to write to.

    • +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    • end (str) – additional string to be printed at the end (newline by default).

    • +
    +
    +
    +
    +

    New in version 0.12.0.

    +
    +
    +

    New in version 0.23.0: added the end argument.

    +
    +
    + +
    +
    +result_node()
    +

    Get the current result node (PGNode) of the process graph. +:rtype: PGNode

    +
    +

    New in version 0.10.1.

    +
    +
    + +
    +
    +save_ml_model(options=None)[source]
    +

    Saves a machine learning model as part of a batch job.

    +
    +
    Parameters:
    +

    options (Optional[dict]) – Additional parameters to create the file(s).

    +
    +
    +
    + +
    +
    +to_json(*, indent=2, separators=None)
    +

    Get interoperable JSON representation of the process graph.

    +

    See DataCube.print_json() to directly print the JSON representation +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    +
    +
    Return type:
    +

    str

    +
    +
    Returns:
    +

    JSON string

    +
    +
    +
    + +
    + +
    +
    +

    openeo.metadata

    +
    +
    +class openeo.metadata.BandDimension(name, bands)[source]
    +
    +
    +append_band(band)[source]
    +

    Create new BandDimension with appended band.

    +
    +
    Return type:
    +

    BandDimension

    +
    +
    +
    + +
    +
    +band_index(band)[source]
    +

    Resolve a given band (common) name/index to band index

    +
    +
    Parameters:
    +

    band (Union[int, str]) – band name, common name or index

    +
    +
    Return int:
    +

    band index

    +
    +
    Return type:
    +

    int

    +
    +
    +
    + +
    +
    +band_name(band, allow_common=True)[source]
    +

    Resolve (common) name or index to a valid (common) name

    +
    +
    Return type:
    +

    str

    +
    +
    +
    + +
    +
    +filter_bands(bands)[source]
    +

    Construct new BandDimension with subset of bands, +based on given band indices or (common) names

    +
    +
    Return type:
    +

    BandDimension

    +
    +
    +
    + +
    +
    +rename_labels(target, source)[source]
    +

    Rename labels, if the type of dimension allows it.

    +
    +
    Parameters:
    +
      +
    • target – List of target labels

    • +
    • source – Source labels, or empty list

    • +
    +
    +
    Return type:
    +

    Dimension

    +
    +
    Returns:
    +

    A new dimension with modified labels, or the same if no change is applied.

    +
    +
    +
    + +
    + +
    +
    +class openeo.metadata.CollectionMetadata(metadata, dimensions=None)[source]
    +

    Wrapper for Image Collection metadata.

    +

    Simplifies getting values from deeply nested mappings, +allows additional parsing and normalizing compatibility issues.

    +

    Metadata is expected to follow format defined by +https://openeo.org/documentation/1.0/developers/api/reference.html#operation/describe-collection +(with partial support for older versions)

    +
    +
    +add_dimension(name, label, type=None)[source]
    +

    Create new metadata object with added dimension

    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    +
    + +
    +
    +append_band(band)[source]
    +

    Create new CollectionMetadata with given band added to band dimension.

    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    +
    + +
    +
    +assert_valid_dimension(dimension)[source]
    +

    Make sure given dimension name is valid.

    +
    +
    Return type:
    +

    str

    +
    +
    +
    + +
    +
    +property band_dimension: BandDimension
    +

    Dimension corresponding to spectral/logic/thematic “bands”.

    +
    + +
    +
    +property band_names: List[str]
    +

    Get band names of band dimension

    +
    + +
    +
    +property bands: List[Band]
    +

    Get band metadata as list of Band metadata tuples

    +
    + +
    +
    +drop_dimension(name=None)[source]
    +

    Drop dimension with given name

    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    +
    + +
    +
    +filter_bands(band_names)[source]
    +

    Create new CollectionMetadata with filtered band dimension +:type band_names: List[Union[str, int]] +:param band_names: list of band names/indices to keep +:rtype: CollectionMetadata +:return:

    +
    + +
    +
    +reduce_dimension(dimension_name)[source]
    +

    Create new metadata object by collapsing/reducing a dimension.

    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    +
    + +
    +
    +reduce_spatial()[source]
    +

    Create new metadata object by reducing the spatial dimensions.

    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    +
    + +
    +
    +rename_dimension(source, target)[source]
    +

    Rename source dimension into target, preserving other properties

    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    +
    + +
    +
    +rename_labels(dimension, target, source=None)[source]
    +

    Renames the labels of the specified dimension from source to target.

    +
    +
    Parameters:
    +
      +
    • dimension (str) – Dimension name

    • +
    • target (list) – The new names for the labels.

    • +
    • source (list) – The names of the labels as they are currently in the data cube.

    • +
    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    Returns:
    +

    Updated metadata

    +
    +
    +
    + +
    + +
    +
    +class openeo.metadata.SpatialDimension(name, extent, crs=4326, step=None)[source]
    +
    +
    +rename(name)[source]
    +

    Create new dimension with new name.

    +
    +
    Return type:
    +

    Dimension

    +
    +
    +
    + +
    + +
    +
    +class openeo.metadata.TemporalDimension(name, extent)[source]
    +
    +
    +rename(name)[source]
    +

    Create new dimension with new name.

    +
    +
    Return type:
    +

    Dimension

    +
    +
    +
    + +
    + +
    +
    +

    openeo.api.process

    +
    +
    +class openeo.api.process.Parameter(name, description=None, schema=None, default=<object object>, optional=None)[source]
    +

    Wrapper for a process parameter, as used in predefined and user-defined processes.

    +
    +
    +classmethod array(name, description=None, default=<object object>, *, item_schema=None)[source]
    +

    Helper to create an ‘array’ type parameter.

    +
    +
    Parameters:
    +

    item_schema (Union[str, dict, None]) – Schema of the array items given in JSON Schema style, e.g. {"type": "string"}. +Simple schemas can also be specified as single string: +e.g. "string" will be expanded to {"type": "string"}.

    +
    +
    Return type:
    +

    Parameter

    +
    +
    +
    +

    Changed in version 0.23.0: Added item_schema argument.

    +
    +
    + +
    +
    +classmethod boolean(name, description=None, default=<object object>)[source]
    +

    Helper to create a ‘boolean’ type parameter.

    +
    +
    Return type:
    +

    Parameter

    +
    +
    +
    + +
    +
    +classmethod datacube(name='data', description='A data cube.')[source]
    +

    Helper to easily create a ‘datacube’ parameter.

    +
    +
    Parameters:
    +
      +
    • name (str) – name of the parameter.

    • +
    • description (str) – description of the parameter

    • +
    +
    +
    Return type:
    +

    Parameter

    +
    +
    Returns:
    +

    Parameter

    +
    +
    +
    +

    New in version 0.22.0.

    +
    +
    + +
    +
    +classmethod integer(name, description=None, default=<object object>)[source]
    +

    Helper to create a ‘integer’ type parameter.

    +
    +
    Return type:
    +

    Parameter

    +
    +
    +
    + +
    +
    +classmethod number(name, description=None, default=<object object>)[source]
    +

    Helper to create a ‘number’ type parameter.

    +
    +
    Return type:
    +

    Parameter

    +
    +
    +
    + +
    +
    +classmethod object(name, description=None, default=<object object>, *, subtype=None)[source]
    +

    Helper to create an ‘object’ type parameter

    +
    +
    Parameters:
    +

    subtype (Optional[str]) – subtype of the ‘object’ schema

    +
    +
    Return type:
    +

    Parameter

    +
    +
    +
    +

    New in version 0.26.0.

    +
    +
    + +
    +
    +classmethod raster_cube(name='data', description='A data cube.')[source]
    +

    Helper to easily create a ‘raster-cube’ parameter.

    +
    +
    Parameters:
    +
      +
    • name (str) – name of the parameter.

    • +
    • description (str) – description of the parameter

    • +
    +
    +
    Return type:
    +

    Parameter

    +
    +
    Returns:
    +

    Parameter

    +
    +
    +
    + +
    +
    +classmethod string(name, description=None, default=<object object>, values=None, subtype=None, format=None)[source]
    +

    Helper to create a ‘string’ type parameter.

    +
    +
    Return type:
    +

    Parameter

    +
    +
    +
    + +
    +
    +to_dict()[source]
    +

    Convert to dictionary for JSON-serialization.

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    + +
    +
    +

    openeo.api.logs

    +
    +
    +class openeo.api.logs.LogEntry(*args, **kwargs)[source]
    +

    Log message and info for jobs and services

    +
    +
    Fields:
      +
    • id: Unique ID for the log, string, REQUIRED

    • +
    • code: Error code, string, optional

    • +
    • level: Severity level, string (error, warning, info or debug), REQUIRED

    • +
    • message: Error message, string, REQUIRED

    • +
    • time: Date and time of the error event as RFC3339 date-time, string, available since API 1.1.0

    • +
    • path: A “stack trace” for the process, array of dicts

    • +
    • links: Related links, array of dicts

    • +
    • usage: Usage metrics available as property ‘usage’, dict, available since API 1.1.0 +May contain the following metrics: cpu, memory, duration, network, disk, storage and other custom ones +Each of the metrics is also a dict with the following parts: value (numeric) and unit (string)

    • +
    • data: Arbitrary data the user wants to “log” for debugging purposes. +Please note that this property may not exist as there’s a difference +between None and non-existing. None for example refers to no-data in +many cases while the absence of the property means that the user did +not provide any data for debugging.

    • +
    +
    +
    +
    + +
    +
    +openeo.api.logs.normalize_log_level(log_level, default=10)[source]
    +

    Helper function to convert a openEO API log level (e.g. string “error”) +to the integer constants defined in Python’s standard library logging module (e.g. logging.ERROR).

    +
    +
    Parameters:
    +
      +
    • log_level (Union[int, str, None]) – log level to normalize: a log level string in the style of +the openEO API (“error”, “warning”, “info”, or “debug”), +an integer value (e.g. a logging constant), or None.

    • +
    • default (int) – fallback log level to return on unknown log level strings or None input.

    • +
    +
    +
    Raises:
    +

    TypeError – when log_level is any other type than str, an int or None.

    +
    +
    Return type:
    +

    int

    +
    +
    Returns:
    +

    One of the following log level constants from the standard module logging: +logging.ERROR, logging.WARNING, logging.INFO, or logging.DEBUG .

    +
    +
    +
    + +
    +
    +

    openeo.rest.connection

    +

    This module provides a Connection object to manage and persist settings when interacting with the OpenEO API.

    +
    +
    +class openeo.rest.connection.Connection(url, *, auth=None, session=None, default_timeout=None, auth_config=None, refresh_token_store=None, slow_response_threshold=None, oidc_auth_renewer=None, auto_validate=True)[source]
    +

    Connection to an openEO backend.

    +
    +
    +as_curl(data, path='/result', method='POST', obfuscate_auth=False)[source]
    +

    Build curl command to evaluate given process graph or data cube +(including authorization and content-type headers).

    +
    >>> print(connection.as_curl(cube))
    +curl -i -X POST -H 'Content-Type: application/json' -H 'Authorization: Bearer ...' \
    +    --data '{"process":{"process_graph":{...}}' \
    +    https://openeo.example/openeo/1.1/result
    +
    +
    +
    +
    Parameters:
    +
      +
    • data (Union[dict, DataCube, FlatGraphableMixin]) – something that is convertable to an openEO process graph: a dictionary, +a DataCube object, +a ProcessBuilder, …

    • +
    • path – endpoint to send request to: typically "/result" (default) for synchronous requests +or "/jobs" for batch jobs

    • +
    • method – HTTP method to use (typically "POST")

    • +
    • obfuscate_auth (bool) – don’t show actual bearer token

    • +
    +
    +
    Return type:
    +

    str

    +
    +
    Returns:
    +

    curl command as a string

    +
    +
    +
    + +
    +
    +assert_user_defined_process_support()[source]
    +

    Capabilities document based verification that back-end supports user-defined processes.

    +
    +

    New in version 0.23.0.

    +
    +
    + +
    +
    +authenticate_basic(username=None, password=None)[source]
    +

    Authenticate a user to the backend using basic username and password.

    +
    +
    Parameters:
    +
      +
    • username (Optional[str]) – User name

    • +
    • password (Optional[str]) – User passphrase

    • +
    +
    +
    Return type:
    +

    Connection

    +
    +
    +
    + +
    +
    +authenticate_oidc(provider_id=None, client_id=None, client_secret=None, *, store_refresh_token=True, use_pkce=None, display=<built-in function print>, max_poll_time=300)[source]
    +

    Generic method to do OpenID Connect authentication.

    +

    In the context of interactive usage, this method first tries to use refresh tokens +and falls back on device code flow.

    +

    For non-interactive, machine-to-machine contexts, it is also possible to trigger +the usage of the “client_credentials” flow through environment variables. +Assuming you have set up a OIDC client (with a secret): +set OPENEO_AUTH_METHOD to client_credentials, +set OPENEO_AUTH_CLIENT_ID to the client id, +and set OPENEO_AUTH_CLIENT_SECRET to the client secret.

    +

    See OIDC Authentication: Dynamic Method Selection for more details.

    +
    +
    Parameters:
    +
      +
    • provider_id (Optional[str]) – provider id to use

    • +
    • client_id (Optional[str]) – client id to use

    • +
    • client_secret (Optional[str]) – client secret to use

    • +
    • max_poll_time (float) – maximum time in seconds to keep polling for successful authentication.

    • +
    +
    +
    +
    +

    New in version 0.6.0.

    +
    +
    +

    Changed in version 0.17.0: Add max_poll_time argument

    +
    +
    +

    Changed in version 0.18.0: Add support for client credentials flow.

    +
    +
    + +
    +
    +authenticate_oidc_authorization_code(client_id=None, client_secret=None, provider_id=None, timeout=None, server_address=None, webbrowser_open=None, store_refresh_token=False)[source]
    +

    OpenID Connect Authorization Code Flow (with PKCE). +:rtype: Connection

    +
    +

    Deprecated since version 0.19.0: Usage of the Authorization Code flow is deprecated (because of its complexity) and will be removed. +It is recommended to use the Device Code flow with authenticate_oidc_device() +or Client Credentials flow with authenticate_oidc_client_credentials().

    +
    +
    + +
    +
    +authenticate_oidc_client_credentials(client_id=None, client_secret=None, provider_id=None)[source]
    +

    Authenticate with OIDC Client Credentials flow

    +

    Client id, secret and provider id can be specified directly through the available arguments. +It is also possible to leave these arguments empty and specify them through +environment variables OPENEO_AUTH_CLIENT_ID, +OPENEO_AUTH_CLIENT_SECRET and OPENEO_AUTH_PROVIDER_ID respectively +as discussed in OIDC Client Credentials Using Environment Variables.

    +
    +
    Parameters:
    +
      +
    • client_id (Optional[str]) – client id to use

    • +
    • client_secret (Optional[str]) – client secret to use

    • +
    • provider_id (Optional[str]) – provider id to use +Fallback value can be set through environment variable OPENEO_AUTH_PROVIDER_ID.

    • +
    +
    +
    Return type:
    +

    Connection

    +
    +
    +
    +

    Changed in version 0.18.0: Allow specifying client id, secret and provider id through environment variables.

    +
    +
    + +
    +
    +authenticate_oidc_device(client_id=None, client_secret=None, provider_id=None, *, store_refresh_token=False, use_pkce=None, max_poll_time=300, **kwargs)[source]
    +

    Authenticate with the OIDC Device Code flow

    +
    +
    Parameters:
    +
      +
    • client_id (Optional[str]) – client id to use instead of the default one

    • +
    • client_secret (Optional[str]) – client secret to use instead of the default one

    • +
    • provider_id (Optional[str]) – provider id to use. +Fallback value can be set through environment variable OPENEO_AUTH_PROVIDER_ID.

    • +
    • store_refresh_token (bool) – whether to store the received refresh token automatically

    • +
    • use_pkce (Optional[bool]) – Use PKCE instead of client secret. +If not set explicitly to True (use PKCE) or False (use client secret), +it will be attempted to detect the best mode automatically. +Note that PKCE for device code is not widely supported among OIDC providers.

    • +
    • max_poll_time (float) – maximum time in seconds to keep polling for successful authentication.

    • +
    +
    +
    Return type:
    +

    Connection

    +
    +
    +
    +

    Changed in version 0.5.1: Add use_pkce argument

    +
    +
    +

    Changed in version 0.17.0: Add max_poll_time argument

    +
    +
    +

    Changed in version 0.19.0: Support fallback provider id through environment variable OPENEO_AUTH_PROVIDER_ID.

    +
    +
    + +
    +
    +authenticate_oidc_refresh_token(client_id=None, refresh_token=None, client_secret=None, provider_id=None, *, store_refresh_token=False)[source]
    +

    Authenticate with OIDC Refresh Token flow

    +
    +
    Parameters:
    +
      +
    • client_id (Optional[str]) – client id to use

    • +
    • refresh_token (Optional[str]) – refresh token to use

    • +
    • client_secret (Optional[str]) – client secret to use

    • +
    • provider_id (Optional[str]) – provider id to use. +Fallback value can be set through environment variable OPENEO_AUTH_PROVIDER_ID.

    • +
    • store_refresh_token (bool) – whether to store the received refresh token automatically

    • +
    +
    +
    Return type:
    +

    Connection

    +
    +
    +
    +

    Changed in version 0.19.0: Support fallback provider id through environment variable OPENEO_AUTH_PROVIDER_ID.

    +
    +
    + +
    +
    +authenticate_oidc_resource_owner_password_credentials(username, password, client_id=None, client_secret=None, provider_id=None, store_refresh_token=False)[source]
    +

    OpenId Connect Resource Owner Password Credentials

    +
    +
    Return type:
    +

    Connection

    +
    +
    +
    + +
    +
    +capabilities()[source]
    +

    Loads all available capabilities.

    +
    +
    Return type:
    +

    RESTCapabilities

    +
    +
    +
    + +
    +
    +collection_items(name, spatial_extent=None, temporal_extent=None, limit=None)[source]
    +

    Loads items for a specific image collection. +May not be available for all collections.

    +

    This is an experimental API and is subject to change.

    +
    +
    Parameters:
    +
      +
    • name – String Id of the collection

    • +
    • spatial_extent (Optional[List[float]]) – Limits the items to the given bounding box in WGS84: +1. Lower left corner, coordinate axis 1 +2. Lower left corner, coordinate axis 2 +3. Upper right corner, coordinate axis 1 +4. Upper right corner, coordinate axis 2

    • +
    • temporal_extent (Optional[List[Union[str, datetime]]]) – Limits the items to the specified temporal interval.

    • +
    • limit (Optional[int]) – The amount of items per request/page. If None, the back-end decides. +The interval has to be specified as an array with exactly two elements (start, end). +Also supports open intervals by setting one of the boundaries to None, but never both.

    • +
    +
    +
    Return type:
    +

    Iterator[dict]

    +
    +
    Returns:
    +

    data_list: List A list of items

    +
    +
    +
    + +
    +
    +create_job(process_graph, *, title=None, description=None, plan=None, budget=None, additional=None, validate=None)[source]
    +

    Create a new job from given process graph on the back-end.

    +
    +
    Parameters:
    +
      +
    • process_graph (Union[dict, str, Path]) – (flat) dict representing a process graph, or process graph as raw JSON string, +or as local file path or URL

    • +
    • title (Optional[str]) – job title

    • +
    • description (Optional[str]) – job description

    • +
    • plan (Optional[str]) – billing plan

    • +
    • budget (Optional[float]) – maximum cost the request is allowed to produce

    • +
    • additional (Optional[dict]) – additional job options to pass to the backend

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    Returns:
    +

    Created job

    +
    +
    +
    + +
    +
    +datacube_from_flat_graph(flat_graph, parameters=None)[source]
    +

    Construct a DataCube from a flat dictionary representation of a process graph.

    +
    +
    Parameters:
    +

    flat_graph (dict) – flat dictionary representation of a process graph +or a process dictionary with such a flat process graph under a “process_graph” field +(and optionally parameter metadata under a “parameters” field).

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A DataCube corresponding with the operations encoded in the process graph

    +
    +
    +
    + +
    +
    +datacube_from_json(src, parameters=None)[source]
    +

    Construct a DataCube from JSON resource containing (flat) process graph representation.

    +
    +
    Parameters:
    +

    src (Union[str, Path]) – raw JSON string, URL to JSON resource or path to local JSON file

    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A DataCube corresponding with the operations encoded in the process graph

    +
    +
    +
    + +
    +
    +datacube_from_process(process_id, namespace=None, **kwargs)[source]
    +

    Load a data cube from a (custom) process.

    +
    +
    Parameters:
    +
      +
    • process_id (str) – The process id.

    • +
    • namespace (Optional[str]) – optional: process namespace

    • +
    • kwargs – The arguments of the custom process

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    A DataCube, without valid metadata, as the client is not aware of this custom process.

    +
    +
    +
    + +
    +
    +describe_account()[source]
    +

    Describes the currently authenticated user account.

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +describe_collection(collection_id)[source]
    +

    Get full collection metadata for given collection id.

    +
    +

    See also

    +

    list_collection_ids() +to list all collection ids provided by the back-end.

    +
    +
    +
    Parameters:
    +

    collection_id (str) – collection id

    +
    +
    Return type:
    +

    dict

    +
    +
    Returns:
    +

    collection metadata.

    +
    +
    +
    + +
    +
    +describe_process(id, namespace=None)[source]
    +

    Returns a single process from the back end.

    +
    +
    Parameters:
    +
      +
    • id (str) – The id of the process.

    • +
    • namespace (Optional[str]) – The namespace of the process.

    • +
    +
    +
    Return type:
    +

    dict

    +
    +
    Returns:
    +

    The process definition.

    +
    +
    +
    + +
    +
    +download(graph, outputfile=None, timeout=None, validate=None)[source]
    +

    Downloads the result of a process graph synchronously, +and save the result to the given file or return bytes object if no outputfile is specified. +This method is useful to export binary content such as images. For json content, the execute method is recommended.

    +
    +
    Parameters:
    +
      +
    • graph (Union[dict, FlatGraphableMixin, str, Path]) – (flat) dict representing a process graph, or process graph as raw JSON string, +or as local file path or URL

    • +
    • outputfile (Union[Path, str, None]) – output file

    • +
    • timeout (Optional[int]) – timeout to wait for response

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Return type:
    +

    Optional[bytes]

    +
    +
    +
    + +
    +
    +execute(process_graph, timeout=None, validate=None)[source]
    +

    Execute a process graph synchronously and return the result (assumed to be JSON).

    +
    +
    Parameters:
    +
      +
    • process_graph (Union[dict, str, Path]) – (flat) dict representing a process graph, or process graph as raw JSON string, +or as local file path or URL

    • +
    • validate (Optional[bool]) – Optional toggle to enable/prevent validation of the process graphs before execution +(overruling the connection’s auto_validate setting).

    • +
    +
    +
    Returns:
    +

    parsed JSON response

    +
    +
    +
    + +
    +
    +get_file(path, metadata=None)[source]
    +

    Gets a handle to a user-uploaded file in the user workspace on the back-end.

    +
    +
    Parameters:
    +

    path (Union[str, PurePosixPath]) – The path on the user workspace.

    +
    +
    Return type:
    +

    UserFile

    +
    +
    +
    + +
    +
    +imagecollection(collection_id, spatial_extent=None, temporal_extent=None, bands=None, properties=None, max_cloud_cover=None, fetch_metadata=True)
    +
    +

    Deprecated since version 0.4.10: Usage of this legacy method is deprecated. Use +load_collection() instead.

    +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +job(job_id)[source]
    +

    Get the job based on the id. The job with the given id should already exist.

    +

    Use openeo.rest.connection.Connection.create_job() to create new jobs

    +
    +
    Parameters:
    +

    job_id (str) – the job id of an existing job

    +
    +
    Return type:
    +

    BatchJob

    +
    +
    Returns:
    +

    A job object.

    +
    +
    +
    + +
    +
    +job_logs(job_id, offset)[source]
    +

    Get batch job logs. +:rtype: list

    +
    +

    Deprecated since version 0.4.10: Use openeo.rest.job.BatchJob.logs() instead.

    +
    +
    + +
    +
    +job_results(job_id)[source]
    +

    Get batch job results metadata. +:rtype: dict

    +
    +

    Deprecated since version 0.4.10: Use openeo.rest.job.BatchJob.get_results() instead.

    +
    +
    + +
    +
    +list_collection_ids()[source]
    +

    List all collection ids provided by the back-end.

    +
    +

    See also

    +

    describe_collection() +to get the metadata of a particular collection.

    +
    +
    +
    Return type:
    +

    List[str]

    +
    +
    Returns:
    +

    list of collection ids

    +
    +
    +
    + +
    +
    +list_collections()[source]
    +

    List basic metadata of all collections provided by the back-end.

    +
    +

    Caution

    +

    Only the basic collection metadata will be returned. +To obtain full metadata of a particular collection, +it is recommended to use describe_collection() instead.

    +
    +
    +
    Return type:
    +

    List[dict]

    +
    +
    Returns:
    +

    list of dictionaries with basic collection metadata.

    +
    +
    +
    + +
    +
    +list_file_formats()[source]
    +

    Get available input and output formats

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +list_file_types()
    +
    +

    Deprecated since version 0.4.6: Usage of this legacy method is deprecated. Use +list_output_formats() instead.

    +
    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +list_files()[source]
    +

    Lists all user-uploaded files in the user workspace on the back-end.

    +
    +
    Return type:
    +

    List[UserFile]

    +
    +
    Returns:
    +

    List of the user-uploaded files.

    +
    +
    +
    + +
    +
    +list_jobs()[source]
    +

    Lists all jobs of the authenticated user.

    +
    +
    Return type:
    +

    List[dict]

    +
    +
    Returns:
    +

    job_list: Dict of all jobs of the user.

    +
    +
    +
    + +
    +
    +list_processes(namespace=None)[source]
    +

    Loads all available processes of the back end.

    +
    +
    Parameters:
    +

    namespace (Optional[str]) – The namespace for which to list processes.

    +
    +
    Return type:
    +

    List[dict]

    +
    +
    Returns:
    +

    processes_dict: Dict All available processes of the back end.

    +
    +
    +
    + +
    +
    +list_service_types()[source]
    +

    Loads all available service types.

    +
    +
    Return type:
    +

    dict

    +
    +
    Returns:
    +

    data_dict: Dict All available service types

    +
    +
    +
    + +
    +
    +list_services()[source]
    +

    Loads all available services of the authenticated user.

    +
    +
    Return type:
    +

    dict

    +
    +
    Returns:
    +

    data_dict: Dict All available services

    +
    +
    +
    + +
    +
    +list_udf_runtimes()[source]
    +

    Loads all available UDF runtimes.

    +
    +
    Return type:
    +

    dict

    +
    +
    Returns:
    +

    data_dict: Dict All available UDF runtimes

    +
    +
    +
    + +
    +
    +list_user_defined_processes()[source]
    +

    Lists all user-defined processes of the authenticated user.

    +
    +
    Return type:
    +

    List[dict]

    +
    +
    +
    + +
    +
    +load_collection(collection_id, spatial_extent=None, temporal_extent=None, bands=None, properties=None, max_cloud_cover=None, fetch_metadata=True)[source]
    +

    Load a DataCube by collection id.

    +
    +
    Parameters:
    +
      +
    • collection_id (Union[str, Parameter]) – image collection identifier

    • +
    • spatial_extent (Union[Dict[str, float], Parameter, None]) – limit data to specified bounding box or polygons

    • +
    • temporal_extent (Union[Sequence[Union[str, date, Parameter, PGNode, ProcessBuilderBase, None]], Parameter, str, None]) – limit data to specified temporal interval. +Typically, just a two-item list or tuple containing start and end date. +See Filter on temporal extent for more details on temporal extent handling and shorthand notation.

    • +
    • bands (Union[None, List[str], Parameter]) – only add the specified bands.

    • +
    • properties (Union[None, Dict[str, Union[str, PGNode, Callable]], List[CollectionProperty], CollectionProperty]) – limit data by collection metadata property predicates. +See collection_property() for easy construction of such predicates.

    • +
    • max_cloud_cover (Optional[float]) – shortcut to set maximum cloud cover (“eo:cloud_cover” collection property)

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a datacube containing the requested data

    +
    +
    +
    +

    New in version 0.13.0: added the max_cloud_cover argument.

    +
    +
    +

    Changed in version 0.23.0: Argument temporal_extent: add support for year/month shorthand notation +as discussed at Year/month shorthand notation.

    +
    +
    +

    Changed in version 0.26.0: Add collection_property() support to properties argument.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_collection”.

    +
    +
    + +
    +
    +load_disk_collection(format, glob_pattern, options=None)[source]
    +

    Loads image data from disk as a DataCube.

    +
    +
    Parameters:
    +
      +
    • format (str) – the file format, e.g. ‘GTiff’

    • +
    • glob_pattern (str) – a glob pattern that matches the files to load from disk

    • +
    • options (Optional[dict]) – options specific to the file format

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    + +
    +
    +load_geojson(data, properties=None)[source]
    +

    Converts GeoJSON data as defined by RFC 7946 into a vector data cube.

    +
    +
    Parameters:
    +
      +
    • data (Union[dict, str, Path, BaseGeometry, Parameter]) –

      the geometry to load. One of:

      +
        +
      • GeoJSON-style data structure: e.g. a dictionary with "type": "Polygon" and "coordinates" fields

      • +
      • a path to a local GeoJSON file

      • +
      • a GeoJSON string

      • +
      • a shapely geometry object

      • +
      +

    • +
    • properties (Optional[List[str]]) – A list of properties from the GeoJSON file to construct an additional dimension from.

    • +
    +
    +
    Returns:
    +

    new VectorCube instance

    +
    +
    +
    +

    Warning

    +

    EXPERIMENTAL: this process is experimental with the potential for major things to change.

    +
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_geojson”.

    +
    +
    + +
    +
    +load_ml_model(id)[source]
    +

    Loads a machine learning model from a STAC Item.

    +
    +
    Parameters:
    +

    id (Union[str, BatchJob]) – STAC item reference, as URL, batch job (id) or user-uploaded file

    +
    +
    Return type:
    +

    MlModel

    +
    +
    Returns:
    +

    +
    +
    +
    +

    New in version 0.10.0.

    +
    +
    + +
    +
    +load_result(id, spatial_extent=None, temporal_extent=None, bands=None)[source]
    +

    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.

    +
    +
    Parameters:
    +
      +
    • id (str) – The id of a batch job with results.

    • +
    • spatial_extent (Optional[Dict[str, float]]) – limit data to specified bounding box or polygons

    • +
    • temporal_extent (Union[Sequence[Union[str, date, Parameter, PGNode, ProcessBuilderBase, None]], Parameter, str, None]) – limit data to specified temporal interval. +Typically, just a two-item list or tuple containing start and end date. +See Filter on temporal extent for more details on temporal extent handling and shorthand notation.

    • +
    • bands (Optional[List[str]]) – only add the specified bands

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    a DataCube

    +
    +
    +
    +

    Changed in version 0.23.0: Argument temporal_extent: add support for year/month shorthand notation +as discussed at Year/month shorthand notation.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_result”.

    +
    +
    + +
    +
    +load_stac(url, spatial_extent=None, temporal_extent=None, bands=None, properties=None)[source]
    +

    Loads data from a static STAC catalog or a STAC API Collection and returns the data as a processable DataCube. +A batch job result can be loaded by providing a reference to it.

    +

    If supported by the underlying metadata and file format, the data that is added to the data cube can be +restricted with the parameters spatial_extent, temporal_extent and bands. +If no data is available for the given extents, a NoDataAvailable error is thrown.

    +

    Remarks:

    +
      +
    • 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.

    • +
    • 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 values should be processed only after the data has been limited to the required extent +and as a consequence also to a manageable size.

    • +
    +
    +
    Parameters:
    +
      +
    • url (str) –

      The URL to a static STAC catalog (STAC Item, STAC Collection, or STAC Catalog) +or a specific STAC API Collection that allows to filter items and to download assets. +This includes batch job results, which itself are compliant to STAC. +For external URLs, authentication details such as API keys or tokens may need to be included in the URL.

      +

      Batch job results can be specified in two ways:

      +
        +
      • For Batch job results at the same back-end, a URL pointing to the corresponding batch job results +endpoint should be provided. The URL usually ends with /jobs/{id}/results and {id} +is the corresponding batch job ID.

      • +
      • For external results, a signed URL must be provided. Not all back-ends support signed URLs, +which are provided as a link with the link relation canonical in the batch job result metadata.

      • +
      +

    • +
    • spatial_extent (Optional[Dict[str, float]]) –

      Limits the data to load to the specified bounding box or polygons.

      +

      For raster data, the process loads the pixel into the data cube if the point at the pixel center intersects +with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC).

      +

      For vector data, the process loads the geometry into the data cube if the geometry is fully within the +bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). +Empty geometries may only be in the data cube if no spatial extent has been provided.

      +

      The GeoJSON can be one of the following feature types:

      +
        +
      • A Polygon or MultiPolygon geometry,

      • +
      • a Feature with a Polygon or MultiPolygon geometry, or

      • +
      • a FeatureCollection containing at least one Feature with Polygon or MultiPolygon geometries.

      • +
      +

      Set this parameter to None 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.

      +

    • +
    • temporal_extent (Union[Sequence[Union[str, date, Parameter, PGNode, ProcessBuilderBase, None]], Parameter, str, None]) –

      Limits the data to load 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:

      +
        +
      1. The first element is the start of the temporal interval. +The specified instance in time is included in the interval.

      2. +
      3. The second element is the end of the temporal interval. +The specified instance in time is excluded from the interval.

      4. +
      +

      The second element must always be greater/later than the first element. +Otherwise, a TemporalExtentEmpty exception is thrown.

      +

      Also supports open intervals by setting one of the boundaries to None, but never both.

      +

      Set this parameter to None 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.

      +

    • +
    • bands (Optional[List[str]]) –

      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.

      +

      Either 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.

      +

      The 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.

      +

      It is recommended to use this parameter instead of using filter_bands() directly after loading unbounded data.

      +

    • +
    • properties (Optional[Dict[str, Union[str, PGNode, Callable]]]) –

      Limits the data by metadata properties to include only data in the data cube which +all given conditions return True for (AND operation).

      +

      Specify key-value-pairs with the key being the name of the metadata property, +which can be retrieved with the openEO Data Discovery for Collections. +The value must be a condition (user-defined process) to be evaluated against a STAC API. +This parameter is not supported for static STAC.

      +

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    +
    +

    New in version 0.17.0.

    +
    +
    +

    Changed in version 0.23.0: Argument temporal_extent: add support for year/month shorthand notation +as discussed at Year/month shorthand notation.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_stac”.

    +
    +
    + +
    +
    +load_url(url, format, options=None)[source]
    +

    Loads a file from a URL

    +
    +
    Parameters:
    +
      +
    • url (str) – The URL to read from. Authentication details such as API keys or tokens may need to be included in the URL.

    • +
    • format (str) – The file format to use when loading the data.

    • +
    • options (Optional[dict]) – The file format parameters to use when reading the data. +Must correspond to the parameters that the server reports as supported parameters for the chosen format

    • +
    +
    +
    Returns:
    +

    new VectorCube instance

    +
    +
    +
    +

    Warning

    +

    EXPERIMENTAL: this process is experimental with the potential for major things to change.

    +
    +
    +

    New in version 0.22.0.

    +
    +
    +

    See also

    +

    openeo.org documentation on process “load_url”.

    +
    +
    + +
    +
    +remove_service(service_id)[source]
    +

    Stop and remove a secondary web service.

    +
    +
    Parameters:
    +

    service_id (str) – service identifier

    +
    +
    Returns:
    +

    +
    +
    +
    +

    Deprecated since version 0.8.0: Use openeo.rest.service.Service.delete_service() +instead.

    +
    +
    + +
    +
    +request(method, path, headers=None, auth=None, check_error=True, expected_status=None, **kwargs)[source]
    +

    Generic request send

    +
    + +
    +
    +save_user_defined_process(user_defined_process_id, process_graph, parameters=None, public=False, summary=None, description=None, returns=None, categories=None, examples=None, links=None)[source]
    +

    Store a process graph and its metadata on the backend as a user-defined process for the authenticated user.

    +
    +
    Parameters:
    +
      +
    • user_defined_process_id (str) – unique identifier for the user-defined process

    • +
    • process_graph (Union[dict, ProcessBuilderBase]) – a process graph

    • +
    • parameters (List[Union[dict, Parameter]]) – a list of parameters

    • +
    • public (bool) – visible to other users?

    • +
    • summary (Optional[str]) – A short summary of what the process does.

    • +
    • description (Optional[str]) – Detailed description to explain the entity. CommonMark 0.29 syntax MAY be used for rich text representation.

    • +
    • returns (Optional[dict]) – Description and schema of the return value.

    • +
    • categories (Optional[List[str]]) – A list of categories.

    • +
    • examples (Optional[List[dict]]) – A list of examples.

    • +
    • links (Optional[List[dict]]) – A list of links.

    • +
    +
    +
    Return type:
    +

    RESTUserDefinedProcess

    +
    +
    Returns:
    +

    a RESTUserDefinedProcess instance

    +
    +
    +
    + +
    +
    +service(service_id)[source]
    +

    Get the secondary web service based on the id. The service with the given id should already exist.

    +

    Use openeo.rest.connection.Connection.create_service() to create new services

    +
    +
    Parameters:
    +

    job_id – the service id of an existing secondary web service

    +
    +
    Return type:
    +

    Service

    +
    +
    Returns:
    +

    A service object.

    +
    +
    +
    + +
    +
    +upload_file(source, target=None)[source]
    +

    Uploads a file to the given target location in the user workspace on the back-end.

    +

    If a file at the target path exists in the user workspace it will be replaced.

    +
    +
    Parameters:
    +
      +
    • source (Union[Path, str]) – A path to a file on the local file system to upload.

    • +
    • target (Union[str, PurePosixPath, None]) – The desired path (which can contain a folder structure if desired) on the user workspace. +If not set: defaults to the original filename (without any folder structure) of the local file .

    • +
    +
    +
    Return type:
    +

    UserFile

    +
    +
    +
    + +
    +
    +user_defined_process(user_defined_process_id)[source]
    +

    Get the user-defined process based on its id. The process with the given id should already exist.

    +
    +
    Parameters:
    +

    user_defined_process_id (str) – the id of the user-defined process

    +
    +
    Return type:
    +

    RESTUserDefinedProcess

    +
    +
    Returns:
    +

    a RESTUserDefinedProcess instance

    +
    +
    +
    + +
    +
    +user_jobs()[source]
    +
    +

    Deprecated since version 0.4.10: use list_jobs() instead

    +
    +
    +
    Return type:
    +

    List[dict]

    +
    +
    +
    + +
    +
    +validate_process_graph(process_graph)[source]
    +

    Validate a process graph without executing it.

    +
    +
    Parameters:
    +

    process_graph (dict) – (flat) dict representing process graph

    +
    +
    Return type:
    +

    List[dict]

    +
    +
    Returns:
    +

    list of errors (dictionaries with “code” and “message” fields)

    +
    +
    +
    + +
    +
    +vectorcube_from_paths(paths, format, options={})[source]
    +

    Loads one or more files referenced by url or path that is accessible by the backend.

    +
    +
    Parameters:
    +
      +
    • paths (List[str]) – The files to read.

    • +
    • format (str) – The file format to read from. It must be one of the values that the server reports as supported input file formats.

    • +
    • options (dict) – The file format parameters to be used to read the files. Must correspond to the parameters that the server reports as supported parameters for the chosen format.

    • +
    +
    +
    Return type:
    +

    VectorCube

    +
    +
    Returns:
    +

    A VectorCube.

    +
    +
    +
    +

    New in version 0.14.0.

    +
    +
    + +
    +
    +classmethod version_discovery(url, session=None, timeout=None)[source]
    +

    Do automatic openEO API version discovery from given url, using a “well-known URI” strategy.

    +
    +
    Parameters:
    +

    url (str) – initial backend url (not including “/.well-known/openeo”)

    +
    +
    Return type:
    +

    str

    +
    +
    Returns:
    +

    root url of highest supported backend version

    +
    +
    +
    + +
    +
    +version_info()[source]
    +

    List version of the openEO client, API, back-end, etc.

    +
    + +
    + +
    +
    +

    openeo.rest.job

    +
    +
    +class openeo.rest.job.BatchJob(job_id, connection)[source]
    +

    Handle for an openEO batch job, allowing it to describe, start, cancel, inspect results, etc.

    +
    +

    New in version 0.11.0: This class originally had the more cryptic name RESTJob, +which is still available as legacy alias, +but BatchJob is recommended since version 0.11.0.

    +
    +
    +
    +delete()[source]
    +

    Delete this batch job.

    +
    +

    New in version 0.20.0: This method was previously called delete_job().

    +
    +

    This method uses openEO endpoint DELETE /jobs/{job_id}

    +
    + +
    +
    +delete_job()
    +

    Delete this batch job.

    +
    +

    Deprecated since version 0.20.0: Usage of this legacy method is deprecated. Use delete() instead.

    +
    +
    + +
    +
    +describe()[source]
    +

    Get detailed metadata about a submitted batch job +(title, process graph, status, progress, …). +:rtype: dict

    +
    +

    New in version 0.20.0: This method was previously called describe_job().

    +
    +

    This method uses openEO endpoint GET /jobs/{job_id}

    +
    + +
    +
    +describe_job()
    +

    Get detailed metadata about a submitted batch job +(title, process graph, status, progress, …). +:rtype: dict

    +
    +

    Deprecated since version 0.20.0: Usage of this legacy method is deprecated. Use describe() instead.

    +
    +
    + +
    +
    +download_result(target=None)[source]
    +

    Download single job result to the target file path or into folder (current working dir by default).

    +

    Fails if there are multiple result files.

    +
    +
    Parameters:
    +

    target (Union[str, Path]) – String or path where the file should be downloaded to.

    +
    +
    Return type:
    +

    Path

    +
    +
    +
    + +
    +
    +download_results(target=None)[source]
    +

    Download all job result files into given folder (current working dir by default).

    +

    The names of the files are taken directly from the backend.

    +
    +
    Parameters:
    +

    target (Union[str, Path]) – String/path, folder where to put the result files.

    +
    +
    Return type:
    +

    Dict[Path, dict]

    +
    +
    Returns:
    +

    file_list: Dict containing the downloaded file path as value and asset metadata

    +
    +
    +
    +

    Deprecated since version 0.4.10: Instead use BatchJob.get_results() and the more +flexible download functionality of JobResults

    +
    +
    + +
    +
    +estimate()[source]
    +

    Calculate time/cost estimate for a job.

    +

    This method uses openEO endpoint GET /jobs/{job_id}/estimate

    +
    + +
    +
    +estimate_job()
    +

    Calculate time/cost estimate for a job.

    +
    +

    Deprecated since version 0.20.0: Usage of this legacy method is deprecated. Use estimate() instead.

    +
    +
    + +
    +
    +get_result()[source]
    +
    +

    Deprecated since version 0.4.10: Use BatchJob.get_results() instead.

    +
    +
    + +
    +
    +get_results()[source]
    +

    Get handle to batch job results for result metadata inspection or downloading resulting assets. +:rtype: JobResults

    +
    +

    New in version 0.4.10.

    +
    +
    + +
    +
    +get_results_metadata_url(*, full=False)[source]
    +

    Get results metadata URL

    +
    +
    Return type:
    +

    str

    +
    +
    +
    + +
    +
    +job_id
    +

    Unique identifier of the batch job (string).

    +
    + +
    +
    +list_results()[source]
    +

    Get batch job results metadata. +:rtype: dict

    +
    +

    Deprecated since version 0.4.10: Use get_results() instead.

    +
    +
    + +
    +
    +logs(offset=None, level=None)[source]
    +

    Retrieve job logs.

    +
    +
    Parameters:
    +
      +
    • offset (Optional[str]) –

      The last identifier (property id of a LogEntry) the client has received.

      +

      If provided, the back-ends only sends the entries that occurred after the specified identifier. +If not provided or empty, start with the first entry.

      +

      Defaults to None.

      +

    • +
    • level (Union[int, str, None]) –

      Minimum log level to retrieve.

      +

      You can use either constants from Python’s standard module logging +or their names (case-insensitive).

      +
      +
      For example:

      logging.INFO, "info" or "INFO" can all be used to show the messages +for level logging.INFO and above, i.e. also logging.WARNING and +logging.ERROR will be included.

      +
      +
      +

      Default is to show all log levels, in other words logging.DEBUG. +This is also the result when you explicitly pass log_level=None or log_level=””.

      +

    • +
    +
    +
    Return type:
    +

    List[LogEntry]

    +
    +
    Returns:
    +

    A list containing the log entries for the batch job.

    +
    +
    +
    + +
    +
    +run_synchronous(outputfile=None, print=<built-in function print>, max_poll_interval=60, connection_retry_interval=30)[source]
    +

    Start the job, wait for it to finish and download result

    +
    +
    Return type:
    +

    BatchJob

    +
    +
    +
    + +
    +
    +start()[source]
    +

    Start this batch job.

    +
    +
    Return type:
    +

    BatchJob

    +
    +
    Returns:
    +

    Started batch job

    +
    +
    +
    +

    New in version 0.20.0: This method was previously called start_job().

    +
    +

    This method uses openEO endpoint POST /jobs/{job_id}/results

    +
    + +
    +
    +start_and_wait(print=<built-in function print>, max_poll_interval=60, connection_retry_interval=30, soft_error_max=10)[source]
    +

    Start the batch job, poll its status and wait till it finishes (or fails)

    +
    +
    Parameters:
    +
      +
    • print – print/logging function to show progress/status

    • +
    • max_poll_interval (int) – maximum number of seconds to sleep between status polls

    • +
    • connection_retry_interval (int) – how long to wait when status poll failed due to connection issue

    • +
    • soft_error_max – maximum number of soft errors (e.g. temporary connection glitches) to allow

    • +
    +
    +
    Return type:
    +

    BatchJob

    +
    +
    Returns:
    +

    +
    +
    +
    + +
    +
    +start_job()
    +

    Start this batch job. +:rtype: BatchJob

    +
    +

    Deprecated since version 0.20.0: Usage of this legacy method is deprecated. Use start() instead.

    +
    +
    + +
    +
    +status()[source]
    +

    Get the status of the batch job

    +
    +
    Return type:
    +

    str

    +
    +
    Returns:
    +

    batch job status, one of “created”, “queued”, “running”, “canceled”, “finished” or “error”.

    +
    +
    +
    + +
    +
    +stop()[source]
    +

    Stop this batch job.

    +
    +

    New in version 0.20.0: This method was previously called stop_job().

    +
    +

    This method uses openEO endpoint DELETE /jobs/{job_id}/results

    +
    + +
    +
    +stop_job()
    +

    Stop this batch job.

    +
    +

    Deprecated since version 0.20.0: Usage of this legacy method is deprecated. Use stop() instead.

    +
    +
    + +
    + +
    +
    +class openeo.rest.job.JobResults(job)[source]
    +

    Results of a batch job: listing of one or more output files (assets) +and some metadata.

    +
    +

    New in version 0.4.10.

    +
    +
    +
    +download_file(target=None, name=None)[source]
    +

    Download single asset. Can be used when there is only one asset in the +JobResults, or when the desired asset name is given explicitly.

    +
    +
    Parameters:
    +
      +
    • target (Union[Path, str]) – path to download to. Can be an existing directory +(in which case the filename advertised by backend will be used) +or full file name. By default, the working directory will be used.

    • +
    • name (str) – asset name to download (not required when there is only one asset)

    • +
    +
    +
    Return type:
    +

    Path

    +
    +
    Returns:
    +

    path of downloaded asset

    +
    +
    +
    + +
    +
    +download_files(target=None, include_stac_metadata=True)[source]
    +

    Download all assets to given folder.

    +
    +
    Parameters:
    +
      +
    • target (Union[Path, str]) – path to folder to download to (must be a folder if it already exists)

    • +
    • include_stac_metadata (bool) – whether to download the job result metadata as a STAC (JSON) file.

    • +
    +
    +
    Return type:
    +

    List[Path]

    +
    +
    Returns:
    +

    list of paths to the downloaded assets.

    +
    +
    +
    + +
    +
    +get_asset(name=None)[source]
    +

    Get single asset by name or without name if there is only one.

    +
    +
    Return type:
    +

    ResultAsset

    +
    +
    +
    + +
    +
    +get_assets()[source]
    +

    Get all assets from the job results.

    +
    +
    Return type:
    +

    List[ResultAsset]

    +
    +
    +
    + +
    +
    +get_metadata(force=False)[source]
    +

    Get batch job results metadata (parsed JSON)

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    + +
    +
    +class openeo.rest.job.RESTJob(job_id, connection)[source]
    +

    Legacy alias for BatchJob.

    +
    +

    Deprecated since version 0.11.0: Use BatchJob instead

    +
    +
    + +
    +
    +class openeo.rest.job.ResultAsset(job, name, href, metadata)[source]
    +

    Result asset of a batch job (e.g. a GeoTIFF or JSON file)

    +
    +

    New in version 0.4.10.

    +
    +
    +
    +download(target=None, chunk_size=None)[source]
    +

    Download asset to given location

    +
    +
    Parameters:
    +

    target (Union[str, Path, None]) – download target path. Can be an existing folder +(in which case the filename advertised by backend will be used) +or full file name. By default, the working directory will be used.

    +
    +
    Return type:
    +

    Path

    +
    +
    +
    + +
    +
    +href
    +

    Download URL of the asset.

    +
    + +
    +
    +load_bytes()[source]
    +

    Load asset in memory as raw bytes.

    +
    +
    Return type:
    +

    bytes

    +
    +
    +
    + +
    +
    +load_json()[source]
    +

    Load asset in memory and parse as JSON.

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +metadata
    +

    Asset metadata provided by the backend, possibly containing keys “type” (for media type), “roles”, “title”, “description”.

    +
    + +
    +
    +name
    +

    Asset name as advertised by the backend.

    +
    + +
    + +
    +
    +

    openeo.rest.conversions

    +

    Helpers for data conversions between Python ecosystem data types and openEO data structures.

    +
    +
    +exception openeo.rest.conversions.InvalidTimeSeriesException[source]
    +
    + +
    +
    +openeo.rest.conversions.datacube_from_file(filename, fmt='netcdf')[source]
    +
    +

    Deprecated since version 0.7.0: Use XarrayDataCube.from_file() instead.

    +
    +
    +
    Return type:
    +

    XarrayDataCube

    +
    +
    +
    + +
    +
    +openeo.rest.conversions.datacube_plot(datacube, *args, **kwargs)[source]
    +
    +

    Deprecated since version 0.7.0: Use XarrayDataCube.plot() instead.

    +
    +
    + +
    +
    +openeo.rest.conversions.datacube_to_file(datacube, filename, fmt='netcdf')[source]
    +
    +

    Deprecated since version 0.7.0: Use XarrayDataCube.save_to_file() instead.

    +
    +
    + +
    +
    +openeo.rest.conversions.timeseries_json_to_pandas(timeseries, index='date', auto_collapse=True)[source]
    +

    Convert a timeseries JSON object as returned by the aggregate_spatial process to a pandas DataFrame object

    +

    This timeseries data has three dimensions in general: date, polygon index and band index. +One of these will be used as index of the resulting dataframe (as specified by the index argument), +and the other two will be used as multilevel columns. +When there is just a single polygon or band in play, the dataframe will be simplified +by removing the corresponding dimension if auto_collapse is enabled (on by default).

    +
    +
    Parameters:
    +
      +
    • timeseries (dict) – dictionary as returned by aggregate_spatial

    • +
    • index (str) – which dimension should be used for the DataFrame index: ‘date’ or ‘polygon’

    • +
    • auto_collapse – whether single band or single polygon cases should be simplified automatically

    • +
    +
    +
    Return type:
    +

    DataFrame

    +
    +
    Returns:
    +

    pandas DataFrame or Series

    +
    +
    +
    + +
    +
    +

    openeo.rest.udp

    +
    +
    +class openeo.rest.udp.RESTUserDefinedProcess(user_defined_process_id, connection)[source]
    +

    Wrapper for a user-defined process stored (or to be stored) on an openEO back-end

    +
    +
    +delete()[source]
    +

    Remove user-defined process from back-end

    +
    +
    Return type:
    +

    None

    +
    +
    +
    + +
    +
    +describe()[source]
    +

    Get metadata of this user-defined process.

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +store(process_graph, parameters=None, public=False, summary=None, description=None, returns=None, categories=None, examples=None, links=None)[source]
    +

    Store a process graph and its metadata on the backend as a user-defined process

    +
    + +
    +
    +update(process_graph, parameters=None, public=False, summary=None, description=None)[source]
    +
    +

    Deprecated since version 0.4.11: Use store instead. Method update is misleading: OpenEO API +does not provide (partial) updates of user-defined processes, +only fully overwriting ‘store’ operations.

    +
    +
    + +
    + +
    +
    +openeo.rest.udp.build_process_dict(process_graph, process_id=None, summary=None, description=None, parameters=None, returns=None, categories=None, examples=None, links=None)[source]
    +

    Build a dictionary describing a process with metadaa (process_graph, parameters, description, …)

    +
    +
    Parameters:
    +
      +
    • process_graph (Union[dict, FlatGraphableMixin]) – dict or builder representing a process graph

    • +
    • process_id (Optional[str]) – identifier of the process

    • +
    • summary (Optional[str]) – short summary of what the process does

    • +
    • description (Optional[str]) – detailed description

    • +
    • parameters (Optional[List[Union[dict, Parameter]]]) – list of process parameters (which have name, schema, default value, …)

    • +
    • returns (Optional[dict]) – description and schema of what the process returns

    • +
    • categories (Optional[List[str]]) – list of categories

    • +
    • examples (Optional[List[dict]]) – list of examples, may be used for unit tests

    • +
    • links (Optional[List[dict]]) – list of links related to the process

    • +
    +
    +
    Return type:
    +

    dict

    +
    +
    Returns:
    +

    dictionary in openEO “process graph with metadata” format

    +
    +
    +
    + +
    +
    +

    openeo.rest.userfile

    +
    +
    +class openeo.rest.userfile.UserFile(path, *, connection, metadata=None)[source]
    +

    Handle to a (user-uploaded) file in the user workspace on a openEO back-end.

    +
    +
    +delete()[source]
    +

    Delete the user-uploaded file from the user workspace on the back-end.

    +
    + +
    +
    +download(target=None)[source]
    +

    Downloads a user-uploaded file from the user workspace on the back-end +locally to the given location.

    +
    +
    Parameters:
    +

    target (Union[Path, str]) – local download target path. Can be an existing folder +(in which case the file name advertised by backend will be used) +or full file name. By default, the working directory will be used.

    +
    +
    Return type:
    +

    Path

    +
    +
    +
    + +
    +
    +classmethod from_metadata(metadata, connection)[source]
    +

    Build UserFile from a workspace file metadata dictionary.

    +
    +
    Return type:
    +

    UserFile

    +
    +
    +
    + +
    +
    +to_dict()[source]
    +

    Returns the provided metadata as dict.

    +
    +
    Return type:
    +

    Dict[str, Any]

    +
    +
    +
    + +
    +
    +upload(source)[source]
    +

    Uploads a local file to the path corresponding to this UserFile in the user workspace +and returns new UserFile of newly uploaded file.

    +
    +
    +

    Tip

    +

    Usually you’ll just need +Connection.upload_file() +instead of this UserFile method.

    +
    +
    +

    If the file exists in the user workspace it will be replaced.

    +
    +
    Parameters:
    +

    source (Union[Path, str]) – A path to a file on the local file system to upload.

    +
    +
    Return type:
    +

    UserFile

    +
    +
    Returns:
    +

    new UserFile instance of the newly uploaded file

    +
    +
    +
    + +
    + +
    +
    +

    openeo.udf

    +
    +
    +class openeo.udf.udf_data.UdfData(proj=None, datacube_list=None, feature_collection_list=None, structured_data_list=None, user_context=None)[source]
    +

    Container for data passed to a user defined function (UDF)

    +
    +
    +property datacube_list: List[XarrayDataCube] | None
    +

    Get the data cube list

    +
    + +
    +
    +property feature_collection_list: List[FeatureCollection] | None
    +

    get all feature collections as list

    +
    + +
    +
    +classmethod from_dict(udf_dict)[source]
    +

    Create a udf data object from a python dictionary that was created from +the JSON definition of the UdfData class

    +
    +
    Parameters:
    +

    udf_dict (dict) – The dictionary that contains the udf data definition

    +
    +
    Return type:
    +

    UdfData

    +
    +
    +
    + +
    +
    +get_datacube_list()[source]
    +

    Get the data cube list

    +
    +
    Return type:
    +

    Optional[List[XarrayDataCube]]

    +
    +
    +
    + +
    +
    +get_feature_collection_list()[source]
    +

    get all feature collections as list

    +
    +
    Return type:
    +

    Optional[List[FeatureCollection]]

    +
    +
    +
    + +
    +
    +get_structured_data_list()[source]
    +

    Get all structured data entries

    +
    +
    Return type:
    +

    Optional[List[StructuredData]]

    +
    +
    Returns:
    +

    A list of StructuredData objects

    +
    +
    +
    + +
    +
    +set_datacube_list(datacube_list)[source]
    +

    Set the data cube list

    +
    +
    Parameters:
    +

    datacube_list (Optional[List[XarrayDataCube]]) – A list of data cubes

    +
    +
    +
    + +
    +
    +set_structured_data_list(structured_data_list)[source]
    +

    Set the list of structured data

    +
    +
    Parameters:
    +

    structured_data_list (Optional[List[StructuredData]]) – A list of StructuredData objects

    +
    +
    +
    + +
    +
    +property structured_data_list: List[StructuredData] | None
    +

    Get all structured data entries

    +
    +
    Returns:
    +

    A list of StructuredData objects

    +
    +
    +
    + +
    +
    +to_dict()[source]
    +

    Convert this UdfData object into a dictionary that can be converted into +a valid JSON representation

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +property user_context: dict
    +

    Return the user context that was passed to the run_udf function

    +
    + +
    + +
    +
    +class openeo.udf.xarraydatacube.XarrayDataCube(array)[source]
    +

    This is a thin wrapper around xarray.DataArray +providing a basic “DataCube” interface for openEO UDF usage around multi-dimensional data.

    +
    +
    +property array: DataArray
    +

    Get the xarray.DataArray that contains the data and dimension definition

    +
    + +
    +
    +classmethod from_dict(xdc_dict)[source]
    +

    Create a XarrayDataCube from a Python dictionary that was created from +the JSON definition of the data cube

    +
    +
    Parameters:
    +

    data – The dictionary that contains the data cube definition

    +
    +
    Return type:
    +

    XarrayDataCube

    +
    +
    +
    + +
    +
    +classmethod from_file(path, fmt=None, **kwargs)[source]
    +

    Load data file as XarrayDataCube in memory

    +
    +
    Parameters:
    +
      +
    • path (Union[str, Path]) – the file on disk

    • +
    • fmt – format to load from, e.g. “netcdf” or “json” +(will be auto-detected when not specified)

    • +
    +
    +
    Return type:
    +

    XarrayDataCube

    +
    +
    Returns:
    +

    loaded data cube

    +
    +
    +
    + +
    +
    +get_array()[source]
    +

    Get the xarray.DataArray that contains the data and dimension definition

    +
    +
    Return type:
    +

    DataArray

    +
    +
    +
    + +
    +
    +plot(title=None, limits=None, show_bandnames=True, show_dates=True, show_axeslabels=False, fontsize=10.0, oversample=1, cmap='RdYlBu_r', cbartext=None, to_file=None, to_show=True)[source]
    +

    Visualize a XarrayDataCube with matplotlib

    +
    +
    Parameters:
    +
      +
    • datacube – data to plot

    • +
    • title (str) – title text drawn in the top left corner (default: nothing)

    • +
    • limits – range of the contour plot as a tuple(min,max) (default: None, in which case the min/max is computed from the data)

    • +
    • show_bandnames (bool) – whether to plot the column names (default: True)

    • +
    • show_dates (bool) – whether to show the dates for each row (default: True)

    • +
    • show_axeslabels (bool) – whether to show the labels on the axes (default: False)

    • +
    • fontsize (float) – font size in pixels (default: 10)

    • +
    • oversample (float) – one value is plotted into oversample x oversample number of pixels (default: 1 which means each value is plotted as a single pixel)

    • +
    • cmap (Union[str, ‘matplotlib.colors.Colormap’]) – built-in matplotlib color map name or ColorMap object (default: RdYlBu_r which is a blue-yellow-red rainbow)

    • +
    • cbartext (str) – text on top of the legend (default: nothing)

    • +
    • to_file (str) – filename to save the image to (default: None, which means no file is generated)

    • +
    • to_show (bool) – whether to show the image in a matplotlib window (default: True)

    • +
    +
    +
    Returns:
    +

    None

    +
    +
    +
    + +
    +
    +save_to_file(path, fmt=None, **kwargs)[source]
    +

    Store XarrayDataCube to file

    +
    +
    Parameters:
    +
      +
    • path (Union[str, Path]) – destination file on disk

    • +
    • fmt – format to save as, e.g. “netcdf” or “json” +(will be auto-detected when not specified)

    • +
    +
    +
    +
    + +
    +
    +to_dict()[source]
    +

    Convert this hypercube into a dictionary that can be converted into +a valid JSON representation

    +
    >>> example = {
    +...     "id": "test_data",
    +...     "data": [
    +...         [[0.0, 0.1], [0.2, 0.3]],
    +...         [[0.0, 0.1], [0.2, 0.3]],
    +...     ],
    +...     "dimension": [
    +...         {"name": "time", "coordinates": ["2001-01-01", "2001-01-02"]},
    +...         {"name": "X", "coordinates": [50.0, 60.0]},
    +...         {"name": "Y"},
    +:rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`dict\``
    +
    +
    +

    … ], +… }

    +
    + +
    + +
    +
    +class openeo.udf.structured_data.StructuredData(data, description=None, type=None)[source]
    +

    This class represents structured data that is produced by an UDF and can not be represented +as a raster or vector data cube. For example: the result of a statistical +computation.

    +

    Usage example:

    +
    >>> StructuredData([3, 5, 8, 13])
    +>>> StructuredData({"mean": 5, "median": 8})
    +>>> StructuredData([('col_1', 'col_2'), (1, 2), (2, 3)], type="table")
    +
    +
    +
    + +
    +
    +openeo.udf.run_code.execute_local_udf(udf, datacube, fmt='netcdf')[source]
    +

    Locally executes an user defined function on a previously downloaded datacube.

    +
    +
    Parameters:
    +
      +
    • udf (Union[str, UDF]) – the code of the user defined function

    • +
    • datacube (Union[str, DataArray, XarrayDataCube]) – the path to the downloaded data in disk or a DataCube

    • +
    • fmt – format of the file if datacube is string

    • +
    +
    +
    Returns:
    +

    the resulting DataCube

    +
    +
    +
    + +

    Debug utilities for UDFs

    +
    +
    +openeo.udf.debug.inspect(data=None, message='', code='User', level='info')[source]
    +

    Implementation of the openEO inspect process for UDF contexts.

    +

    Note that it is up to the back-end implementation to properly capture this logging +and include it in the batch job logs.

    +
    +
    Parameters:
    +
      +
    • data – data to log

    • +
    • message (str) – message to send in addition to the data

    • +
    • code (str) – A label to help identify one or more log entries

    • +
    • level (str) – The severity level of this message. Allowed values: “error”, “warning”, “info”, “debug”

    • +
    +
    +
    +
    +

    New in version 0.10.1.

    +
    +
    +

    See also

    +

    Logging from a UDF

    +
    +
    + +
    +
    +

    openeo.util

    +

    Various utilities and helpers.

    +
    +
    +class openeo.util.BBoxDict(*, west, south, east, north, crs=None)[source]
    +

    Dictionary based helper to easily create/work with bounding box dictionaries +(having keys “west”, “south”, “east”, “north”, and optionally “crs”).

    +
    +
    Parameters:
    +

    crs (Union[int, str, None]) – value describing the coordinate reference system. +Typically just an int (interpreted as EPSG code, e.g. 4326) +or a string (handled as authority string, e.g. "EPSG:4326"). +See openeo.util.normalize_crs() for more details about additional normalization that is applied to this argument.

    +
    +
    +
    +

    New in version 0.10.1.

    +
    +
    +
    +classmethod from_dict(data)[source]
    +

    Build from dictionary with at least keys “west”, “south”, “east”, and “north”.

    +
    +
    Return type:
    +

    BBoxDict

    +
    +
    +
    + +
    +
    +classmethod from_sequence(seq, crs=None)[source]
    +

    Build from sequence of 4 bounds (west, south, east and north).

    +
    +
    Return type:
    +

    BBoxDict

    +
    +
    +
    + +
    + +
    +
    +openeo.util.load_json_resource(src)[source]
    +

    Helper to load some kind of JSON resource

    +
    +
    Parameters:
    +

    src (Union[str, Path]) – a JSON resource: a raw JSON string, +a path to (local) JSON file, or a URL to a remote JSON resource

    +
    +
    Return type:
    +

    dict

    +
    +
    Returns:
    +

    data structured parsed from JSON

    +
    +
    +
    + +
    +
    +openeo.util.normalize_crs(crs, *, use_pyproj=True)[source]
    +

    Normalize the given value (describing a CRS or Coordinate Reference System) +to an openEO compatible EPSG code (int) or WKT2 CRS string.

    +

    At minimum, the following input values are handled:

    +
      +
    • an integer value (e.g. 4326) is interpreted as an EPSG code

    • +
    • a string that just contains an integer (e.g. "4326") +or with and additional "EPSG:" prefix (e.g. "EPSG:4326") +will also be interpreted as an EPSG value

    • +
    +

    Additional support and behavior depends on the availability of the pyproj library:

    +
      +
    • When available, it will be used for parsing and validation: +everything supported by pyproj.CRS.from_user_input is allowed. +See the pyproj docs for more details.

    • +
    • Otherwise, some best effort validation is done: +EPSG looking integer or string values will be parsed as such as discussed above. +Other strings will be assumed to be WKT2 already. +Other data structures will not be accepted.

    • +
    +
    +
    Parameters:
    +
      +
    • crs (Any) – value that encodes a coordinate reference system, typically just an int (EPSG code) or string (authority string). +If the pyproj library is available, everything supported by it is allowed.

    • +
    • use_pyproj (bool) – whether pyproj should be leveraged at all +(mainly useful for testing the “no pyproj available” code path)

    • +
    +
    +
    Return type:
    +

    Union[None, int, str]

    +
    +
    Returns:
    +

    EPSG code as int, or WKT2 string. Or None if input was empty.

    +
    +
    Raises:
    +

    ValueError – When the given CRS data can not be parsed/converted/normalized.

    +
    +
    +
    + +
    +
    +openeo.util.to_bbox_dict(x, *, crs=None)[source]
    +

    Convert given data or object to a bounding box dictionary +(having keys “west”, “south”, “east”, “north”, and optionally “crs”).

    +

    Supports various input types/formats:

    +
      +
    • list/tuple (assumed to be in west-south-east-north order)

      +
      >>> to_bbox_dict([3, 50, 4, 51])
      +{'west': 3, 'south': 50, 'east': 4, 'north': 51}
      +
      +
      +
    • +
    • dictionary (unnecessary items will be stripped)

      +
      >>> to_bbox_dict({
      +...     "color": "red", "shape": "triangle",
      +...     "west": 1, "south": 2, "east": 3, "north": 4, "crs": "EPSG:4326",
      +... })
      +{'west': 1, 'south': 2, 'east': 3, 'north': 4, 'crs': 'EPSG:4326'}
      +
      +
      +
    • +
    • a shapely geometry

    • +
    +
    +

    New in version 0.10.1.

    +
    +
    +
    Parameters:
    +
      +
    • x (Any) – input data that describes west-south-east-north bounds in some way, e.g. as a dictionary, +a list, a tuple, ashapely geometry, …

    • +
    • crs (Union[int, str, None]) – (optional) CRS field

    • +
    +
    +
    Return type:
    +

    BBoxDict

    +
    +
    Returns:
    +

    dictionary (subclass) with keys “west”, “south”, “east”, “north”, and optionally “crs”.

    +
    +
    +
    + +
    +
    +

    openeo.processes

    +
    +
    +openeo.processes.process(process_id, arguments=None, namespace=None, **kwargs)
    +

    Apply process, using given arguments

    +
    +
    Parameters:
    +
      +
    • process_id (str) – process id of the process.

    • +
    • arguments (dict) – argument dictionary for the process.

    • +
    • namespace (Optional[str]) – process namespace (only necessary to specify for non-predefined or non-user-defined processes)

    • +
    +
    +
    Returns:
    +

    new ProcessBuilder instance

    +
    +
    +
    + +
    +
    +

    Graph building

    +

    Various utilities and helpers to simplify the construction of openEO process graphs.

    +
    +

    Public openEO process graph building utilities

    +
    +
    +
    +class openeo.rest.graph_building.CollectionProperty(name, _builder=None)[source]
    +

    Helper object to easily create simple collection metadata property filters +to be used with Connection.load_collection().

    +
    +

    Note

    +

    This class should not be used directly by end user code. +Use the collection_property() factory instead.

    +
    +
    +

    Warning

    +

    this is an experimental feature, naming might change.

    +
    +
    + +
    +
    +openeo.rest.graph_building.collection_property(name)[source]
    +

    Helper to easily create simple collection metadata property filters +to be used with Connection.load_collection().

    +

    Usage example:

    +
    from openeo import collection_property
    +...
    +
    +connection.load_collection(
    +    ...
    +    properties=[
    +        collection_property("eo:cloud_cover") <= 75,
    +        collection_property("platform") == "Sentinel-2B",
    +    ]
    +)
    +
    +
    +
    +

    Warning

    +

    this is an experimental feature, naming might change.

    +
    +
    +

    New in version 0.26.0.

    +
    +
    +
    Parameters:
    +

    name (str) – name of the collection property to filter on

    +
    +
    Return type:
    +

    CollectionProperty

    +
    +
    Returns:
    +

    an object that supports operators like <=, == to easily build simple property filters.

    +
    +
    +
    + +
    +

    Internal openEO process graph building utilities

    +

    Internal functionality for abstracting, building, manipulating and processing openEO process graphs.

    +
    +
    +
    +class openeo.internal.graph_building.FlatGraphableMixin[source]
    +

    Mixin for classes that can be exported/converted to +a “flat graph” representation of an openEO process graph.

    +
    +
    +print_json(*, file=None, indent=2, separators=None, end='\\n')[source]
    +

    Print interoperable JSON representation of the process graph.

    +

    See DataCube.to_json() to get the JSON representation as a string +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • file – file-like object (stream) to print to (current sys.stdout by default). +Or a path (string or pathlib.Path) to a file to write to.

    • +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    • end (str) – additional string to be printed at the end (newline by default).

    • +
    +
    +
    +
    +

    New in version 0.12.0.

    +
    +
    +

    New in version 0.23.0: added the end argument.

    +
    +
    + +
    +
    +to_json(*, indent=2, separators=None)[source]
    +

    Get interoperable JSON representation of the process graph.

    +

    See DataCube.print_json() to directly print the JSON representation +and Export a process graph for more usage information.

    +

    Also see json.dumps docs for more information on the JSON formatting options.

    +
    +
    Parameters:
    +
      +
    • indent (Optional[int]) – JSON indentation level.

    • +
    • separators (Optional[Tuple[str, str]]) – (optional) tuple of item/key separators.

    • +
    +
    +
    Return type:
    +

    str

    +
    +
    Returns:
    +

    JSON string

    +
    +
    +
    + +
    + +
    +
    +class openeo.internal.graph_building.PGNode(process_id, arguments=None, namespace=None, **kwargs)[source]
    +

    A process node in a process graph: has at least a process_id and arguments.

    +

    Note that a full openEO “process graph” is essentially a directed acyclic graph of nodes +pointing to each other. A full process graph is practically equivalent with its “result” node, +as it points (directly or indirectly) to all the other nodes it depends on.

    +
    +

    Warning

    +

    This class is an implementation detail meant for internal use. +It is not recommended for general use in normal user code. +Instead, use process graph abstraction builders like +Connection.load_collection(), +Connection.datacube_from_process(), +Connection.datacube_from_flat_graph(), +Connection.datacube_from_json(), +Connection.load_ml_model(), +openeo.processes.process(),

    +
    +
    +
    +flat_graph()[source]
    +

    Get the process graph in internal flat dict representation.

    +
    +
    Return type:
    +

    Dict[str, dict]

    +
    +
    +
    + +
    +
    +static from_flat_graph(flat_graph, parameters=None)[source]
    +

    Unflatten a given flat dict representation of a process graph and return result node.

    +
    +
    Return type:
    +

    PGNode

    +
    +
    +
    + +
    +
    +to_dict()[source]
    +

    Convert process graph to a nested dictionary structure. +Uses deep copy style: nodes that are reused in graph will be deduplicated

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +static to_process_graph_argument(value)[source]
    +

    Normalize given argument properly to a “process_graph” argument +to be used as reducer/subprocess for processes like +reduce_dimension, aggregate_spatial, apply, merge_cubes, resample_cube_temporal

    +
    +
    Return type:
    +

    dict

    +
    +
    +
    + +
    +
    +update_arguments(**kwargs)[source]
    +

    Add/Update arguments of the process node.

    +
    +

    New in version 0.10.1.

    +
    +
    + +
    + +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/auth.html b/auth.html new file mode 100644 index 000000000..a716e7eb8 --- /dev/null +++ b/auth.html @@ -0,0 +1,666 @@ + + + + + + + + Authentication and Account Management — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Authentication and Account Management

    +

    While a couple of openEO operations can be done +anonymously, most of the interesting parts +of the API require you to identify as a registered +user. +The openEO API specifies two ways to authenticate +as a user:

    +
      +
    • OpenID Connect (recommended, but not always straightforward to use)

    • +
    • Basic HTTP Authentication (not recommended, but practically easier in some situations)

    • +
    +

    To illustrate how to authenticate with the openEO Python Client Library, +we start form a back-end connection:

    +
    import openeo
    +
    +connection = openeo.connect("https://openeo.example.com")
    +
    +
    +
    +

    Basic HTTP Auth

    +

    Let’s start with the easiest authentication method, +based on the Basic HTTP authentication scheme. +It is however not recommended for various reasons, +such as its limited security measures. +For example, if you are connecting to a back-end with a http:// URL +instead of a https:// one, you should certainly not use basic HTTP auth.

    +

    With these security related caveats out of the way, you authenticate +using your username and password like this:

    +
    connection.authenticate_basic("john", "j0hn123")
    +
    +
    +

    Subsequent usage of the connection object connection will +use authenticated calls. +For example, show information about the authenticated user:

    +
    >>> connection.describe_account()
    +{'user_id': 'john'}
    +
    +
    +
    +
    +

    OpenID Connect Based Authentication

    +

    OpenID Connect (often abbreviated “OIDC”) is an identity layer on top of the OAuth 2.0 protocol. +An in-depth discussion of the whole architecture would lead us too far here, +but some central OpenID Connect concepts are quite useful to understand +in the context of working with openEO:

    +
      +
    • There is decoupling between:

      +
        +
      • the OpenID Connect identity provider +which handles the authentication/authorization and stores user information +(e.g. an organization Google, Github, Microsoft, your academic/research institution, …)

      • +
      • the openEO back-end which manages earth observation collections +and executes your algorithms

      • +
      +

      Instead of managing the authentication procedure itself, +an openEO back-end forwards a user to the relevant OpenID Connect provider to authenticate +and request access to basic profile information (e.g. email address). +On return, when the user allowed this access, +the openEO back-end receives the profile information and uses this to identify the user.

      +

      Note that with this approach, the back-end does not have to +take care of all the security and privacy challenges +of properly handling user registration, passwords/authentication, etc. +Also, it allows the user to securely reuse an existing account +registered with an established organisation, instead of having +to register yet another account with some web service.

      +
    • +
    • Your openEO script or application acts as +a so called OpenID Connect client, with an associated client id. +In most cases, a default client (id) defined by the openEO back-end will be used automatically. +For some applications a custom client might be necessary, +but this is out of scope of this documentation.

    • +
    • OpenID Connect authentication can be done with different kind of “flows” (also called “grants”) +and picking the right flow depends on your specific use case. +The most common OIDC flows using the openEO Python Client Library are:

      + +
    • +
    +

    OpenID Connect is clearly more complex than Basic HTTP Auth. +In the sections below we will discuss the practical details of each flow.

    +
    +

    General options

    +
      +
    • A back-end might support multiple OpenID Connect providers. +The openEO Python Client Library will pick the first one by default, +but another another provider can specified explicity with the provider_id argument, e.g.:

      +
      connection.authenticate_oidc_device(
      +    provider_id="gl",
      +    ...
      +)
      +
      +
      +
    • +
    +
    +
    +
    +

    OIDC Authentication: Device Code Flow

    +

    The device code flow (also called device authorization grant) +is an interactive flow that requires a web browser for the authentication +with the OpenID Connect provider. +The nice things is that the browser doesn’t have to run on +the same system or network as where you run your application, +you could even use a browser on your mobile phone.

    +

    Use authenticate_oidc_device() to initiate the flow:

    +
    connection.authenticate_oidc_device()
    +
    +
    +

    This will print a message like this:

    +
    Visit https://oidc.example.net/device
    +and enter user code 'DTNY-KLNX' to authenticate.
    +
    +
    +

    Some OpenID Connect Providers use a slightly longer URL that already includes +the user code, and then you don’t need to enter the user code in one of the next steps:

    +
    Visit https://oidc.example.net/device?user_code=DTNY-KLNX to authenticate.
    +
    +
    +

    You should now visit this URL in your browser of choice. +Usually, it is intentionally a short URL to make it feasible to type it +instead of copy-pasting it (e.g. on another device).

    +

    Authenticate with the OpenID Connect provider and, if requested, enter the user code +shown in the message. +When the URL already contains the user code, the page won’t ask for this code.

    +

    Meanwhile, the openEO Python Client Library is actively polling the OpenID Connect +provider and when you successfully complete the authentication, +it will receive the necessary tokens for authenticated communication +with the back-end and print:

    +
    Authorized successfully.
    +
    +
    +

    In case of authentication failure, the openEO Python Client Library +will stop polling at some point and raise an exception.

    +
    +
    +

    OIDC Authentication: Refresh Token Flow

    +

    When OpenID Connect authentication completes successfully, +the openID Python library receives an access token +to be used when doing authenticated calls to the back-end. +The access token usually has a short lifetime to reduce +the security risk when it would be stolen or intercepted. +The openID Python library also receives a refresh token +that can be used, through the Refresh Token flow, +to easily request a new access token, +without having to re-authenticate, +which makes it useful for non-interactive uses cases.

    +

    However, as it needs an existing refresh token, +the Refresh Token Flow requires +first to authenticate with one of the other flows +(but in practice this should not be done very often +because refresh tokens usually have a relatively long lifetime). +When doing the initial authentication, +you have to explicitly enable storage of the refresh token, +through the store_refresh_token argument, e.g.:

    +
    connection.authenticate_oidc_device(
    +    ...
    +    store_refresh_token=True
    +
    +
    +

    The refresh token will be stored in file in private file +in your home directory and will be used automatically +when authenticating with the Refresh Token Flow, +using authenticate_oidc_refresh_token():

    +
    connection.authenticate_oidc_refresh_token(
    +    client_secret=client_secret,
    +    client_id=client_id
    +)
    +
    +
    +

    You can also bootstrap the refresh token file +as described in OpenID Connect refresh tokens

    +
    +
    +

    OIDC Authentication: Client Credentials Flow

    +

    The OIDC Client Credentials flow does not involve interactive authentication (e.g. through a web browser), +which makes it a useful option for non-interactive use cases.

    +
    +

    Important

    +

    This method requires a custom OIDC client id and client secret. +It is out of scope of this general documentation to explain +how to obtain these as it depends on the openEO back-end you are using +and the OIDC provider that is in play.

    +

    Also, your openEO back-end might not allow it, because technically +you are authenticating a client instead of a user.

    +

    Consult the support of the openEO back-end you want to use for more information.

    +
    +

    In its most simple form, given your client id and secret, +you can authenticate with +authenticate_oidc_client_credentials() +as follows:

    +
    connection.authenticate_oidc_client_credentials(
    +    client_id=client_id,
    +    client_secret=client_secret,
    +)
    +
    +
    +

    You might also have to pass a custom provider id (argument provider_id) +if your OIDC client is associated with an OIDC provider that is different from the default provider.

    +
    +

    Caution

    +

    Make sure to keep the client secret a secret and avoid putting it directly in your source code +or, worse, committing it to a version control system. +Instead, fetch the secret from a protected source (e.g. a protected file, a database for sensitive data, …) +or from environment variables.

    +
    +
    +

    OIDC Client Credentials Using Environment Variables

    +

    Since version 0.18.0, the openEO Python Client Library has built-in support to get the client id, +secret (and provider id) from environment variables +OPENEO_AUTH_CLIENT_ID, OPENEO_AUTH_CLIENT_SECRET and OPENEO_AUTH_PROVIDER_ID respectively. +Just call authenticate_oidc_client_credentials() +without arguments.

    +

    Usage example assuming a Linux (Bash) shell context:

    +
    $ export OPENEO_AUTH_CLIENT_ID="my-client-id"
    +$ export OPENEO_AUTH_CLIENT_SECRET="Cl13n7S3cr3t!?123"
    +$ export OPENEO_AUTH_PROVIDER_ID="oidcprovider"
    +$ python
    +>>> import openeo
    +>>> connection = openeo.connect("openeo.example.com")
    +>>> connection.authenticate_oidc_client_credentials()
    +<Connection to 'https://openeo.example.com/openeo/1.1/' with OidcBearerAuth>
    +
    +
    +
    +
    +
    +

    OIDC Authentication: Dynamic Method Selection

    +

    The sections above discuss various authentication options, like +the device code flow, +refresh tokens and +client credentials flow, +but often you want to dynamically switch between these depending on the situation: +e.g. use a refresh token if you have an active one, and fallback on the device code flow otherwise. +Or you want to be able to run the same code in an interactive environment and automated in an unattended manner, +without having to switch authentication methods explicitly in code.

    +

    That is what Connection.authenticate_oidc() is for:

    +
    connection.authenticate_oidc() # is all you need
    +
    +
    +

    In a basic situation (without any particular environment variables set as discussed further), +this method will first try to authenticate with refresh tokens (if any) +and fall back on the device code flow otherwise. +Ideally, when valid refresh tokens are available, this works without interaction, +but occasionally, when the refresh tokens expire, one has to do the interactive device code flow.

    +

    Since version 0.18.0, the openEO Python Client Library also allows to trigger the +client credentials flow +from authenticate_oidc() +by setting environment variable OPENEO_AUTH_METHOD +and the other client credentials environment variables. +For example:

    +
    $ export OPENEO_AUTH_METHOD="client_credentials"
    +$ export OPENEO_AUTH_CLIENT_ID="my-client-id"
    +$ export OPENEO_AUTH_CLIENT_SECRET="Cl13n7S3cr3t!?123"
    +$ export OPENEO_AUTH_PROVIDER_ID="oidcprovider"
    +$ python
    +>>> import openeo
    +>>> connection = openeo.connect("openeo.example.com")
    +>>> connection.authenticate_oidc()
    +<Connection to 'https://openeo.example.com/openeo/1.1/' with OidcBearerAuth>
    +
    +
    +
    +
    +

    Auth config files and openeo-auth helper tool

    +

    The openEO Python Client Library provides some features and tools +that ease the usability and security challenges +that come with authentication (especially in case of OpenID Connect).

    +

    Note that the code examples above contain quite some passwords and other secrets +that should be kept safe from prying eyes. +It is bad practice to define these kind of secrets directly +in your scripts and source code because that makes it quite hard +to responsibly share or reuse your code. +Even worse is storing these secrets in your version control system, +where it might be near impossible to remove them again. +A better solution is to keep secrets in separate configuration or cache files, +outside of your normal source code tree +(to avoid committing them accidentally).

    +

    The openEO Python Client Library supports config files to store: +user names, passwords, client IDs, client secrets, etc, +so you don’t have to specify them always in your scripts and applications.

    +

    The openEO Python Client Library (when installed properly) +provides a command line tool openeo-auth to bootstrap and manage +these configs and secrets. +It is a command line tool that provides various “subcommands” +and has built-in help:

    +
    $ openeo-auth -h
    +usage: openeo-auth [-h] [--verbose]
    +                   {paths,config-dump,token-dump,add-basic,add-oidc,oidc-auth}
    +                   ...
    +
    +Tool to manage openEO related authentication and configuration.
    +
    +optional arguments:
    +  -h, --help            show this help message and exit
    +
    +Subcommands:
    +  {paths,config-dump,token-dump,add-basic,add-oidc,oidc-auth}
    +    paths               Show paths to config/token files.
    +    config-dump         Dump config file.
    +...
    +
    +
    +

    For example, to see the expected paths of the config files:

    +
    $ openeo-auth paths
    +openEO auth config: /home/john/.config/openeo-python-client/auth-config.json (perms: 0o600, size: 1414B)
    +openEO OpenID Connect refresh token store: /home/john/.local/share/openeo-python-client/refresh-tokens.json (perms: 0o600, size: 846B)
    +
    +
    +

    With the config-dump and token-dump subcommands you can dump +the current configuration and stored refresh tokens, e.g.:

    +
    $ openeo-auth config-dump
    +### /home/john/.config/openeo-python-client/auth-config.json ###############
    +{
    +  "backends": {
    +    "https://openeo.example.com": {
    +      "basic": {
    +        "username": "john",
    +        "password": "<redacted>",
    +        "date": "2020-07-24T13:40:50Z"
    +...
    +
    +
    +

    The sensitive information (like passwords) are redacted by default.

    +
    +

    Basic HTTP Auth config

    +

    With the add-basic subcommand you can add Basic HTTP Auth credentials +for a given back-end to the config. +It will interactively ask for username and password and +try if these credentials work:

    +
    $ openeo-auth add-basic https://openeo.example.com/
    +Enter username and press enter: john
    +Enter password and press enter:
    +Trying to authenticate with 'https://openeo.example.com'
    +Successfully authenticated 'john'
    +Saved credentials to '/home/john/.config/openeo-python-client/auth-config.json'
    +
    +
    +

    Now you can authenticate in your application without having to +specify username and password explicitly:

    +
    connection.authenticate_basic()
    +
    +
    +
    +
    +

    OpenID Connect configs

    +

    Likewise, with the add-oidc subcommand you can add OpenID Connect +credentials to the config:

    +
    $ openeo-auth add-oidc https://openeo.example.com/
    +Using provider ID 'example' (issuer 'https://oidc.example.net/')
    +Enter client_id and press enter: client-d7393fba
    +Enter client_secret and press enter:
    +Saved client information to '/home/john/.config/openeo-python-client/auth-config.json'
    +
    +
    +

    Now you can user OpenID Connect based authentication in your application +without having to specify the client ID and client secret explicitly, +like one of these calls:

    +
    connection.authenticate_oidc_authorization_code()
    +connection.authenticate_oidc_client_credentials()
    +connection.authenticate_oidc_resource_owner_password_credentials(username=username, password=password)
    +connection.authenticate_oidc_device()
    +connection.authenticate_oidc_refresh_token()
    +
    +
    +

    Note that you still have to add additional options as required, like +provider_id, server_address, store_refresh_token, etc.

    +
    +

    OpenID Connect refresh tokens

    +

    There is also a oidc-auth subcommand to execute an OpenID Connect +authentication flow and store the resulting refresh token. +This is intended to for bootstrapping the environment or system +on which you want to run openEO scripts or applications that use +the Refresh Token Flow for authentication. +For example:

    +
    $ openeo-auth oidc-auth https://openeo.example.com
    +Using config '/home/john/.config/openeo-python-client/auth-config.json'.
    +Starting OpenID Connect device flow.
    +To authenticate: visit https://oidc.example.net/device and enter the user code 'Q7ZNsy'.
    +Authorized successfully.
    +The OpenID Connect device flow was successful.
    +Stored refresh token in '/home/john/.local/share/openeo-python-client/refresh-tokens.json'
    +
    +
    +
    +
    +
    +
    +

    Default openEO back-end URL and auto-authentication

    +
    +

    New in version 0.10.0.

    +
    +

    If you often use the same openEO back-end URL and authentication scheme, +it can be handy to put these in a configuration file as discussed at Configuration files.

    +
    +

    Note

    +

    Note that these general configuration files are different +from the auth config files discussed earlier under Auth config files and openeo-auth helper tool. +The latter are for storing authentication related secrets +and are mostly managed automatically (e.g. by the oidc-auth helper tool). +The former are not for storing secrets and are usually edited manually.

    +
    +

    For example, to define a default back-end and automatically use OpenID Connect authentication +add these configuration options to the desired configuration file:

    +
    [Connection]
    +default_backend = openeo.cloud
    +default_backend.auto_authenticate = oidc
    +
    +
    +

    Getting an authenticated connection is now as simple as:

    +
    >>> import openeo
    +>>> connection = openeo.connect()
    +Loaded openEO client config from openeo-client-config.ini
    +Using default back-end URL 'openeo.cloud' (from config)
    +Doing auto-authentication 'oidc' (from config)
    +Authenticated using refresh token.
    +
    +
    +
    +
    +

    Authentication for long-running applications and non-interactive contexts

    +

    With OpenID Connect authentication, the access token +(which is used in the authentication headers) +is typically short-lived (e.g. couple of minutes or hours). +This practically means that an authenticated connection could expire and become unusable +before a long-running script or application finishes its whole workflow. +Luckily, OpenID Connect also includes usage of refresh tokens, +which have a much longer expiry and allow request a new access token +to re-authenticate the connection. +Since version 0.10.1, te openEO Python Client Library will automatically +attempt to re-authenticate a connection when access token expiry is detected +and valid refresh tokens are available.

    +

    Likewise, refresh tokens can also be used for authentication in cases +where a script or application is run automatically in the background on regular basis (daily, weekly, …). +If there is a non-expired refresh token available, the script can authenticate +without user interaction.

    +
    +

    Guidelines and tips

    +

    Some guidelines to get long-term and non-interactive authentication working for your use case:

    +
      +
    • If you run a workflow periodically, but the interval between runs +is larger than the expiry time of the refresh token +(e.g. a monthly job, while the refresh token expires after, say, 10 days), +you could consider setting up a custom OIDC client with better suited +refresh token timeout. +The practical details of this heavily depend on the OIDC Identity Provider +in play and are out of scope of this discussion.

    • +
    • Obtaining a refresh token requires manual/interactive authentication, +but once it is stored on the necessary machine(s) +in the refresh token store as discussed in Auth config files and openeo-auth helper tool, +no further manual interaction should be necessary +during the lifetime of the refresh token. +To do so, use one of the following methods:

      +
        +
      • Use the openeo-auth oidc-auth cli tool, for example to authenticate +for openeo back-end openeo.example.com:

        +
        $ openeo-auth oidc-auth openeo.example.com
        +...
        +Stored refresh token in '/home/john/.local/share/openeo-python-client/refresh-tokens.json'
        +
        +
        +
      • +
      • Use a Python snippet to authenticate and store the refresh token:

        +
        import openeo
        +connection = openeo.connect("openeo.example.com")
        +connection.authenticate_oidc_device(store_refresh_token=True)
        +
        +
        +
      • +
      +

      To verify that (and where) the refresh token is stored, use openeo-auth token-dump:

      +
      $ openeo-auth token-dump
      +### /home/john/.local/share/openeo-python-client/refresh-tokens.json #######
      +{
      +  "https://oidc.example.net": {
      +    "default-client": {
      +      "date": "2022-05-11T13:13:20Z",
      +      "refresh_token": "<redacted>"
      +    },
      +...
      +
      +
      +
    • +
    +
    +
    +
    +

    Best Practices and Troubleshooting Tips

    +
    +

    Warning

    +

    Handle (OIDC) access and refresh tokens like secret, personal passwords. +Never share your access or refresh tokens with other people, +publicly, or for user support reasons.

    +
    +
    +

    Clear the refresh token file

    +

    When you have authentication or permission issues and you suspect +that your (locally cached) refresh tokens are the culprit: +remove your refresh token file in one of the following ways:

    +
      +
    • Locate the file with the openeo-auth command line tool:

      +
      $ openeo-auth paths
      +...
      +openEO OpenID Connect refresh token store: /home/john/.local/share/openeo-python-client/refresh-tokens.json (perms: 0o600, size: 846B)
      +
      +
      +

      and remove it. +Or, if you know what you are doing: remove the desired section from this JSON file.

      +
    • +
    • Remove it directly with the token-clear subcommand of the openeo-auth command line tool:

      +
      $ openeo-auth token-clear
      +
      +
      +
    • +
    • Remove it with this Python snippet:

      +
      from openeo.rest.auth.config import RefreshTokenStore
      +RefreshTokenStore().remove()
      +
      +
      +
    • +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/basics.html b/basics.html new file mode 100644 index 000000000..b73fd7452 --- /dev/null +++ b/basics.html @@ -0,0 +1,518 @@ + + + + + + + + Getting Started — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Getting Started

    +
    +

    Connect to an openEO back-end

    +

    First, establish a connection to an openEO back-end, using its connection URL. +For example the VITO/Terrascope backend:

    +
    import openeo
    +
    +connection = openeo.connect("openeo.vito.be")
    +
    +
    +

    The resulting Connection object is your central gateway to

    +
      +
    • list data collections, available processes, file formats and other capabilities of the back-end

    • +
    • start building your openEO algorithm from the desired data on the back-end

    • +
    • execute and monitor (batch) jobs on the back-end

    • +
    • etc.

    • +
    +
    +

    See also

    +

    Use the openEO Hub to explore different back-end options +and their capabilities in a web-based way.

    +
    +
    +
    +

    Collection discovery

    +

    The Earth observation data (the input of your openEO jobs) is organised in +so-called collections, +e.g. fundamental satellite collections like “Sentinel 1” or “Sentinel 2”, +or preprocessed collections like “NDVI”.

    +

    You can programmatically list the collections that are available on a back-end +and their metadata using methods on the connection object we just created +(like list_collection_ids() +or describe_collection()

    +
    >>> # Get all collection ids
    +>>> connection.list_collection_ids()
    +['SENTINEL1_GRD', 'SENTINEL2_L2A', ...
    +
    +>>> # Get metadata of a single collection
    +>>> connection.describe_collection("SENTINEL2_L2A")
    +{'id': 'SENTINEL2_L2A', 'title': 'Sentinel-2 top of canopy ...', 'stac_version': '0.9.0', ...
    +
    +
    +

    Congrats, you now just did your first real openEO queries to the openEO back-end +using the openEO Python client library.

    +
    +

    Tip

    +

    The openEO Python client library comes with Jupyter (notebook) integration in a couple of places. +For example, put connection.describe_collection("SENTINEL2_L2A") (without print()) +as last statement in a notebook cell +and you’ll get a nice graphical rendering of the collection metadata.

    +
    +
    +

    See also

    +

    Find out more about data discovery, loading and filtering at Finding and loading data.

    +
    +
    +
    +

    Authentication

    +

    In the code snippets above we did not need to log in as a user +since we just queried publicly available back-end information. +However, to run non-trivial processing queries one has to authenticate +so that permissions, resource usage, etc. can be managed properly.

    +

    To handle authentication, openEO leverages OpenID Connect (OIDC). +It offers some interesting features (e.g. a user can securely reuse an existing account), +but is a fairly complex topic, discussed in more depth at Authentication and Account Management.

    +

    The openEO Python client library tries to make authentication as streamlined as possible. +In most cases for example, the following snippet is enough to obtain an authenticated connection:

    +
    import openeo
    +
    +connection = openeo.connect("openeo.vito.be").authenticate_oidc()
    +
    +
    +

    This statement will automatically reuse a previously authenticated session, when available. +Otherwise, e.g. the first time you do this, some user interaction is required +and it will print a web link and a short user code, for example:

    +
    To authenticate: visit https://aai.egi.eu/auth/realms/egi/device and enter the user code 'SLUO-BMUD'.
    +
    +
    +

    Visit this web page in a browser, log in there with an existing account and enter the user code. +If everything goes well, the connection object in the script will be authenticated +and the back-end will be able to identify you in subsequent requests.

    +
    +
    +

    Example use case: EVI map and timeseries

    +

    A common task in earth observation is to apply a formula to a number of spectral bands +in order to compute an ‘index’, such as NDVI, NDWI, EVI, … +In this tutorial we’ll go through a couple of steps to extract +EVI (enhanced vegetation index) values and timeseries, +and discuss some openEO concepts along the way.

    +
    +
    +

    Loading an initial data cube

    +

    For calculating the EVI, we need the reflectance of the +red, blue and (near) infrared spectral components. +These spectral bands are part of the well-known Sentinel-2 data set +and is available on the current back-end under collection id SENTINEL2_L2A. +We load an initial small spatio-temporal slice (a data cube) as follows:

    +
    sentinel2_cube = connection.load_collection(
    +    "SENTINEL2_L2A",
    +    spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19},
    +    temporal_extent = ["2021-02-01", "2021-04-30"],
    +    bands=["B02", "B04", "B08"]
    +)
    +
    +
    +

    Note how we specify a the region of interest, a time range and a set of bands to load.

    +
    +

    Important

    +

    By filtering as early as possible (directly in load_collection() in this case), +we make sure the back-end only loads the data we are interested in +for better performance and keeping the processing costs low.

    +
    +
    +

    See also

    +

    See the chapter Finding and loading data for more details on data discovery, +general data loading (Loading a data cube from a collection) and filtering +(e.g. temporal-extent-handling).

    +
    +

    The load_collection() method on the connection +object created a DataCube object (variable sentinel2_cube). +This DataCube class of the openEO Python Client Library +provides loads of methods corresponding to various openEO processes, +e.g. for masking, filtering, aggregation, spectral index calculation, data fusion, etc. +In the next steps we will illustrate a couple of these.

    +
    +

    Important

    +

    It is important to highlight that we did not load any real EO data yet. +Instead we just created an abstract client-side reference, +encapsulating the collection id, the spatial extent, the temporal extent, etc. +The actual data loading will only happen at the back-end +once we explicitly trigger the execution of the data processing pipeline we are building.

    +
    +
    +
    +

    Band math

    +

    From this data cube, we can now select the individual bands +with the DataCube.band() method +and rescale the digital number values to physical reflectances:

    +
    blue = sentinel2_cube.band("B02") * 0.0001
    +red = sentinel2_cube.band("B04") * 0.0001
    +nir = sentinel2_cube.band("B08") * 0.0001
    +
    +
    +

    We now want to compute the enhanced vegetation index +and can do that directly with these band variables:

    +
    evi_cube = 2.5 * (nir - red) / (nir + 6.0 * red - 7.5 * blue + 1.0)
    +
    +
    +
    +

    Important

    +

    As noted before: while this looks like an actual calculation, +there is no real data processing going on here. +The evi_cube object at this point is just an abstract representation +of our algorithm under construction. +The mathematical operators we used here are syntactic sugar +for expressing this part of the algorithm in a very compact way.

    +

    As an illustration of this, let’s have peek at the JSON representation +of our algorithm so far, the so-called openEO process graph:

    +
    >>> print(evi_cube.to_json(indent=None))
    +{"process_graph": {"loadcollection1": {"process_id": "load_collection", ...
    +... "id": "SENTINEL2_L2A", "spatial_extent": {"west": 5.15, "south": ...
    +... "multiply1": { ... "y": 0.0001}}, ...
    +... "multiply3": { ... {"x": 2.5, "y": {"from_node": "subtract1"}}} ...
    +...
    +
    +
    +

    Note how the load_collection arguments, rescaling and EVI calculation aspects +can be deciphered from this. +Rest assured, as user you normally you don’t have to worry too much +about these process graph details, +the openEO Python Client library handles this behind the scenes for you.

    +
    +
    +
    +

    Download (synchronously)

    +

    Let’s download this as a GeoTIFF file. +Because GeoTIFF does not support a temporal dimension, +we first eliminate it by taking the temporal maximum value for each pixel:

    +
    evi_composite = evi_cube.max_time()
    +
    +
    +
    +

    Note

    +

    This max_time() is not an official openEO process +but one of the many convenience methods in the openEO Python Client Library +to simplify common processing patterns. +It implements a reduce operation along the temporal dimension +with a max reducer/aggregator.

    +
    +

    Now we can download this to a local file:

    +
    evi_composite.download("evi-composite.tiff")
    +
    +
    +

    This download command triggers the actual processing on the back-end: +it sends the process graph to the back-end and waits for the result. +It is a synchronous operation (the download() call +blocks until the result is fully downloaded) and because we work on a small spatio-temporal extent, +this should only take a couple of seconds.

    +

    If we inspect the downloaded image, we see that the maximum EVI value is heavily impacted +by cloud related artefacts, which makes the result barely usable. +In the next steps we will address cloud masking.

    +_images/evi-composite.png +
    +
    +

    Batch Jobs (asynchronous execution)

    +

    Synchronous downloads are handy for quick experimentation on small data cubes, +but if you start processing larger data cubes, you can easily +hit computation time limits or other constraints. +For these larger tasks, it is recommended to work with batch jobs, +which allow you to work asynchronously: +after you start your job, you can disconnect (stop your script or even close your computer) +and then minutes/hours later you can reconnect to check the batch job status and download results. +The openEO Python Client Library also provides helpers to keep track of a running batch job +and show a progress report.

    +
    +

    See also

    +

    See Batch Jobs for more details.

    +
    +
    +
    +

    Applying a cloud mask

    +

    As mentioned above, we need to filter out cloud pixels to make the result more usable. +It is very common for earth observation data to have separate masking layers that for instance indicate +whether a pixel is covered by a (type of) cloud or not. +For Sentinel-2, one such layer is the “scene classification” layer generated by the Sen2Cor algorithm. +In this example, we will use this layer to mask out unwanted data.

    +

    First, we load a new SENTINEL2_L2A based data cube with this specific SCL band as single band:

    +
    s2_scl = connection.load_collection(
    +    "SENTINEL2_L2A",
    +    spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19},
    +    temporal_extent = ["2021-02-01", "2021-04-30"],
    +    bands=["SCL"]
    +)
    +
    +
    +

    Now we can use the compact “band math” feature again to build a +binary mask with a simple comparison operation:

    +
    # Select the "SCL" band from the data cube
    +scl_band = s2_scl.band("SCL")
    +# Build mask to mask out everything but class 4 (vegetation)
    +mask = (scl_band != 4)
    +
    +
    +

    Before we can apply this mask to the EVI cube we have to resample it, +as the “SCL” layer has a “ground sample distance” of 20 meter, +while it is 10 meter for the “B02”, “B04” and “B08” bands. +We can easily do the resampling by referring directly to the EVI cube.

    +
    mask_resampled = mask.resample_cube_spatial(evi_cube)
    +
    +# Apply the mask to the `evi_cube`
    +evi_cube_masked = evi_cube.mask(mask_resampled)
    +
    +
    +

    We can now download this as a GeoTIFF, again after taking the temporal maximum:

    +
    evi_cube_masked.max_time().download("evi-masked-composite.tiff")
    +
    +
    +

    Now, the EVI map is a lot more valuable, as the non-vegetation locations +and observations are filtered out:

    +_images/evi-masked-composite.png +
    +
    +

    Aggregated EVI timeseries

    +

    A common type of analysis is aggregating pixel values over one or more regions of interest +(also known as “zonal statistics) and tracking this aggregation over a period of time as a timeseries. +Let’s extract the EVI timeseries for these two regions:

    +
    features = {"type": "FeatureCollection", "features": [
    +    {
    +        "type": "Feature", "properties": {},
    +        "geometry": {"type": "Polygon", "coordinates": [[
    +            [5.1417, 51.1785], [5.1414, 51.1772], [5.1444, 51.1768], [5.1443, 51.179], [5.1417, 51.1785]
    +        ]]}
    +    },
    +    {
    +        "type": "Feature", "properties": {},
    +        "geometry": {"type": "Polygon", "coordinates": [[
    +            [5.156, 51.1892], [5.155, 51.1855], [5.163, 51.1855], [5.163, 51.1891], [5.156, 51.1892]
    +        ]]}
    +    }
    +]}
    +
    +
    +
    +

    Note

    +

    To have a self-containing example we define the geometries here as an inline GeoJSON-style dictionary. +In a real use case, your geometry will probably come from a local file or remote URL. +The openEO Python Client Library supports alternative ways of specifying the geometry +in methods like aggregate_spatial(), e.g. +as Shapely geometry objects.

    +
    +

    Building on the experience from previous sections, we first build a masked EVI cube +(covering a longer time window than before):

    +
    # Load raw collection data
    +sentinel2_cube = connection.load_collection(
    +    "SENTINEL2_L2A",
    +    spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19},
    +    temporal_extent = ["2020-01-01", "2021-12-31"],
    +    bands=["B02", "B04", "B08", "SCL"],
    +)
    +
    +# Extract spectral bands and calculate EVI with the "band math" feature
    +blue = sentinel2_cube.band("B02") * 0.0001
    +red = sentinel2_cube.band("B04") * 0.0001
    +nir = sentinel2_cube.band("B08") * 0.0001
    +evi = 2.5 * (nir - red) / (nir + 6.0 * red - 7.5 * blue + 1.0)
    +
    +# Use the scene classification layer to mask out non-vegetation pixels
    +scl = sentinel2_cube.band("SCL")
    +evi_masked = evi.mask(scl != 4)
    +
    +
    +

    Now we use the aggregate_spatial() method +to do spatial aggregation over the geometries we defined earlier. +Note how we can specify the aggregation function "mean" as a simple string for the reducer argument.

    +
    evi_aggregation = evi_masked.aggregate_spatial(
    +    geometries=features,
    +    reducer="mean",
    +)
    +
    +
    +

    If we download this, we get the timeseries encoded as a JSON structure, other useful formats are CSV and netCDF.

    +
    evi_aggregation.download("evi-aggregation.json")
    +
    +
    +
    +

    Warning

    +

    Technically, the output of the openEO process aggregate_spatial +is a so-called “vector cube”. +At the time of this writing, the specification of this openEO concept +is not fully fleshed out yet in the openEO API. +openEO back-ends and clients to provide best-effort support for it, +but bear in mind that some details are subject to change.

    +
    +

    The openEO Python Client Library provides helper functions +to convert the downloaded JSON data to a pandas dataframe, +which we massage a bit more:

    +
    import json
    +import pandas as pd
    +from openeo.rest.conversions import timeseries_json_to_pandas
    +
    +import json
    +with open("evi-aggregation.json") as f:
    +    data = json.load(f)
    +
    +df = timeseries_json_to_pandas(data)
    +df.index = pd.to_datetime(df.index)
    +df = df.dropna()
    +df.columns = ("Field A", "Field B")
    +
    +
    +

    This gives us finally our EVI timeseries dataframe:

    +
    >>> df
    +                           Field A   Field B
    +date
    +2020-01-06 00:00:00+00:00  0.522499  0.300250
    +2020-01-16 00:00:00+00:00  0.529591  0.288079
    +2020-01-18 00:00:00+00:00  0.633011  0.327598
    +...                             ...       ...
    +
    +
    +_images/evi-timeseries.png +
    +
    +

    Computing multiple statistics

    +

    The same method also allows the computation of multiple statistics at once. This does rely +on ‘callbacks’ to construct a result with multiple statistics. +The use of such more complex processes is further explained in Processes with child “callbacks”.

    +
    from openeo.processes import array_create, mean, sd, median, count
    +
    +evi_aggregation = evi_masked.aggregate_spatial(
    +    geometries=features,
    +    reducer=lambda x: array_create([mean(x), sd(x), median(x), count(x)]),
    +)
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/batch_jobs.html b/batch_jobs.html new file mode 100644 index 000000000..24769a736 --- /dev/null +++ b/batch_jobs.html @@ -0,0 +1,444 @@ + + + + + + + + Batch Jobs — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Batch Jobs

    +

    Most of the simple, basic openEO usage examples show synchronous downloading of results: +you submit a process graph with a (HTTP POST) request and receive the result +as direct response of that same request. +This only works properly if the processing doesn’t take too long (order of seconds, or a couple of minutes at most).

    +

    For the heavier work (larger regions of interest, larger time series, more intensive processing, …) +you have to use batch jobs, which are supported in the openEO API through separate HTTP requests, corresponding to these steps:

    +
      +
    • you create a job (providing a process graph and some other metadata like title, description, …)

    • +
    • you start the job

    • +
    • you wait for the job to finish, periodically polling its status

    • +
    • when the job finished successfully: get the listing of result assets

    • +
    • you download the result assets (or use them in an other way)

    • +
    +
    +

    Tip

    +

    This documentation mainly discusses how to programmatically +create and interact with batch job using the openEO Python client library. +The openEO API however does not enforce usage of the same tool +for each step in the batch job life cycle.

    +

    For example: if you prefer a graphical, web-based interactive environment +to manage and monitor your batch jobs, +feel free to switch to an openEO web editor +like editor.openeo.org +or editor.openeo.cloud +at any time. +After logging in with the same account you use in your Python scripts, +you should see your batch jobs listed under the “Data Processing” tab:

    +_images/batchjobs-webeditor-listing.png +

    With the “action” buttons on the right, you can for example +inspect batch job details, start/stop/delete jobs, +download their results, get batch job logs, etc.

    +
    +
    +

    Create a batch job

    +

    In the openEO Python Client Library, if you have a (raster) data cube, you can easily +create a batch job with the DataCube.create_job() method. +It’s important to specify in what format the result should be stored, +which can be done with an explicit DataCube.save_result() call before creating the job:

    +
    cube = connection.load_collection(...)
    +...
    +# Store raster data as GeoTIFF files
    +cube = cube.save_result(format="GTiff")
    +job = cube.create_job()
    +
    +
    +

    or directly in job.create_job():

    +
    cube = connection.load_collection(...)
    +...
    +job = cube.create_job(out_format="GTiff)
    +
    +
    +

    While not necessary, it is also recommended to give your batch job a descriptive title +so it’s easier to identify in your job listing, e.g.:

    +
    job = cube.create_job(title="NDVI timeseries 2022")
    +
    +
    +
    +
    +

    Batch job object

    +

    The job object returned by create_job() +is a BatchJob object. +It is basically a client-side reference to a batch job that exists on the back-end +and allows to interact with that batch job +(see the BatchJob API docs for +available methods).

    +
    +

    Note

    +

    The BatchJob class originally had +the more cryptic name RESTJob, +which is still available as legacy alias, +but BatchJob is (available and) recommended since version 0.11.0.

    +
    +

    A batch job on a back-end is fully identified by its +job_id:

    +
    >>> job.job_id
    +'d5b8b8f2-74ce-4c2e-b06d-bff6f9b14b8d'
    +
    +
    +
    +

    Reconnecting to a batch job

    +

    Depending on your situation or use case: +make sure to properly take note of the batch job id. +It allows you to “reconnect” to your job on the back-end, +even if it was created at another time, +by another script/notebook or even with another openEO client.

    +

    Given a back-end connection and the batch job id, +use Connection.job() +to create a BatchJob object for an existing batch job:

    +
    job_id = "5d806224-fe79-4a54-be04-90757893795b"
    +job = connection.job(job_id)
    +
    +
    +
    +
    +

    Jupyter integration

    +

    BatchJob objects have basic Jupyter notebook integration. +Put your BatchJob object as last statement +in a notebook cell and you get an overview of your batch jobs, +including job id, status, title and even process graph visualization:

    +_images/batchjobs-jupyter-created.png +
    +
    +
    +

    List your batch jobs

    +

    You can list your batch jobs on the back-end with +Connection.list_jobs(), which returns a list of job metadata:

    +
    >>> connection.list_jobs()
    +[{'title': 'NDVI timeseries 2022', 'status': 'created', 'id': 'd5b8b8f2-74ce-4c2e-b06d-bff6f9b14b8d', 'created': '2022-06-08T08:58:11Z'},
    + {'title': 'NDVI timeseries 2021', 'status': 'finished', 'id': '4e720e70-88bd-40bc-92db-a366985ebd67', 'created': '2022-06-04T14:46:06Z'},
    + ...
    +
    +
    +

    The listing returned by Connection.list_jobs() +has Jupyter notebook integration:

    +_images/batchjobs-jupyter-listing.png +
    +
    +

    Run a batch job

    +

    Starting a batch job is pretty straightforward with the +start() method:

    +
    job.start()
    +
    +
    +

    If this didn’t raise any errors or exceptions your job +should now have started (status “running”) +or be queued for processing (status “queued”).

    +
    +

    Wait for a batch job to finish

    +

    A batch job typically takes some time to finish, +and you can check its status with the status() method:

    +
    >>> job.status()
    +"running"
    +
    +
    +

    The possible batch job status values, defined by the openEO API, are +“created”, “queued”, “running”, “canceled”, “finished” and “error”.

    +

    Usually, you can only reliably get results from your job, +as discussed in Download batch job results, +when it reaches status “finished”.

    +
    +
    +

    Create, start and wait in one go

    +

    You could, depending on your situation, manually check your job’s status periodically +or set up a polling loop system to keep an eye on your job. +The openEO Python client library also provides helpers to do that for you.

    +

    Working from an existing BatchJob instance

    +
    +

    If you have a batch job that is already created as shown above, you can use +the job.start_and_wait() method +to start it and periodically poll its status until it reaches status “finished” (or fails with status “error”). +Along the way it will print some progress messages.

    +
    >>> job.start_and_wait()
    +0:00:00 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': send 'start'
    +0:00:36 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': queued (progress N/A)
    +0:01:35 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': queued (progress N/A)
    +0:02:19 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': running (progress N/A)
    +0:02:50 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': running (progress N/A)
    +0:03:28 Job 'b0e8adcf-087f-41de-afe6-b3c0ea88ff38': finished (progress N/A)
    +
    +
    +
    +

    Working from a DataCube instance

    +
    +

    If you didn’t create the batch job yet from a given DataCube +you can do the job creation, starting and waiting in one go +with cube.execute_batch():

    +
    >>> job = cube.execute_batch()
    +0:00:00 Job 'f9f4e3d3-bc13-441b-b76a-b7bfd3b59669': send 'start'
    +0:00:23 Job 'f9f4e3d3-bc13-441b-b76a-b7bfd3b59669': queued (progress N/A)
    +...
    +
    +
    +

    Note that cube.execute_batch() +returns a BatchJob instance pointing to +the newly created batch job.

    +
    +
    +

    Tip

    +

    You can fine-tune the details of the polling loop (the poll frequency, +how the progress is printed, …). +See job.start_and_wait() +or cube.execute_batch() +for more information.

    +
    +
    +
    +
    +

    Batch job logs

    +

    Batch jobs in openEO have logs to help with monitoring and debugging batch jobs. +The back-end typically uses this to dump information during data processing +that may be relevant for the user (e.g. warnings, resource stats, …). +Moreover, openEO processes like inspect allow users to log their own information.

    +

    Batch job logs can be fetched with job.logs()

    +
    >>> job.logs()
    +[{'id': 'log001', 'level': 'info', 'message': 'Job started with 4 workers'},
    + {'id': 'log002', 'level': 'debug', 'message': 'Loading 5x3x6 tiles'},
    + {'id': 'log003', 'level': 'error', 'message': "Failed to load data cube: corrupt data for tile 'J9A7K2'."},
    +...
    +
    +
    +

    In a Jupyter notebook environment, this also comes with Jupyter integration:

    +_images/batchjobs-jupyter-logs.png +
    +

    Automatic batch job log printing

    +

    When using +job.start_and_wait() +or cube.execute_batch() +to run a batch job and it fails, +the openEO Python client library will automatically +print the batch job logs and instructions to help with further investigation:

    +
    >>> job.start_and_wait()
    +0:00:00 Job '68caccff-54ee-470f-abaa-559ed2d4e53c': send 'start'
    +0:00:01 Job '68caccff-54ee-470f-abaa-559ed2d4e53c': running (progress N/A)
    +0:00:07 Job '68caccff-54ee-470f-abaa-559ed2d4e53c': error (progress N/A)
    +
    +Your batch job '68caccff-54ee-470f-abaa-559ed2d4e53c' failed.
    +Logs can be inspected in an openEO (web) editor
    +or with `connection.job('68caccff-54ee-470f-abaa-559ed2d4e53c').logs()`.
    +
    +Printing logs:
    +[{'id': 'log001', 'level': 'info', 'message': 'Job started with 4 workers'},
    +{'id': 'log002', 'level': 'debug', 'message': 'Loading 5x3x6 tiles'},
    +{'id': 'log003', 'level': 'error', 'message': "Failed to load data cube: corrupt data for tile 'J9A7K2'."}]
    +
    +
    +
    +
    +
    +

    Download batch job results

    +

    Once a batch job is finished you can get a handle to the results +(which can be a single file or multiple files) and metadata +with get_results():

    +
    >>> results = job.get_results()
    +>>> results
    +<JobResults for job '57da31da-7fd4-463a-9d7d-c9c51646b6a4'>
    +
    +
    +

    The result metadata describes the spatio-temporal properties of the result +and is in fact a valid STAC item:

    +
    >>> results.get_metadata()
    +{
    +    'bbox': [3.5, 51.0, 3.6, 51.1],
    +    'geometry': {'coordinates': [[[3.5, 51.0], [3.5, 51.1], [3.6, 51.1], [3.6, 51.0], [3.5, 51.0]]], 'type': 'Polygon'},
    +    'assets': {
    +        'res001.tiff': {
    +            'href': 'https://openeo.example/download/432f3b3ef3a.tiff',
    +            'type': 'image/tiff; application=geotiff',
    +            ...
    +        'res002.tiff': {
    +            ...
    +
    +
    +
    +

    Download all assets

    +

    In the general case, when you have one or more result files (also called “assets”), +the easiest option to download them is +using download_files() (plural) +where you just specify a download folder +(otherwise the current working directory will be used by default):

    +
    results.download_files("data/out")
    +
    +
    +

    The resulting files will be named as they are advertised in the results metadata +(e.g. res001.tiff and res002.tiff in case of the metadata example above).

    +
    +
    +

    Download single asset

    +

    If you know that there is just a single result file, you can also download it directly with +download_file() (singular) with the desired file name:

    +
    results.download_file("data/out/result.tiff")
    +
    +
    +

    This will fail however if there are multiple assets in the job result +(like in the metadata example above). +In that case you can still download a single by specifying which one you +want to download with the name argument:

    +
    results.download_file("data/out/result.tiff", name="res002.tiff")
    +
    +
    +
    +
    +

    Fine-grained asset downloads

    +

    If you need a bit more control over which asset to download and how, +you can iterate over the result assets explicitly +and download these ResultAsset instances +with download(), like this:

    +
    for asset in results.get_assets():
    +    if asset.metadata["type"].startswith("image/tiff"):
    +        asset.download("data/out/result-v2-" + asset.name)
    +
    +
    +
    +
    +
    +

    Directly load batch job results

    +

    If you want to skip downloading an asset to disk, you can also load it directly. +For example, load a JSON asset with load_json():

    +
    >>> asset.metadata
    +{"type": "application/json", "href": "https://openeo.example/download/432f3b3ef3a.json"}
    +>>> data = asset.load_json()
    +>>> data
    +{"2021-02-24T10:59:23Z": [[3, 2, 5], [3, 4, 5]], ....}
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/best_practices.html b/best_practices.html new file mode 100644 index 000000000..ded07d2c5 --- /dev/null +++ b/best_practices.html @@ -0,0 +1,211 @@ + + + + + + + + Best practices, coding style and general tips — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Best practices, coding style and general tips

    +

    This is a collection of guidelines regarding best practices, +coding style and usage patterns for the openEO Python Client Library.

    +

    It is in the first place an internal recommendation for openEO developers +to give documentation, code examples, demo’s and tutorials +a consistent look and feel, +following common software engineering best practices. +Secondly, the wider audience of openEO users is also invited to pick up +a couple of tips and principles to improve their own code and scripts.

    +
    +

    Background and inspiration

    +

    While some people consider coding style a personal choice or even irrelevant, +there are various reasons to settle on certain conventions. +Just the fact alone of following conventions +lowers the bar to get faster to the important details in someone else’s code. +Apart from taste, there are also technical reasons to pick certain rules +to streamline the programming workflow, +not only for humans, +but also supporting tools (e.g. minimize risk on merge conflicts).

    +

    While the Python language already has a strong focus on readability by design, +the Python community is strongly gravitating to even more strict conventions:

    +
      +
    • pep8: the mother of all Python code style guides

    • +
    • black: an opinionated code formatting tool +that gets more and more traction in popular, high profile projects.

    • +
    +

    This openEO oriented style guide will highlight +and build on these recommendations.

    +
    +
    +

    General code style recommendations

    +
      +
    • Indentation with 4 spaces.

    • +
    • Avoid star imports (from module import *). +While this seems like a quick way to import a bunch of functions/classes, +it makes it very hard for the reader to figure out where things come from. +It can also lead to strange bugs and behavior because it silently overwrites +references you previously imported.

    • +
    +
    +
    +

    Line (length) management

    +

    While desktop monitors offer plenty of (horizontal) space nowadays, +it is still a common recommendation to avoid long source code lines. +Not only are long lines hard to read and understand, +one should also consider that source code might still be viewed +on a small screen or tight viewport, +where scrolling horizontally is annoying or even impossible. +Unnecessarily long lines are also notorious +for not playing well with version control tools and workflows.

    +

    Here are some guidelines on how to split long statements over multiple lines.

    +

    Split long function/method calls directly after the opening parenthesis +and list arguments with a standard 4 space indentation +(not after the first argument with some ad-hoc indentation). +Put the closing parenthesis on its own line.

    +
    # Avoid this:
    +s2_fapar = connection.load_collection("TERRASCOPE_S2_FAPAR_V2",
    +                                      spatial_extent={'west': 16.138916, 'east': 16.524124, 'south': 48.1386, 'north': 48.320647},
    +                                      temporal_extent=["2020-05-01", "2020-05-20"])
    +
    +# This is better:
    +s2_fapar = connection.load_collection(
    +    "TERRASCOPE_S2_FAPAR_V2",
    +    spatial_extent={'west': 16.138916, 'east': 16.524124, 'south': 48.1386, 'north': 48.320647},
    +    temporal_extent=["2020-05-01", "2020-05-20"],
    +)
    +
    +
    +
    +
    +

    Jupyter(lab) tips and tricks

    +
      +
    • Add a cell with openeo.client_version() (e.g. just after importing all your libraries) +to keep track of which version of the openeo Python client library you used in your notebook.

    • +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/changelog.html b/changelog.html new file mode 100644 index 000000000..ee245da9e --- /dev/null +++ b/changelog.html @@ -0,0 +1,1135 @@ + + + + + + + + Changelog — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Changelog

    +

    All notable changes to this project will be documented in this file.

    +

    The format is based on Keep a Changelog, +and this project adheres to Semantic Versioning.

    +
    +

    [Unreleased]

    +
    +

    Added

    +
      +
    • Support new UDF signature: def apply_datacube(cube: DataArray, context: dict) -> DataArray +(#310)

    • +
    • Add collection_property() helper to easily build collection metadata property filters for Connection.load_collection() +(#331)

    • +
    • Add DataCube.apply_polygon() (standardized version of experimental chunk_polygon) (#424)

    • +
    • Various improvements to band mapping with the Awesome Spectral Indices feature. +Allow explicitly specifying the satellite platform for band name mapping (e.g. “Sentinel2” or “LANDSAT8”) if cube metadata lacks info. +Follow the official band mapping from Awesome Spectral Indices better. +Allow manually specifying the desired band mapping. +(#485, #501)

    • +
    • Also attempt to automatically refresh OIDC access token on a 401 TokenInvalid response (in addition to 403 TokenInvalid) (#508)

    • +
    • Add Parameter.object() factory for object type parameters

    • +
    +
    +
    +

    Changed

    +
    +
    +

    Removed

    +
      +
    • Remove custom spectral indices “NDGI”, “NDMI” and “S2WI” from “extra-indices-dict.json” +that were shadowing the official definitions from Awesome Spectral Indices (#501)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Initial support for “spectral indices” that use constants defined by Awesome Spectral Indices (#501)

    • +
    +
    +
    +
    +

    [0.25.0] - 2023-11-02

    +
    +

    Changed

    +
      +
    • Introduce OpenEoApiPlainError for API error responses that are not well-formed +for better distinction with properly formed API error responses (OpenEoApiError). +(#491).

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix missing validate support in LocalConnection.execute (#493)

    • +
    +
    +
    +
    +

    [0.24.0] - 2023-10-27

    +
    +

    Added

    +
      +
    • Add DataCube.reduce_spatial()

    • +
    • Added option (enabled by default) to automatically validate a process graph before execution. +Validation issues just trigger warnings for now. (#404)

    • +
    • Added “Sentinel1” band mapping support to “Awesome Spectral Indices” wrapper (#484)

    • +
    • Run tests in GitHub Actions against Python 3.12 as well

    • +
    +
    +
    +

    Changed

    +
      +
    • Enforce XarrayDataCube dimension order in execute_local_udf() to (t, bands, y, x) +to improve UDF interoperability with existing back-end implementations.

    • +
    +
    +
    +
    +

    [0.23.0] - 2023-10-02

    +
    +

    Added

    +
      +
    • Support year/month shorthand date notations in temporal extent arguments of Connection.load_collection, DataCube.filter_temporal and related (#421)

    • +
    • Support parameterized bands in load_collection (#471)

    • +
    • Allow specifying item schema in Parameter.array()

    • +
    • Support “subtype” and “format” schema options in Parameter.string()

    • +
    +
    +
    +

    Changed

    +
      +
    • Before doing user-defined process (UDP) listing/creation: verify that back-end supports that (through openEO capabilities document) to improve error message.

    • +
    • Skip metadata-based normalization/validation and stop showing unhelpful warnings/errors +like “No cube:dimensions metadata” or “Invalid dimension” +when no metadata is available client-side anyway (e.g. when using datacube_from_process, parameterized cube building, …). +(#442)

    • +
    +
    +
    +

    Removed

    +
      +
    • Bumped minimal supported Python version to 3.7 (#460)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Support handling of “callback” parameters in openeo.processes callables (#470)

    • +
    +
    +
    +
    +

    [0.22.0] - 2023-08-09

    +
    +

    Added

    +
      +
    • Processes that take a CRS as argument now try harder to normalize your input to +a CRS representation that aligns with the openEO API (using pyproj library when available) +(#259)

    • +
    • Initial load_geojson support with Connection.load_geojson() (#424)

    • +
    • Initial load_url (for vector cubes) support with Connection.load_url() (#424)

    • +
    • Add VectorCube.apply_dimension() (Open-EO/openeo-python-driver#197)

    • +
    • Support lambda based property filtering in Connection.load_stac() (#425)

    • +
    • VectorCube: initial support for filter_bands, filter_bbox, filter_labels and filter_vector (#459)

    • +
    +
    +
    +

    Changed

    +
      +
    • Connection based requests: always use finite timeouts by default (20 minutes in general, 30 minutes for synchronous execute requests) +(#454)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix: MultibackendJobManager should stop when finished, also when job finishes with error (#452)

    • +
    +
    +
    +
    +

    [0.21.1] - 2023-07-19

    +
    +

    Fixed

    +
      +
    • Fix spatial_extent/temporal_extent handling in “localprocessing” load_stac (#451)

    • +
    +
    +
    +
    +

    [0.21.0] - 2023-07-19

    +
    +

    Added

    +
      +
    • Add support in VectoCube.download() and VectorCube.execute_batch() to guess output format from extension of a given filename +(#401, #449)

    • +
    • Added load_stac for Client Side Processing, based on the openeo-processes-dask implementation

    • +
    +
    +
    +

    Changed

    +
      +
    • Updated docs for Client Side Processing with load_stac examples, available at https://open-eo.github.io/openeo-python-client/cookbook/localprocessing.html

    • +
    +
    +
    +

    Fixed

    +
      +
    • Avoid double save_result nodes when combining VectorCube.save_result() and .download(). +(#401, #448)

    • +
    +
    +
    +
    +

    [0.20.0] - 2023-06-30

    +
    +

    Added

    +
      +
    • Added automatically renewal of access tokens with OIDC client credentials grant (Connection.authenticate_oidc_client_credentials) +(#436)

    • +
    +
    +
    +

    Changed

    +
      +
    • Simplified BatchJob methods start(), stop(), describe(), … +Legacy aliases start_job(), describe_job(), … are still available and don’t trigger a deprecation warning for now. +(#280)

    • +
    • Update openeo.extra.spectral_indices to Awesome Spectral Indices v0.4.0

    • +
    +
    +
    +
    +

    [0.19.0] - 2023-06-16

    +
    +

    Added

    +
      +
    • Generalized support for setting (default) OIDC provider id through env var OPENEO_AUTH_PROVIDER_ID +#419

    • +
    • Added OidcDeviceCodePollTimeout: specific exception for OIDC device code flow poll timeouts

    • +
    • On-demand preview: Added DataCube.preview() to generate a XYZ service with the process graph and display a map widget

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix format option conflict between save_result and create_job +#433

    • +
    • Ensure that OIDC device code link opens in a new tab/window #443

    • +
    +
    +
    +
    +

    [0.18.0] - 2023-05-31

    +
    +

    Added

    +
      +
    • Support OIDC client credentials grant from a generic connection.authenticate_oidc() call +through environment variables +#419

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fixed UDP parameter conversion issue in build_process_dict when using parameter in context of run_udf +#431

    • +
    +
    +
    +
    +

    [0.17.0] and [0.17.1] - 2023-05-16

    +
    +

    Added

    +
      +
    • Connection.authenticate_oidc(): add argument max_poll_time to set maximum device code flow poll time

    • +
    • Show progress bar while waiting for OIDC authentication with device code flow, +including special mode for in Jupyter notebooks. +(#237)

    • +
    • Basic support for load_stac process with Connection.load_stac() +(#425)

    • +
    • Add DataCube.aggregate_spatial_window()

    • +
    +
    +
    +

    Fixed

    +
      +
    • Include “scope” parameter in OIDC token request with client credentials grant.

    • +
    • Support fractional seconds in Rfc3339.parse_datetime +(#418)

    • +
    +
    +
    +
    +

    [0.16.0] - 2023-04-17 - “SRR5” release

    +
    +

    Added

    +
      +
    • Full support for user-uploaded files (/files endpoints) +(#377)

    • +
    • Initial, experimental “local processing” feature to use +openEO Python Client Library functionality on local +GeoTIFF/NetCDF files and also do the processing locally +using the openeo_processes_dask package +(#338)

    • +
    • Add BatchJob.get_results_metadata_url().

    • +
    +
    +
    +

    Changed

    +
      +
    • Connection.list_files() returns a list of UserFile objects instead of a list of metadata dictionaries. +Use UserFile.metadata to get the original dictionary. +(#377)

    • +
    • DataCube.aggregate_spatial() returns a VectorCube now, instead of a DataCube +(#386). +The (experimental) fit_class_random_forest() and fit_regr_random_forest() methods +moved accordingly to the VectorCube class.

    • +
    • Improved documentation on openeo.processes and ProcessBuilder +(#390).

    • +
    • DataCube.create_job() and Connection.create_job() now require +keyword arguments for all but the first argument for clarity. +(#412).

    • +
    • Pass minimum log level to backend when retrieving batch job and secondary service logs. +(Open-EO/openeo-api#485, +Open-EO/openeo-python-driver#170)

    • +
    +
    +
    +

    Removed

    +
      +
    • Dropped support for pre-1.0.0 versions of the openEO API +(#134):

      +
        +
      • Remove ImageCollectionClient and related helpers +(now unused leftovers from version 0.4.0 and earlier). +(Also #100)

      • +
      • Drop support for pre-1.0.0 job result metadata

      • +
      • Require at least version 1.0.0 of the openEO API for a back-end in Connection +and all its methods.

      • +
      +
    • +
    +
    +
    +

    Fixed

    +
      +
    • Reinstated old behavior of authentication related user files (e.g. refresh token store) on Windows: when PrivateJsonFile may be readable by others, just log a message instead of raising PermissionError (387)

    • +
    • VectorCube.create_job() and MlModel.create_job() are properly aligned with DataCube.create_job() +regarding setting job title, description, etc. +(#412).

    • +
    • More robust handling of billing currency/plans in capabilities +(#414)

    • +
    • Avoid blindly adding a save_result node from DataCube.execute_batch() when there is already one +(#401)

    • +
    +
    +
    +
    +

    [0.15.0] - 2023-03-03

    +
    +

    Added

    +
      +
    • The openeo Python client library can now also be installed with conda (conda-forge channel) +(#176)

    • +
    • Allow using a custom requests.Session in openeo.rest.auth.oidc logic

    • +
    +
    +
    +

    Changed

    +
      +
    • Less verbose log printing on failed batch job #332

    • +
    • Improve (UTC) timezone handling in openeo.util.Rfc3339 and add rfc3339.today()/rfc3339.utcnow().

    • +
    +
    +
    +
    +

    [0.14.1] - 2023-02-06

    +
    +

    Fixed

    +
      +
    • Fine-tuned XarrayDataCube tests for conda building and packaging (#176)

    • +
    +
    +
    +
    +

    [0.14.0] - 2023-02-01

    +
    +

    Added

    +
      +
    • Jupyter integration: show process graph visualization of DataCube objects instead of generic repr. (#336)

    • +
    • Add Connection.vectorcube_from_paths() to load a vector cube +from files (on back-end) or URLs with load_uploaded_files process.

    • +
    • Python 3.10 and 3.11 are now officially supported +(test run now also for 3.10 and 3.11 in GitHub Actions, #346)

    • +
    • Support for simplified OIDC device code flow, (#335)

    • +
    • Added MultiBackendJobManager, based on implementation from openeo-classification project +(#361)

    • +
    • Added resilience to MultiBackendJobManager for backend failures (#365)

    • +
    +
    +
    +

    Changed

    +
      +
    • execute_batch also skips temporal 502 Bad Gateway errors. #352

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fixed/improved math operator/process support for DataCubes in “apply” mode (non-“band math”), +allowing expressions like 10 * cube.log10() and ~(cube == 0) +(#123)

    • +
    • Support PrivateJsonFile permissions properly on Windows, using oschmod library. +(#198)

    • +
    • Fixed some broken unit tests on Windows related to path (separator) handling. +(#350)

    • +
    +
    +
    +
    +

    [0.13.0] - 2022-10-10 - “UDF UX” release

    +
    +

    Added

    +
      +
    • Add max_cloud_cover argument to load_collection() to simplify setting maximum cloud cover (property eo:cloud_cover) (#328)

    • +
    +
    +
    +

    Changed

    +
      +
    • Improve default dimension metadata of a datacube created with openeo.rest.datacube.DataCube.load_disk_collection

    • +
    • DataCube.download(): only automatically add save_result node when there is none yet.

    • +
    • Deprecation warnings: make sure they are shown by default and can be hidden when necessary.

    • +
    • Rework and improve openeo.UDF helper class for UDF usage +(#312).

      +
        +
      • allow loading directly from local file or URL

      • +
      • autodetect runtime from file/URL suffix or source code

      • +
      • hide implementation details around data argument (e.g.data={"from_parameter": "x"})

      • +
      • old usage patterns of openeo.UDF and DataCube.apply_dimension() still work but trigger deprecation warnings

      • +
      +
    • +
    • Show warning when using load_collection property filters that are not defined in the collection metadata (summaries).

    • +
    +
    +
    +
    +

    [0.12.1] - 2022-09-15

    +
    +

    Changed

    +
      +
    • Eliminate dependency on distutils.version.LooseVersion which started to trigger deprecation warnings (#316).

    • +
    +
    +
    +

    Removed

    +
      +
    • Remove old Connection.oidc_auth_user_id_token_as_bearer workaround flag (#300)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix refresh token handling in case of OIDC token request with refresh token grant (#326)

    • +
    +
    +
    +
    +

    [0.12.0] - 2022-09-09

    +
    +

    Added

    +
      +
    • Allow passing raw JSON string, JSON file path or URL to Connection.download(), +Connection.execute() and Connection.create_job()

    • +
    • Add support for reverse math operators on DataCube in apply mode (#323)

    • +
    • Add DataCube.print_json() to simplify exporting process graphs in Jupyter or other interactive environments (#324)

    • +
    • Raise DimensionAlreadyExistsException when trying to add_dimension() a dimension with existing name (Open-EO/openeo-geopyspark-driver#205)

    • +
    +
    +
    +

    Changed

    +
      +
    • DataCube.execute_batch() now also guesses the output format from the filename, +and allows using format argument next to the current out_format +to align with the DataCube.download() method. (#240)

    • +
    • Better client-side handling of merged band name metadata in DataCube.merge_cubes()

    • +
    +
    +
    +

    Removed

    +
      +
    • Remove legacy DataCube.graph and DataCube.flatten() to prevent usage patterns that cause interoperability issues +(#155, #209, #324)

    • +
    +
    +
    +
    +

    [0.11.0] - 2022-07-02

    +
    +

    Added

    +
      +
    • Add support for passing a PGNode/VectorCube as geometry to aggregate_spatial, mask_polygon, …

    • +
    • Add support for second order callbacks e.g. is_valid in count in reduce_dimension (#317)

    • +
    +
    +
    +

    Changed

    +
      +
    • Rename RESTJob class name to less cryptic and more user-friendly BatchJob. +Original RESTJob is still available as deprecated alias. +(#280)

    • +
    • Dropped default reducer (“max”) from DataCube.reduce_temporal_simple()

    • +
    • Various documentation improvements:

      +
        +
      • general styling, landing page and structure tweaks (#285)

      • +
      • batch job docs (#286)

      • +
      • getting started docs (#308)

      • +
      • part of UDF docs (#309)

      • +
      • added process-to-method mapping docs

      • +
      +
    • +
    • Drop hardcoded h5netcdf engine from XarrayIO.from_netcdf_file() +and XarrayIO.to_netcdf_file() (#314)

    • +
    • Changed argument name of Connection.describe_collection() from name to collection_id +to be more in line with other methods/functions.

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix context/condition confusion bug with count callback in DataCube.reduce_dimension() (#317)

    • +
    +
    +
    +
    +

    [0.10.1] - 2022-05-18 - “LPS22” release

    +
    +

    Added

    +
      +
    • Add context parameter to DataCube.aggregate_spatial(), DataCube.apply_dimension(), +DataCube.apply_neighborhood(), DataCube.apply(), DataCube.merge_cubes(). +(#291)

    • +
    • Add DataCube.fit_regr_random_forest() (#293)

    • +
    • Add PGNode.update_arguments(), which combined with DataCube.result_node() allows to do advanced process graph argument tweaking/updating without using ._pg hacks.

    • +
    • JobResults.download_files(): also download (by default) the job result metadata as STAC JSON file (#184)

    • +
    • OIDC handling in Connection: try to automatically refresh access token when expired (#298)

    • +
    • Connection.create_job raises exception if response does not contain a valid job_id

    • +
    • Add openeo.udf.debug.inspect for using the openEO inspect process in a UDF (#302)

    • +
    • Add openeo.util.to_bbox_dict() to simplify building a openEO style bbox dictionary, e.g. from a list or shapely geometry (#304)

    • +
    +
    +
    +

    Removed

    +
      +
    • Removed deprecated (and non-functional) zonal_statistics method from old ImageCollectionClient API. (#144)

    • +
    +
    +
    +
    +

    [0.10.0] - 2022-04-08 - “SRR3” release

    +
    +

    Added

    +
      +
    • Add support for comparison operators (<, >, <= and >=) in callback process building

    • +
    • Added Connection.describe_process() to retrieve and show a single process

    • +
    • Added DataCube.flatten_dimensions() and DataCube.unflatten_dimension +(Open-EO/openeo-processes#308, Open-EO/openeo-processes#316)

    • +
    • Added VectorCube.run_udf (to avoid non-standard process_with_node(UDF(...)) usage)

    • +
    • Added DataCube.fit_class_random_forest() and Connection.load_ml_model() to train and load Machine Learning models +(#279)

    • +
    • Added DataCube.predict_random_forest() to easily use reduce_dimension with a predict_random_forest reducer +using a MlModel (trained with fit_class_random_forest) +(#279)

    • +
    • Added DataCube.resample_cube_temporal (#284)

    • +
    • Add target_dimension argument to DataCube.aggregate_spatial (#288)

    • +
    • Add basic configuration file system to define a default back-end URL and enable auto-authentication (#264, #187)

    • +
    • Add context argument to DataCube.chunk_polygon()

    • +
    • Add Connection.version_info() to list version information about the client, the API and the back-end

    • +
    +
    +
    +

    Changed

    +
      +
    • Include openEO API error id automatically in exception message to simplify user support and post-mortem analysis.

    • +
    • Use Connection.default_timeout (when set) also on version discovery request

    • +
    • Drop ImageCollection from DataCube’s class hierarchy. +This practically removes very old (pre-0.4.0) methods like date_range_filter and bbox_filter from DataCube. +(#100, #278)

    • +
    • Deprecate DataCube.send_job in favor of DataCube.create_job for better consistency (internally and with other libraries) (#276)

    • +
    • Update (autogenerated) openeo.processes module to 1.2.0 release (2021-12-13) of openeo-processes

    • +
    • Update (autogenerated) openeo.processes module to draft version of 2022-03-16 (e4df8648) of openeo-processes

    • +
    • Update openeo.extra.spectral_indices to a post-0.0.6 version of Awesome Spectral Indices

    • +
    +
    +
    +

    Removed

    +
      +
    • Removed deprecated zonal_statistics method from DataCube. (#144)

    • +
    • Deprecate old-style DataCube.polygonal_mean_timeseries(), DataCube.polygonal_histogram_timeseries(), +DataCube.polygonal_median_timeseries() and DataCube.polygonal_standarddeviation_timeseries()

    • +
    +
    +
    +

    Fixed

    +
      +
    • Support rename_labels on temporal dimension (#274)

    • +
    • Basic support for mixing DataCube and ProcessBuilder objects/processing (#275)

    • +
    +
    +
    +
    +

    [0.9.2] - 2022-01-14

    +
    +

    Added

    +
      +
    • Add experimental support for chunk_polygon process (Open-EO/openeo-processes#287)

    • +
    • Add support for spatial_extent, temporal_extent and bands to Connection.load_result()

    • +
    • Setting the environment variable OPENEO_BASEMAP_URL allows to set a new templated URL to a XYZ basemap for the Vue Components library, OPENEO_BASEMAP_ATTRIBUTION allows to set the attribution for the basemap (#260)

    • +
    • Initial support for experimental “federation:missing” flag on partial openEO Platform user job listings (Open-EO/openeo-api#419)

    • +
    • Best effort detection of mistakenly using Python builtin sum or all functions in callbacks (Forum #113)

    • +
    • Automatically print batch job logs when job doesn’t finish successfully (using execute_batch/run_synchronous/start_and_wait).

    • +
    +
    +
    +
    +

    [0.9.1] - 2021-11-16

    +
    +

    Added

    +
      +
    • Add options argument to DataCube.atmospheric_correction (Open-EO/openeo-python-driver#91)

    • +
    • Add atmospheric_correction_options and cloud_detection_options arguments to DataCube.ard_surface_reflectance (Open-EO/openeo-python-driver#91)

    • +
    • UDP storing: add support for “returns”, “categories”, “examples” and “links” properties (#242)

    • +
    • Add openeo.extra.spectral_indices: experimental API to easily compute spectral indices (vegetation, water, urban, …) +on a DataCube, using the index definitions from Awesome Spectral Indices

    • +
    +
    +
    +

    Changed

    +
      +
    • Batch job status poll loop: ignore (temporary) “service unavailable” errors (Open-EO/openeo-python-driver#96)

    • +
    • Batch job status poll loop: fail when there are too many soft errors (temporary connection/availability issues)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix DataCube.ard_surface_reflectance() to use process ard_surface_reflectance instead of atmospheric_correction

    • +
    +
    +
    +
    +

    [0.9.0] - 2021-10-11

    +
    +

    Added

    +
      +
    • Add command line tool openeo-auth token-clear to remove OIDC refresh token cache

    • +
    • Add support for OIDC device authorization grant without PKCE nor client secret, +(#225, openeo-api#410)

    • +
    • Add DataCube.dimension_labels() (EP-4008)

    • +
    • Add Connection.load_result() (EP-4008)

    • +
    • Add proper support for child callbacks in fit_curve and predict_curve (#229)

    • +
    • ProcessBuilder: Add support for array_element(data, n) through data[n] syntax (#228)

    • +
    • ProcessBuilder: Add support for eq and neq through == and != operators (EP-4011)

    • +
    • Add DataCube.validate() for process graph validation (EP-4012 related)

    • +
    • Add Connection.as_curl() for generating curl command to evaluate a process graph or DataCube from the command line

    • +
    • Add support in DataCube.download() to guess output format from extension of a given filename

    • +
    +
    +
    +

    Changed

    +
      +
    • Improve default handling of crs (and base/height) in filter_bbox: avoid explicitly sending null unnecessarily +(#233).

    • +
    • Update documentation/examples/tests: EPSG CRS in filter_bbox should be integer code, not string +(#233).

    • +
    • Raise ProcessGraphVisitException from ProcessGraphVisitor.resolve_from_node() (instead of generic ValueError)

    • +
    • DataCube.linear_scale_range is now a shortcut for DataCube.apply(lambda  x:x.x.linear_scale_range( input_min, input_max, output_min, output_max)). +Instead of creating an invalid process graph that tries to invoke linear_scale_range on a datacube directly.

    • +
    • Nicer error message when back-end does not support basic auth (#247)

    • +
    +
    +
    +

    Removed

    +
      +
    • Remove unused and outdated (0.4-style) File/RESTFile classes (#115)

    • +
    • Deprecate usage of DataCube.graph property (#209)

    • +
    +
    +
    +
    +

    [0.8.2] - 2021-08-24

    +

    Minor release to address version packaging issue.

    +
    +
    +

    [0.8.1] - 2021-08-24

    +
    +

    Added

    +
      +
    • Support nested callbacks inside array arguments, for instance in array_modify, array_create

    • +
    • Support array_concat

    • +
    • add ProcessGraphUnflattener and PGNodeGraphUnflattener to unflatten a flat dict representation of a process +graph to a PGNode graph (EP-3609)

    • +
    • Add Connection.datacube_from_flat_graph and Connection.datacube_from_json to construct a DataCube +from flat process graph representation (e.g. JSON file or JSON URL) (EP-3609)

    • +
    • Add documentation about UDP unflattening and sharing (EP-3609)

    • +
    • Add fit_curve and predict_curve, two methods used in change detection

    • +
    +
    +
    +

    Changed

    +
      +
    • Update processes.py based on 1.1.0 release op openeo-processes project

    • +
    • processes.py: include all processes from “proposals” folder of openeo-processes project

    • +
    • Jupyter integration: Visual rendering for process graphs shown instead of a plain JSON representation.

    • +
    • Migrate from Travis CI to GitHub Actions for documentation building and unit tests (#178, EP-3645)

    • +
    +
    +
    +

    Removed

    +
      +
    • Removed unit test runs for Python 3.5 (#210)

    • +
    +
    +
    +
    +

    [0.8.0] - 2021-06-25

    +
    +

    Added

    +
      +
    • Allow, but raise warning when specifying a CRS for the geometry passed to aggregate_spatial and mask_polygon, +which is non-standard/experimental feature, only supported by specific back-ends +(#204)

    • +
    • Add optional argument to Parameter and fix re-encoding parameters with default value. (EP-3846)

    • +
    • Add support to test strict equality with ComparableVersion

    • +
    • Jupyter integration: add rich HTML rendering for more backend metadata (Job, Job Estimate, Logs, Services, User-Defined Processes)

    • +
    • Add support for filter_spatial

    • +
    • Add support for aggregate_temporal_period

    • +
    • Added class Service for secondary web-services

    • +
    • Added a method service to Connection

    • +
    • Add Rfc3339.parse_date and Rfc3339.parse_date_or_datetime

    • +
    +
    +
    +

    Changed

    +
      +
    • Disallow redirects on POST/DELETE/… requests and require status code 200 on POST /result requests. +This improves error information where POST /result would involve a redirect. (EP-3889)

    • +
    • Class JobLogEntry got replaced with a more complete and re-usable LogEntry dict

    • +
    • The following methods return a Service class instead of a dict: tiled_viewing_service in ImageCollection, ImageCollectionClient and DataCube, create_service in Connection

    • +
    +
    +
    +

    Deprecated

    +
      +
    • The method remove_service in Connection has been deprecated in favor of delete_service in the Service class

    • +
    +
    +
    +
    +

    [0.7.0] - 2021-04-21

    +
    +

    Added

    + +
    +
    +

    Changed

    +
      +
    • Eliminate development/optional dependency on openeo_udf project +(#159, #190, EP-3578). +Now the openEO client library itself contains the necessary classes and implementation to run UDF code locally.

    • +
    +
    +
    +

    Fixed

    +
      +
    • Connection: don’t send default auth headers to non-backend domains (#201)

    • +
    +
    +
    +
    +

    [0.6.1] - 2021-03-29

    +
    +

    Changed

    +
      +
    • Improve OpenID Connect usability on Windows: don’t raise exception on file permissions +that can not be changed (by os.chmod on Windows) (#198)

    • +
    +
    +
    +
    +

    [0.6.0] - 2021-03-26

    +
    +

    Added

    +
      +
    • Add initial/experimental support for OIDC device code flow with PKCE (alternative for client secret) (#191 / EP-3700)

    • +
    • When creating a connection: use “https://” by default when no protocol is specified

    • +
    • DataCube.mask_polygon: support Parameter argument for mask

    • +
    • Add initial/experimental support for default OIDC client (#192, Open-EO/openeo-api#366)

    • +
    • Add Connection.authenticate_oidc for user-friendlier OIDC authentication: first try refresh token and fall back on device code flow

    • +
    • Add experimental support for array_modify process (Open-EO/openeo-processes#202)

    • +
    +
    +
    +

    Removed

    +
      +
    • Remove old/deprecated Connection.authenticate_OIDC()

    • +
    +
    +
    +
    +

    [0.5.0] - 2021-03-17

    +
    +

    Added

    +
      +
    • Add namespace support to DataCube.process, PGNode, ProcessGraphVisitor (minor API breaking change) and related. +Allows building process graphs with processes from non-“backend” namespaces +(#182)

    • +
    • collection_items to request collection items through a STAC API

    • +
    • paginate as a basic method to support link-based pagination

    • +
    • Add namespace support to Connection.datacube_from_process

    • +
    • Add basic support for band name aliases in metadata.Band for band index lookup (EP-3670)

    • +
    +
    +
    +

    Changed

    +
      +
    • OpenEoApiError moved from openeo.rest.connection to openeo.rest

    • +
    • Added HTML representation for list_jobs, list_services, list_files and for job results

    • +
    • Improve refresh token handling in OIDC logic: avoid requesting refresh token +(which can fail if OIDC client is not set up for that) when not necessary (EP-3700)

    • +
    • RESTJob.start_and_wait: add status line when sending “start” request, and drop microsecond resolution from status lines

    • +
    +
    +
    +

    Fixed

    +
      +
    • Updated Vue Components library (solves issue with loading from slower back-ends where no result was shown)

    • +
    +
    +
    +
    +

    [0.4.10] - 2021-02-26

    +
    +

    Added

    +
      +
    • Add “reflected” operator support to ProcessBuilder

    • +
    • Add RESTJob.get_results(), JobResults and ResultAsset for more fine-grained batch job result handling. (EP-3739)

    • +
    • Add documentation on batch job result (asset) handling and downloading

    • +
    +
    +
    +

    Changed

    +
      +
    • Mark Connection.imagecollection more clearly as deprecated/legacy alias of Connection.load_collection

    • +
    • Deprecated job_results() and job_logs() on Connection object, it’s better to work through RESTJob object.

    • +
    • Update DataCube.sar_backscatter to the latest process spec: add coefficient argument +and remove orthorectify, rtc. (openeo-processes#210)

    • +
    +
    +
    +

    Removed

    +
      +
    • Remove outdated batch job result download logic left-overs

    • +
    • Remove (outdated) abstract base class openeo.job.Job: did not add value, only caused maintenance overhead. (#115)

    • +
    +
    +
    +
    +

    [0.4.9] - 2021-01-29

    +
    +

    Added

    +
      +
    • Make DataCube.filter_bbox() easier to use: allow passing a bbox tuple, list, dict or even shapely geometry directly as first positional argument or as bbox keyword argument. +Handling of the legacy non-standard west-east-north-south positional argument order is preserved for now (#136)

    • +
    • Add “band math” methods DataCube.ln(), DataCube.logarithm(base), DataCube.log10() and DataCube.log2()

    • +
    • Improved support for creating and handling parameters when defining user-defined processes (EP-3698)

    • +
    • Initial Jupyter integration: add rich HTML rendering of backend metadata (collections, file formats, UDF runtimes, …) +(#170)

    • +
    • add resolution_merge process (experimental) (EP-3687, openeo-processes#221)

    • +
    • add sar_backscatter process (experimental) (EP-3612, openeo-processes#210)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fixed ‘Content-Encoding’ handling in Connection.download: client did not automatically decompress /result +responses when necessary (#175)

    • +
    +
    +
    +
    +

    [0.4.8] - 2020-11-17

    +
    +

    Added

    +
      +
    • Add DataCube.aggregate_spatial()

    • +
    +
    +
    +

    Changed

    +
      +
    • Get/create default RefreshTokenStore lazily in Connection

    • +
    • Various documentation tweaks

    • +
    +
    +
    +
    +

    [0.4.7] - 2020-10-22

    +
    +

    Added

    +
      +
    • Add support for title/description/plan/budget in DataCube.send_job (#157 / #158)

    • +
    • Add DataCube.to_json() to easily get JSON representation of a DataCube

    • +
    • Allow to subclass CollectionMetadata and preserve original type when “cloning”

    • +
    +
    +
    +

    Changed

    +
      +
    • Changed execute_batch to support downloading multiple files (within EP-3359, support profiling)

    • +
    • Don’t send None-valued title/description/plan/budget fields from DataCube.send_job (#157 / #158)

    • +
    +
    +
    +

    Removed

    +
      +
    • Remove duplicate and broken Connection.list_processgraphs

    • +
    +
    +
    +

    Fixed

    +
      +
    • Various documentation fixes and tweaks

    • +
    • Avoid merge_cubes warning when using non-band-math DataCube operators

    • +
    +
    +
    +
    +

    [0.4.6] - 2020-10-15

    +
    +

    Added

    +
      +
    • Add DataCube.aggregate_temporal

    • +
    • Add initial support to download profiling information

    • +
    +
    +
    +

    Changed

    +
      +
    • Deprecated legacy functions/methods are better documented as such and link to a recommended alternative (EP-3617).

    • +
    • Get/create default AuthConfig in Connection lazily (allows client to run in environments without existing (default) config folder)

    • +
    +
    +
    +

    Deprecated

    +
      +
    • Deprecate zonal_statistics in favor of aggregate_spatial

    • +
    +
    +
    +

    Removed

    +
      +
    • Remove support for old, non-standard stretch_colors process (Use linear_scale_range instead).

    • +
    +
    +
    +
    +

    [0.4.5] - 2020-10-01

    +
    +

    Added

    +
      +
    • Also handle dict arguments in dereference_from_node_arguments (EP-3509)

    • +
    • Add support for less/greater than and equal operators

    • +
    • Raise warning when user defines a UDP with same id as a pre-defined one (EP-3544, #147)

    • +
    • Add rename_labels support in metadata (EP-3585)

    • +
    • Improve “callback” handling (sub-process graphs): add predefined callbacks for all official processes and functionality to assemble these (EP-3555, #153)

    • +
    • Moved datacube write/save/plot utilities from udf to client (EP-3456)

    • +
    • Add documentation on OpenID Connect authentication (EP-3485)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix kwargs handling in TimingLogger decorator

    • +
    +
    +
    +
    +

    [0.4.4] - 2020-08-20

    +
    +

    Added

    +
      +
    • Add openeo-auth command line tool to manage OpenID Connect (and basic auth) related configs (EP-3377/EP-3493)

    • +
    • Support for using config files for OpenID Connect and basic auth based authentication, instead of hardcoding credentials (EP-3377/EP-3493)

    • +
    +
    +
    +

    Fixed

    +
      +
    • Fix target_band handling in DataCube.ndvi (EP-3496)

    • +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/configuration.html b/configuration.html new file mode 100644 index 000000000..d8fb847ac --- /dev/null +++ b/configuration.html @@ -0,0 +1,237 @@ + + + + + + + + Configuration — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Configuration

    +
    +

    Warning

    +

    Configuration files are an experimental feature +and some details are subject to change.

    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    Configuration files

    +

    Some functionality of the openEO Python client library can customized +through configuration files.

    +
    +

    Note

    +

    Note that these configuration files are different from the authentication secret/cache files +discussed at Auth config files and openeo-auth helper tool. +The latter are focussed on storing authentication secrets +and are mostly managed automatically. +The normal configuration files however should not contain secrets, +are usually edited manually, can be placed at various locations +and it is not uncommon to store them in version control where that makes sense.

    +
    +
    +

    Format

    +

    At the moment, only INI-style configs are supported. +This is a simple configuration format, easy to maintain +and it is supported out of the box in Python (without additional libraries).

    +

    Example (note the use of sections and support for comments):

    +
    [General]
    +# Print loaded configuration file and default back-end URLs in interactive mode
    +verbose = auto
    +
    +[Connection]
    +default_backend = openeo.cloud
    +
    +
    +
    +
    +

    Location

    +

    The following configuration locations are probed (in this order) for an existing configuration file. The first successful hit will be loaded:

    +
      +
    • the path in environment variable OPENEO_CLIENT_CONFIG if it is set (filename must end with extension .ini)

    • +
    • the file openeo-client-config.ini in the current working directory

    • +
    • the file ${OPENEO_CONFIG_HOME}/openeo-client-config.ini if the environment variable OPENEO_CONFIG_HOME is set

    • +
    • the file ${XDG_CONFIG_HOME}/openeo-python-client/openeo-client-config.ini if environment variable XDG_CONFIG_HOME is set

    • +
    • the file .openeo-client-config.ini in the home folder of the user

    • +
    +
    +
    +

    Configuration options

    + +++++ + + + + + + + + + + + + + + + + + + + + + + + + +

    Config Section

    Config

    Description and possible values

    General

    verbose

    +
    Verbosity mode when important config values are used:
      +
    • print: always print() info

    • +
    • auto (default): only print() when in an interactive context

    • +
    • off: don’t print info

    • +
    +
    +
    +

    Connection

    default_backend

    Default back-end to connect to when openeo.connect() +is used without explicit back-end URL. +Also see Default openEO back-end URL and auto-authentication

    Connection

    default_backend.auto_authenticate

    +
    Automatically authenticate in openeo.connect() when using the default_backend config. Allowed values:
      +
    • basic for basic authentication

    • +
    • oidc for OpenID Connect authentication

    • +
    • off (default) for no authentication

    • +
    +
    +
    +

    Also see Default openEO back-end URL and auto-authentication

    +

    Connection

    auto_authenticate

    Automatically authenticate in openeo.connect(). +Allowed values: see default_backend.auto_authenticate. +Also see Default openEO back-end URL and auto-authentication

    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/ard.html b/cookbook/ard.html new file mode 100644 index 000000000..527773dd9 --- /dev/null +++ b/cookbook/ard.html @@ -0,0 +1,232 @@ + + + + + + + + Analysis Ready Data generation — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Analysis Ready Data generation

    +

    For certain use cases, the preprocessed data collections available in the openEO back-ends are not sufficient or simply not +available. For that case, openEO supports a few very common preprocessing scenario:

    +
      +
    • Atmospheric correction of optical data

    • +
    • SAR backscatter computation

    • +
    +

    These processes also offer a number of parameters to customize the processing. There’s also variants with a default +parametrization that results in data that is compliant with CEOS CARD4L specifications https://ceos.org/ard/.

    +

    We should note that these operations can be computationally expensive, so certainly affect overall processing time and +cost of your final algorithm. Hence, make sure to make an informed decision when you decide to use these methods.

    +
    +

    Atmospheric correction

    +

    The atmospheric correction process can apply a chosen +method on raw ‘L1C’ data. The supported methods and input datasets depend on the back-end, because not every method is +validated or works on any dataset, and different back-ends try to offer a variety of options. This gives you as a user +more options to run and compare different methods, and select the most suitable one for your case.

    +

    To perform an atmospheric correction, the user has to +load an uncorrected L1C optical dataset. On the resulting datacube, the atmospheric_correction() +method can be invoked. Note that it may not be possible to apply certain processes to the raw input data: preprocessing +algorithms can be tightly coupled with the raw data, making it hard or impossible for the back-end to perform operations +in between loading and correcting the data.

    +

    The CARD4L variant of this process is: ard_surface_reflectance(). This process follows +CEOS specifications, and thus can additional processing steps, like a BRDF correction, that are not yet available as a +separate process.

    +
    +

    Reference implementations

    +

    This section shows a few working examples for these processes.

    +
    +

    EODC back-end

    +

    EODC (https://openeo.eodc.eu/v1.0) supports ard_surface_reflectance, based on the FORCE toolbox. (https://github.com/davidfrantz/force)

    +
    +
    +

    Geotrellis back-end

    +

    The geotrellis back-end (https://openeo.vito.be) supports atmospheric_correction() with iCor and SMAC as methods. +The version of iCor only offers basic atmoshperic correction features, without special options for water products: https://remotesensing.vito.be/case/icor +SMAC is implemented based on: https://github.com/olivierhagolle/SMAC +Both methods have been tested with Sentinel-2 as input. The viewing and sun angles need to be selected by the user to make them +available for the algorithm.

    +

    This is an example of applying iCor:

    +
    l1c = connection.load_collection("SENTINEL2_L1C_SENTINELHUB",
    +        spatial_extent={'west':3.758216409030558,'east':4.087806252,'south':51.291835566,'north':51.3927399},
    +        temporal_extent=["2017-03-07","2017-03-07"],bands=['B04','B03','B02','B09','B8A','B11','sunAzimuthAngles','sunZenithAngles','viewAzimuthMean','viewZenithMean'] )
    +l1c.atmospheric_correction(method="iCor").download("rgb-icor.geotiff",format="GTiff")
    +
    +
    +
    +
    +
    +
    +

    SAR backscatter

    +

    Data from synthetic aperture radar sensors requires significant preprocessing to be calibrated and normalized for terrain. +This is referred to as backscatter computation, and supported by +sar_backscatter and the CARD4L compliant variant +ard_normalized_radar_backscatter

    +

    The user should load a datacube containing raw SAR data, such as Sentinel-1 GRD. On the resulting datacube, the +sar_backscatter() method can be invoked. The CEOS CARD4L variant is: +ard_normalized_radar_backscatter(). These processes are tightly coupled to +metadata from specific sensors, so it is not possible to apply other processes to the datacube first, +with the exception of specifying filters in space and time.

    +
    +

    Reference implementations

    +

    This section shows a few working examples for these processes.

    +
    +

    EODC back-end

    +

    EODC (https://openeo.eodc.eu/v1.0) supports sar_backscatter, based on the Sentinel-1 toolbox. (https://sentinel.esa.int/web/sentinel/toolboxes/sentinel-1)

    +
    +
    +

    Geotrellis back-end

    +

    When working with the Sentinelhub SENTINEL1_GRD collection, both sar processes can be used. The underlying implementation is +provided by Sentinelhub, (https://docs.sentinel-hub.com/api/latest/data/sentinel-1-grd/#processing-options), and offers full +CARD4L compliant processing options.

    +

    This is an example of ard_normalized_radar_backscatter():

    +
    s1grd = (connection.load_collection('SENTINEL1_GRD', bands=['VH', 'VV'])
    + .filter_bbox(west=2.59003, east=2.8949, north=51.2206, south=51.069)
    + .filter_temporal(extent=["2019-10-10","2019-10-10"]))
    +
    +job = s1grd.ard_normalized_radar_backscatter().execute_batch()
    +
    +for asset in job.get_results().get_assets():
    +    asset.download()
    +
    +
    +

    When working with other GRD data, an implementation based on Orfeo Toolbox is used:

    + +

    The Orfeo implementation currently only supports sigma0 computation, and is not CARD4L compliant.

    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/index.html b/cookbook/index.html new file mode 100644 index 000000000..88fe82897 --- /dev/null +++ b/cookbook/index.html @@ -0,0 +1,215 @@ + + + + + + + + openEO CookBook — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/job_manager.html b/cookbook/job_manager.html new file mode 100644 index 000000000..5ffb96f6b --- /dev/null +++ b/cookbook/job_manager.html @@ -0,0 +1,316 @@ + + + + + + + + Multi Backend Job Manager — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Multi Backend Job Manager

    +
    +

    Warning

    +

    This is a new experimental API, subject to change.

    +
    +
    +
    +class openeo.extra.job_management.MultiBackendJobManager(poll_sleep=60, root_dir='.')[source]
    +

    Tracker for multiple jobs on multiple backends.

    +

    Usage example:

    +
    import pandas as pd
    +import openeo
    +from openeo.extra.job_management import MultiBackendJobManager
    +
    +manager = MultiBackendJobManager()
    +manager.add_backend("foo", connection=openeo.connect("http://foo.test"))
    +manager.add_backend("bar", connection=openeo.connect("http://bar.test"))
    +
    +jobs_df = pd.DataFrame(...)
    +output_file = "jobs.csv"
    +
    +def start_job(
    +    row: pd.Series,
    +    connection: openeo.Connection,
    +    **kwargs
    +) -> openeo.BatchJob:
    +    year = row["year"]
    +    cube = connection.load_collection(
    +        ...,
    +        temporal_extent=[f"{year}-01-01", f"{year+1}-01-01"],
    +    )
    +    ...
    +    return cube.create_job(...)
    +
    +manager.run_jobs(df=jobs_df, start_job=start_job, output_file=output_file)
    +
    +
    +

    See run_jobs() for more information on the start_job callable.

    +
    +

    New in version 0.14.0.

    +
    +
    +
    +add_backend(name, connection, parallel_jobs=2)[source]
    +

    Register a backend with a name and a Connection getter.

    +
    +
    Parameters:
    +
      +
    • name (str) – Name of the backend.

    • +
    • connection (Union[Connection, Callable[[], Connection]]) – Either a Connection to the backend, or a callable to create a backend connection.

    • +
    • parallel_jobs (int) – Maximum number of jobs to allow in parallel on a backend.

    • +
    +
    +
    +
    + +
    +
    +ensure_job_dir_exists(job_id)[source]
    +

    Create the job folder if it does not exist yet.

    +
    +
    Return type:
    +

    Path

    +
    +
    +
    + +
    +
    +get_error_log_path(job_id)[source]
    +

    Path where error log file for the job is saved.

    +
    +
    Return type:
    +

    Path

    +
    +
    +
    + +
    +
    +get_job_dir(job_id)[source]
    +

    Path to directory where job metadata, results and error logs are be saved.

    +
    +
    Return type:
    +

    Path

    +
    +
    +
    + +
    +
    +get_job_metadata_path(job_id)[source]
    +

    Path where job metadata file is saved.

    +
    +
    Return type:
    +

    Path

    +
    +
    +
    + +
    +
    +on_job_done(job, row)[source]
    +

    Handles jobs that have finished. Can be overridden to provide custom behaviour.

    +

    Default implementation downloads the results into a folder containing the title.

    +
    +
    Parameters:
    +
      +
    • job (BatchJob) – The job that has finished.

    • +
    • row – DataFrame row containing the job’s metadata.

    • +
    +
    +
    +
    + +
    +
    +on_job_error(job, row)[source]
    +

    Handles jobs that stopped with errors. Can be overridden to provide custom behaviour.

    +

    Default implementation writes the error logs to a JSON file.

    +
    +
    Parameters:
    +
      +
    • job (BatchJob) – The job that has finished.

    • +
    • row – DataFrame row containing the job’s metadata.

    • +
    +
    +
    +
    + +
    +
    +run_jobs(df, start_job, output_file)[source]
    +

    Runs jobs, specified in a dataframe, and tracks parameters.

    +
    +
    Parameters:
    +
      +
    • df (DataFrame) – DataFrame that specifies the jobs, and tracks the jobs’ statuses.

    • +
    • start_job (Callable[[], BatchJob]) –

      A callback which will be invoked with, amongst others, +the row of the dataframe for which a job should be created and/or started. +This callable should return a openeo.rest.job.BatchJob object.

      +

      The following parameters will be passed to start_job:

      +
      +
      +
      row (pandas.Series):

      The row in the pandas dataframe that stores the jobs state and other tracked data.

      +
      +
      connection_provider:

      A getter to get a connection by backend name. +Typically, you would need either the parameter connection_provider, +or the parameter connection, but likely you will not need both.

      +
      +
      connection (Connection):

      The Connection itself, that has already been created. +Typically, you would need either the parameter connection_provider, +or the parameter connection, but likely you will not need both.

      +
      +
      provider (str):

      The name of the backend that will run the job.

      +
      +
      +
      +

      You do not have to define all the parameters described below, but if you leave +any of them out, then remember to include the *args and **kwargs parameters. +Otherwise you will have an exception because run_jobs() passes unknown parameters to start_job.

      +

    • +
    • output_file (Union[str, Path]) – Path to output file (CSV) containing the status and metadata of the jobs.

    • +
    +
    +
    +
    + +
    + +
    +
    +openeo.extra.job_management.ignore_connection_errors(context=None)[source]
    +

    Context manager to ignore connection errors.

    +
    + +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/localprocessing.html b/cookbook/localprocessing.html new file mode 100644 index 000000000..75eeb9625 --- /dev/null +++ b/cookbook/localprocessing.html @@ -0,0 +1,302 @@ + + + + + + + + Client-side (local) processing — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Client-side (local) processing

    +
    +

    Warning

    +

    This is a new experimental feature and API, subject to change.

    +
    +
    +

    Background

    +

    The client-side processing functionality allows to test and use openEO with its processes locally, i.e. without any connection to an openEO back-end. +It relies on the projects openeo-pg-parser-networkx, which provides an openEO process graph parsing tool, and openeo-processes-dask, which provides an Xarray and Dask implementation of most openEO processes.

    +
    +
    +

    Installation

    +
    +

    Note

    +

    This feature requires Python>=3.9. +Tested with openeo-pg-parser-networkx==2023.5.1 and +openeo-processes-dask==2023.7.1.

    +
    +
    pip install openeo[localprocessing]
    +
    +
    +
    +
    +

    Usage

    +

    Every openEO process graph relies on data which is typically provided by a cloud infrastructure (the openEO back-end). +The client-side processing adds the possibility to read and use local netCDFs, geoTIFFs, ZARR files, and remote STAC Collections or Items for your experiments.

    +
    +

    STAC Collections and Items

    +
    +

    Warning

    +

    The provided examples using STAC rely on third party STAC Catalogs, we can’t guarantee that the urls will remain valid.

    +
    +

    With the load_stac process it’s possible to load and use data provided by remote or local STAC Collections or Items. +The following code snippet loads Sentinel-2 L2A data from a public STAC Catalog, using specific spatial and temporal extent, band name and also properties for cloud coverage.

    +
    >>> from openeo.local import LocalConnection
    +>>> local_conn = LocalConnection("./")
    +
    +>>> url = "https://earth-search.aws.element84.com/v1/collections/sentinel-2-l2a"
    +>>> spatial_extent = {"west": 11, "east": 12, "south": 46, "north": 47}
    +>>> temporal_extent = ["2019-01-01", "2019-06-15"]
    +>>> bands = ["red"]
    +>>> properties = {"eo:cloud_cover": dict(lt=50)}
    +>>> s2_cube = local_conn.load_stac(url=url,
    +...    spatial_extent=spatial_extent,
    +...    temporal_extent=temporal_extent,
    +...    bands=bands,
    +...    properties=properties,
    +... )
    +>>> s2_cube.execute()
    +<xarray.DataArray 'stackstac-08730b1b5458a4ed34edeee60ac79254' (time: 177,
    +                                                                band: 1,
    +                                                                y: 11354,
    +                                                                x: 8025)>
    +dask.array<getitem, shape=(177, 1, 11354, 8025), dtype=float64, chunksize=(1, 1, 1024, 1024), chunktype=numpy.ndarray>
    +Coordinates: (12/53)
    +  * time                                     (time) datetime64[ns] 2019-01-02...
    +    id                                       (time) <U24 'S2B_32TPR_20190102_...
    +  * band                                     (band) <U3 'red'
    +  * x                                        (x) float64 6.52e+05 ... 7.323e+05
    +  * y                                        (y) float64 5.21e+06 ... 5.096e+06
    +    s2:product_uri                           (time) <U65 'S2B_MSIL2A_20190102...
    +    ...                                       ...
    +    raster:bands                             object {'nodata': 0, 'data_type'...
    +    gsd                                      int32 10
    +    common_name                              <U3 'red'
    +    center_wavelength                        float64 0.665
    +    full_width_half_max                      float64 0.038
    +    epsg                                     int32 32632
    +Attributes:
    +    spec:        RasterSpec(epsg=32632, bounds=(600000.0, 4990200.0, 809760.0...
    +    crs:         epsg:32632
    +    transform:   | 10.00, 0.00, 600000.00|\n| 0.00,-10.00, 5300040.00|\n| 0.0...
    +    resolution:  10.0
    +
    +
    +
    +
    +

    Local Collections

    +

    If you want to use our sample data, please clone this repository:

    +
    git clone https://github.com/Open-EO/openeo-localprocessing-data.git
    +
    +
    +

    With some sample data we can now check the STAC metadata for the local files by doing:

    +
    from openeo.local import LocalConnection
    +local_data_folders = [
    +    "./openeo-localprocessing-data/sample_netcdf",
    +    "./openeo-localprocessing-data/sample_geotiff",
    +]
    +local_conn = LocalConnection(local_data_folders)
    +local_conn.list_collections()
    +
    +
    +

    This code will parse the metadata content of each netCDF, geoTIFF or ZARR file in the provided folders and return a JSON object containing the STAC representation of the metadata. +If this code is run in a Jupyter Notebook, the metadata will be rendered nicely.

    +
    +

    Tip

    +

    The code expects local files to have a similar structure to the sample files provided here. +If the code can not handle you special netCDF, you can still modify the function that reads the metadata from it here and the function that reads the data here.

    +
    +
    +
    +

    Local Processing

    +

    Let’s start with the provided sample netCDF of Sentinel-2 data:

    +
    >>> local_collection = "openeo-localprocessing-data/sample_netcdf/S2_L2A_sample.nc"
    +>>> s2_datacube = local_conn.load_collection(local_collection)
    +>>> # Check if the data is loaded correctly
    +>>> s2_datacube.execute()
    +<xarray.DataArray (bands: 5, t: 12, y: 705, x: 935)>
    +dask.array<stack, shape=(5, 12, 705, 935), dtype=float32, chunksize=(1, 12, 705, 935), chunktype=numpy.ndarray>
    +Coordinates:
    +  * t        (t) datetime64[ns] 2022-06-02 2022-06-05 ... 2022-06-27 2022-06-30
    +  * x        (x) float64 6.75e+05 6.75e+05 6.75e+05 ... 6.843e+05 6.843e+05
    +  * y        (y) float64 5.155e+06 5.155e+06 5.155e+06 ... 5.148e+06 5.148e+06
    +    crs      |S1 ...
    +  * bands    (bands) object 'B04' 'B03' 'B02' 'B08' 'SCL'
    +Attributes:
    +    Conventions:  CF-1.9
    +    institution:  openEO platform - Geotrellis backend: 0.9.5a1
    +    description:
    +    title:
    +
    +
    +

    As you can see in the previous example, we are using a call to execute() which will execute locally the generated openEO process graph. +In this case, the process graph consist only in a single load_collection, which performs lazy loading of the data. With this first step you can check if the data is being read correctly by openEO.

    +

    Looking at the metadata of this netCDF sample, we can see that it contains the bands B04, B03, B02, B08 and SCL. +Additionally, we also see that it is composed by more than one element in time and that it covers the month of June 2022.

    +

    We can now do a simple processing for demo purposes, let’s compute the median NDVI in time and visualize the result:

    +
    b04 = s2_datacube.band("B04")
    +b08 = s2_datacube.band("B08")
    +ndvi = (b08 - b04) / (b08 + b04)
    +ndvi_median = ndvi.reduce_dimension(dimension="t", reducer="median")
    +result_ndvi = ndvi_median.execute()
    +result_ndvi.plot.imshow(cmap="Greens")
    +
    +
    +../_images/local_ndvi.jpg +

    We can perform the same example using data provided by STAC Collection:

    +
    from openeo.local import LocalConnection
    +local_conn = LocalConnection("./")
    +
    +url = "https://earth-search.aws.element84.com/v1/collections/sentinel-2-l2a"
    +spatial_extent =  {"east": 11.40, "north": 46.52, "south": 46.46, "west": 11.25}
    +temporal_extent = ["2022-06-01", "2022-06-30"]
    +bands = ["red", "nir"]
    +properties = {"eo:cloud_cover": dict(lt=80)}
    +s2_datacube = local_conn.load_stac(
    +    url=url,
    +    spatial_extent=spatial_extent,
    +    temporal_extent=temporal_extent,
    +    bands=bands,
    +    properties=properties,
    +)
    +
    +b04 = s2_datacube.band("red")
    +b08 = s2_datacube.band("nir")
    +ndvi = (b08 - b04) / (b08 + b04)
    +ndvi_median = ndvi.reduce_dimension(dimension="time", reducer="median")
    +result_ndvi = ndvi_median.execute()
    +
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/sampling.html b/cookbook/sampling.html new file mode 100644 index 000000000..45fd2b435 --- /dev/null +++ b/cookbook/sampling.html @@ -0,0 +1,191 @@ + + + + + + + + Dataset sampling — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Dataset sampling

    +

    Tested on:

    +
      +
    • Terrascope

    • +
    • Copernicus Dataspace Ecosystem

    • +
    +

    A number of use cases do not require a full datacube to be computed, +but rather want to extract a result at specific locations. +Examples include extracting training data for model calibration, or computing the result for +areas where validation data is available.

    +

    Sampling can be done for points or polygons: +- point extractions basically result in a ‘vector cube’, so can be exported into tabular formats. +- polygon extractions can be stored to an individual netCDF per polygon so in this case the output is a sparse raster cube.

    +

    To indicate to openEO that we only want to compute the datacube for certain polygon features, we use the +filter_spatial() method.

    +

    Next to that, we will also indicate that we want to write multiple output files. This is more convenient, as we will +want to have one or more raster outputs per sampling feature, for convenient further processing. To do this, we set +the ‘sample_by_feature’ output format property, which is available for the netCDF and GTiff output formats.

    +

    Combining all of this, results in the following sample code:

    +
    s2_bands = auth_connection.load_collection(
    +    "TERRASCOPE_S2_TOC_V2",
    +    bands=["B04"],
    +    temporal_extent=["2020-05-01", "2020-06-01"],
    +)
    +s2_bands = s2_bands.filter_spatial(
    +    "https://artifactory.vgt.vito.be/testdata-public/parcels/test_10.geojson",
    +)
    +job = s2_bands.create_job(
    +    title="Sentinel2",
    +    description="Sentinel-2 L2A bands",
    +    out_format="netCDF",
    +    sample_by_feature=True,
    +)
    +
    +
    +

    Sampling only works for batch jobs, because it results in multiple output files, which can not be conveniently transferred +in a synchronous call.

    +
    +

    Performance & scalability

    +

    It’s important to note that dataset sampling is not necessarily a cheap operation, since creation of a sparse datacube still +may require accessing a large number of raw EO assets. Backends of course can and should optimize to restrict processing +to a minimum, but the size of the required input datasets is often a determining factor for cost and performance rather +than the size of the output dataset.

    +
    +
    +

    Sampling at scale

    +

    When doing large scale (e.g. continental) sampling, it is usually not possible or impractical to run it as a single openEO +batch job. The recommendation here is to apply a spatial grouping to your sampling locations, with a single group covering +an area of around 100x100km. The optimal size of a group may be backend dependant. Also remember that when working with +data in the UTM projection, you may want to avoid covering multiple UTM zones in a single group.

    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/spectral_indices.html b/cookbook/spectral_indices.html new file mode 100644 index 000000000..6d5077a67 --- /dev/null +++ b/cookbook/spectral_indices.html @@ -0,0 +1,448 @@ + + + + + + + + Spectral Indices — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Spectral Indices

    +
    +

    Warning

    +

    This is a new experimental API, subject to change.

    +
    +

    openeo.extra.spectral_indices is an auxiliary subpackage +to simplify the calculation of common spectral indices +used in various Earth observation applications (vegetation, water, urban etc.). +It leverages the spectral indices defined in the +Awesome Spectral Indices project +by David Montero Loaiza.

    +
    +

    New in version 0.9.1.

    +
    +
    +

    Band mapping

    +

    The formulas provided by “Awesome Spectral Indices” are defined in terms of standardized variable names +like “B” for blue, “R” for red, “N” for near-infrared, “WV” for water vapour, etc.

    +
    "NDVI": {
    +     "formula": "(N - R)/(N + R)",
    +     "long_name": "Normalized Difference Vegetation Index",
    +
    +
    +

    Obviously, these formula variables have to be mapped properly to the band names of your cube.

    +
    +

    Automatic band mapping

    +

    In most simple cases, when there is enough collection metadata +to automatically detect the satellite platform (Sentinel2, Landsat8, ..) +and the original band names haven’t been renamed, +this mapping will be handled automatically, e.g.:

    +
    cube = connection.load_collection("SENTINEL2_L2A", ...)
    +indices = compute_indices(cube, indices=["NDVI", "NDMI"])
    +
    +
    +
    +
    +

    Manual band mapping

    +

    In more complex cases, it might be necessary to specify some additional information to guide the band mapping. +If the band names follow the standard, but it’s just the satellite platform can not be guessed +from the collection metadata, it is typically enough to specify the platform explicitly:

    +
    indices = compute_indices(
    +    cube,
    +    indices=["NDVI", "NDMI"],
    +    platform="SENTINEL2",
    +)
    +
    +
    +

    Additionally, if the band names in your cube have been renamed, deviating from conventions, it is also +possible to explicitly specify the band name to spectral index variable name mapping:

    +
    indices = compute_indices(
    +    cube,
    +    indices=["NDVI", "NDMI"],
    +    variable_map={
    +        "R": "S2-red",
    +        "N": "S2-nir",
    +        "S1": "S2-swir",
    +    },
    +)
    +
    +
    +
    +

    New in version 0.26.0: Function arguments platform and variable_map to fine-tune the band mapping.

    +
    +
    +
    +
    +

    API

    +
    +
    +openeo.extra.spectral_indices.append_and_rescale_indices(datacube, index_dict, *, variable_map=None, platform=None)[source]
    +

    Computes a list of indices from a datacube and appends them to the existing datacube

    +
    +
    Parameters:
    +
      +
    • datacube (DataCube) – input data cube

    • +
    • index_dict (dict) –

      a dictionary that contains the input- and output range of the collection on which you calculate the indices +as well as the indices that you want to calculate with their responding input- and output ranges +It follows the following format:

      +
      {
      +    "collection": {
      +        "input_range": [0,8000],
      +        "output_range": [0,250]
      +    },
      +    "indices": {
      +        "NDVI": {
      +            "input_range": [-1,1],
      +            "output_range": [0,250]
      +        },
      +    }
      +}
      +
      +
      +

      See list_indices() for supported indices.

      +

    • +
    • variable_map (Optional[Dict[str, str]]) – (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. +To be specified if the given data cube has non-standard band names, +or the satellite platform can not be recognized from the data cube metadata. +See Manual band mapping for more information.

    • +
    • platform (Optional[str]) – optionally specify the satellite platform (to determine band name mapping) +if the given data cube has no or an unhandled collection id in its metadata. +See Manual band mapping for more information.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    data cube with appended indices

    +
    +
    +
    +

    Warning

    +

    this “rescaled” index helper uses an experimental API (e.g. index_dict argument) that is subject to change.

    +
    +
    +

    New in version 0.26.0: Added variable_map and platform arguments.

    +
    +
    + +
    +
    +openeo.extra.spectral_indices.append_index(datacube, index, *, variable_map=None, platform=None)[source]
    +

    Compute a single spectral index and append it to the given data cube.

    +
    +
    Parameters:
    +
      +
    • cube – input data cube

    • +
    • index (str) – name of the index to compute and append. See list_indices() for supported indices.

    • +
    • variable_map (Optional[Dict[str, str]]) – (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. +To be specified if the given data cube has non-standard band names, +or the satellite platform can not be recognized from the data cube metadata. +See Manual band mapping for more information.

    • +
    • platform (Optional[str]) – optionally specify the satellite platform (to determine band name mapping) +if the given data cube has no or an unhandled collection id in its metadata. +See Manual band mapping for more information.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    data cube with appended index

    +
    +
    +
    +

    New in version 0.26.0: Added variable_map and platform arguments.

    +
    +
    + +
    +
    +openeo.extra.spectral_indices.append_indices(datacube, indices, *, variable_map=None, platform=None)[source]
    +

    Compute multiple spectral indices and append them to the given data cube.

    +
    +
    Parameters:
    +
      +
    • datacube (DataCube) – input data cube

    • +
    • indices (List[str]) – list of names of the indices to compute and append. See list_indices() for supported indices.

    • +
    • variable_map (Optional[Dict[str, str]]) – (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. +To be specified if the given data cube has non-standard band names, +or the satellite platform can not be recognized from the data cube metadata. +See Manual band mapping for more information.

    • +
    • platform (Optional[str]) – optionally specify the satellite platform (to determine band name mapping) +if the given data cube has no or an unhandled collection id in its metadata. +See Manual band mapping for more information.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    data cube with appended indices

    +
    +
    +
    +

    New in version 0.26.0: Added variable_map and platform arguments.

    +
    +
    + +
    +
    +openeo.extra.spectral_indices.compute_and_rescale_indices(datacube, index_dict, *, append=False, variable_map=None, platform=None)[source]
    +

    Computes a list of indices from a data cube

    +
    +
    Parameters:
    +
      +
    • datacube (DataCube) – input data cube

    • +
    • index_dict (dict) –

      a dictionary that contains the input- and output range of the collection on which you calculate the indices +as well as the indices that you want to calculate with their responding input- and output ranges +It follows the following format:

      +
      {
      +    "collection": {
      +        "input_range": [0,8000],
      +        "output_range": [0,250]
      +    },
      +    "indices": {
      +        "NDVI": {
      +            "input_range": [-1,1],
      +            "output_range": [0,250]
      +        },
      +    }
      +}
      +
      +
      +

      If you don’t want to rescale your data, you can fill the input-, index- and output-range with None.

      +

      See list_indices() for supported indices.

      +

    • +
    • append (bool) – append the indices as bands to the given data cube +instead of creating a new cube with only the calculated indices

    • +
    • variable_map (Optional[Dict[str, str]]) – (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. +To be specified if the given data cube has non-standard band names, +or the satellite platform can not be recognized from the data cube metadata. +See Manual band mapping for more information.

    • +
    • platform (Optional[str]) – optionally specify the satellite platform (to determine band name mapping) +if the given data cube has no or an unhandled collection id in its metadata. +See Manual band mapping for more information.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    the datacube with the indices attached as bands

    +
    +
    +
    +

    Warning

    +

    this “rescaled” index helper uses an experimental API (e.g. index_dict argument) that is subject to change.

    +
    +
    +

    New in version 0.26.0: Added variable_map and platform arguments.

    +
    +
    + +
    +
    +openeo.extra.spectral_indices.compute_index(datacube, index, *, variable_map=None, platform=None)[source]
    +

    Compute a single spectral index from a data cube.

    +
    +
    Parameters:
    +
      +
    • datacube (DataCube) – input data cube

    • +
    • index (str) – name of the index to compute. See list_indices() for supported indices.

    • +
    • variable_map (Optional[Dict[str, str]]) – (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. +To be specified if the given data cube has non-standard band names, +or the satellite platform can not be recognized from the data cube metadata. +See Manual band mapping for more information.

    • +
    • platform (Optional[str]) – optionally specify the satellite platform (to determine band name mapping) +if the given data cube has no or an unhandled collection id in its metadata. +See Manual band mapping for more information.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    data cube containing the index as band

    +
    +
    +
    +

    New in version 0.26.0: Added variable_map and platform arguments.

    +
    +
    + +
    +
    +openeo.extra.spectral_indices.compute_indices(datacube, indices, *, append=False, variable_map=None, platform=None)[source]
    +

    Compute multiple spectral indices from the given data cube.

    +
    +
    Parameters:
    +
      +
    • datacube (DataCube) – input data cube

    • +
    • indices (List[str]) – list of names of the indices to compute and append. See list_indices() for supported indices.

    • +
    • append (bool) – append the indices as bands to the given data cube +instead of creating a new cube with only the calculated indices

    • +
    • variable_map (Optional[Dict[str, str]]) – (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. +To be specified if the given data cube has non-standard band names, +or the satellite platform can not be recognized from the data cube metadata. +See Manual band mapping for more information.

    • +
    • platform (Optional[str]) – optionally specify the satellite platform (to determine band name mapping) +if the given data cube has no or an unhandled collection id in its metadata. +See Manual band mapping for more information.

    • +
    +
    +
    Return type:
    +

    DataCube

    +
    +
    Returns:
    +

    data cube containing the indices as bands

    +
    +
    +
    +

    New in version 0.26.0: Added variable_map and platform arguments.

    +
    +
    + +
    +
    +openeo.extra.spectral_indices.list_indices()[source]
    +

    List names of supported spectral indices

    +
    +
    Return type:
    +

    List[str]

    +
    +
    +
    + +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/tricks.html b/cookbook/tricks.html new file mode 100644 index 000000000..cb80c223a --- /dev/null +++ b/cookbook/tricks.html @@ -0,0 +1,206 @@ + + + + + + + + Miscellaneous tips and tricks — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Miscellaneous tips and tricks

    +
    +

    Export a process graph

    +

    You can export the underlying process graph of +a DataCube, VectorCube, etc, +to a standardized JSON format, which allows interoperability with other openEO tools.

    +

    For example, use print_json() to directly print the JSON representation +in your interactive Jupyter or Python session:

    +
    >>> dump = cube.print_json()
    +{
    +  "process_graph": {
    +    "loadcollection1": {
    +      "process_id": "load_collection",
    +...
    +
    +
    +

    Or save it to a file, by getting the JSON representation first as a string +with to_json():

    +
    # Export as JSON string
    +dump = cube.to_json()
    +
    +# Write to file in `pathlib` style
    +export_path = pathlib.Path("path/to/export.json")
    +export_path.write_text(dump, encoding="utf8")
    +
    +# Write to file in `open()` style
    +with open("path/to/export.json", encoding="utf8") as f:
    +    f.write(dump)
    +
    +
    +
    +

    Warning

    +

    Avoid using methods like flat_graph(), +which are mainly intended for internal use. +Not only are these methods subject to change, they also lead to representations +with interoperability and reuse issues. +For example, naively printing or automatic (repr) rendering of +flat_graph() output will roughly look like JSON, +but is in fact invalid: it uses single quotes (instead of double quotes) +and booleans values are title-case (instead of lower case).

    +
    +
    +
    +

    Execute a process graph directly from raw JSON

    +

    When you have a process graph in JSON format, as a string, a local file or a URL, +you can execute/download it without converting it do a DataCube first. +Just pass the string, path or URL directly to +Connection.download(), +Connection.execute() or +Connection.create_job(). +For example:

    +
    # `execute` with raw JSON string
    +connection.execute("""
    +    {
    +        "add": {"process_id": "add", "arguments": {"x": 3, "y": 5}, "result": true}
    +    }
    +""")
    +
    +# `download` with local path to JSON file
    +connection.download("path/to/my-process-graph.json")
    +
    +# `create_job` with URL to JSON file
    +job = connection.create_job("https://jsonbin.example/my/process-graph.json")
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/cookbook/udp_sharing.html b/cookbook/udp_sharing.html new file mode 100644 index 000000000..e9e6e80be --- /dev/null +++ b/cookbook/udp_sharing.html @@ -0,0 +1,248 @@ + + + + + + + + Sharing of user-defined processes — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Sharing of user-defined processes

    +
    +

    Warning

    +

    Beta feature - +At the time of this writing (July 2021), sharing of user-defined processes +(publicly or among users) is not standardized in the openEO API. +There are however some experimental sharing features in the openEO Python Client Library +and some back-end providers that we are going to discuss here.

    +

    Be warned that the details of this feature are subject to change. +For more status information, consult GitHub ticket +Open-EO/openeo-api#310.

    +
    +
    +

    Publicly publishing a user-defined process.

    +

    As discussed in Building and storing user-defined process, user-defined processes can be +stored with the save_user_defined_process() method +on a on a back-end Connection. +By default, these user-defined processes are private and only accessible by the user that saved it:

    +
    from openeo.processes import subtract, divide
    +from openeo.api.process import Parameter
    +
    +# Build user-defined process
    +f = Parameter.number("f", description="Degrees Fahrenheit.")
    +fahrenheit_to_celsius = divide(x=subtract(x=f, y=32), y=1.8)
    +
    +# Store user-defined process in openEO back-end.
    +udp = connection.save_user_defined_process(
    +    "fahrenheit_to_celsius",
    +    fahrenheit_to_celsius,
    +    parameters=[f]
    +)
    +
    +
    +

    Some back-ends, like the VITO/Terrascope back-end allow a user to flag a user-defined process as “public” +so that other users can access its description and metadata:

    +
    udp = connection.save_user_defined_process(
    +    ...
    +    public=True
    +)
    +
    +
    +

    The sharable, public URL of this user-defined process is available from the metadata given by +RESTUserDefinedProcess.describe. +It’s listed as “canonical” link:

    +
    >>> udp.describe()
    +{
    +    "id": "fahrenheit_to_celsius",
    +    "links": [
    +        {
    +            "rel": "canonical",
    +            "href": "https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius",
    +            "title": "Public URL for user-defined process fahrenheit_to_celsius"
    +        }
    +    ],
    +    ...
    +
    +
    +
    +
    +

    Using a public UDP through URL based “namespace”

    +

    Some back-ends, like the VITO/Terrascope back-end, allow to use a public UDP +through setting its public URL as the namespace property of the process graph node.

    +

    For example, based on the fahrenheit_to_celsius UDP created above, +the “flat graph” representation of a process graph could look like this:

    +
    {
    +    ...
    +    "to_celsius": {
    +        "process_id": "fahrenheit_to_celsius",
    +        "namespace": "https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius",
    +        "arguments": {"f": 86}
    +    }
    +
    +
    +

    As a very basic illustration with the openEO Python Client library, +we can create and evaluate a process graph, +containing a fahrenheit_to_celsius call as single process, +with Connection.datacube_from_process as follows:

    +
    cube = connection.datacube_from_process(
    +    process_id="fahrenheit_to_celsius",
    +    namespace="https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius",
    +    f=86
    +)
    +print(cube.execute())
    +# Prints: 30.0
    +
    +
    +
    +
    +

    Loading a published user-defined process as DataCube

    +

    From the public URL of the user-defined process, +it is also possible for another user to construct, fully client-side, +a new DataCube +with Connection.datacube_from_json.

    +

    It is important to note that this approach is different from calling +a user-defined process as described in Evaluate user-defined processes and Using a public UDP through URL based “namespace”. +Connection.datacube_from_json +breaks open the encapsulation of the user-defined process and “unrolls” the process graph inside +into a new DataCube. +This also implies that parameters defined in the user-defined process have to be provided when calling +Connection.datacube_from_json

    +
    udp_url = "https://openeo.vito.be/openeo/1.0/processes/u:johndoe/fahrenheit_to_celsius"
    +cube = connection.datacube_from_json(udp_url, parameters={"f": 86})
    +print(cube.execute())
    +# Prints: 30.0
    +
    +
    +

    For more information, also see Construct DataCube from JSON.

    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/data_access.html b/data_access.html new file mode 100644 index 000000000..a0aa34e8d --- /dev/null +++ b/data_access.html @@ -0,0 +1,409 @@ + + + + + + + + Finding and loading data — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Finding and loading data

    +

    As illustrated in the basic concepts, most openEO scripts start with load_collection, but this skips the step of +actually finding out which collection to load. This section dives a bit deeper into finding the right data, and some more +advanced data loading use cases.

    +
    +

    Data discovery

    +

    To explore data in a given back-end, it is recommended to use a more visual tool like the openEO Hub +(http://hub.openeo.org/). This shows available collections, and metadata in a user-friendly manner.

    +

    Next to that, the client also offers various Connection methods +to explore collections and their metadata:

    + +

    When using these methods inside a Jupyter notebook, you should notice that the output is rendered in a user friendly way.

    +

    In a regular script, these methods can be used to programmatically find a collection that matches specific criteria.

    +

    As a user, make sure to carefully read the documentation for a given collection, as there can be important differences. +You should also be aware of the data retention policy of a given collection: some data archives only retain the last 3 months +for instance, making them only suitable for specific types of analysis. Such differences can have an impact on the reproducibility +of your openEO scripts.

    +

    Also note that the openEO metadata may use links to point to much more information for a particular collection. For instance +technical specification on how the data was preprocessed, or viewers that allow you to visually explore the data. This can +drastically improve your understanding of the dataset.

    +

    Finally, licensing information is important to keep an eye on: not all data is free and open.

    +
    +

    Initial exploration of an openEO collection

    +

    A common question from users is about very specific details of a collection, we’d like to list some examples and solutions here:

    +
      +
    • The collection data type, and range of values, can be determined by simply downloading a sample of data, as NetCDF or Geotiff. This can in fact be done at any point in the design of your script, to get a good idea of intermediate results.

    • +
    • Data availability, and available timestamps can be retrieved by computing average values for your area of interest. Just construct a polygon, and retrieve those statistics. For optical data, this can also be used to get an idea on cloud statistics.

    • +
    • Most collections have a native projection system, again a simple download will give you this information if its not clear from the metadata.

    • +
    +
    +
    +
    +

    Loading a data cube from a collection

    +

    Many examples already illustrate the basic openEO load_collection process through a Connection.load_collection() call, +with filters on space, time and bands. +For example:

    +
    cube = connection.load_collection(
    +    "SENTINEL2_L2A",
    +    spatial_extent={"west": 3.75, "east": 4.08, "south": 51.29, "north": 51.39},
    +    temporal_extent=["2021-05-07", "2021-05-14"],
    +    bands=["B04", "B03", "B02"],
    +)
    +
    +
    +

    The purpose of these filters in load_collection is to reduce the amount of raw data that is loaded (and processed) by the back-end. +This is essential to get a response to your processing request in reasonable time and keep processing costs low. +It’s recommended to start initial exploration with a small spatio-temporal extent +and gradually increase the scope once initial tests work out.

    +

    Next to specifying filters inside the load_collection process, +there are also possibilities to filter with separate filter processes, e.g. at a later stage in your process graph. +For most openEO back-ends, the following example snippet should be equivalent to the previous:

    +
    cube = connection.load_collection("SENTINEL2_L2A")
    +cube = cube.filter_bbox(west=3.75, east=4.08, south=51.29, north=51.39)
    +cube = cube.filter_temporal("2021-05-07", "2021-05-14")
    +cube = cube.filter_bands(["B04", "B03", "B02"])
    +
    +
    +

    Another nice feature is that processes that work with geometries or vector features +(e.g. aggregated statistics for a polygon, or masking by polygon) +can also be used by a back-end to automatically infer an appropriate spatial extent. +This way, you do not need to explicitly set these filters yourself.

    +

    In the following sections, we want to dive a bit into details, and more advanced cases.

    +
    +
    +

    Filter on spatial extent

    +

    A spatial extent is a bounding box that specifies the minimum and and maximum longitude and latitude of the region of interest you want to process.

    +

    By default these latitude and longitude values are expressed in the standard Coordinate Reference System for the world, which is EPSG:4623, also known as “WGS 84”, or just “lat-long”.

    +
    connection.load_collection(
    +    ...,
    +    spatial_extent={"west": 5.14, "south": 51.17, "east": 5.17, "north": 51.19},
    +)
    +
    +
    +
    +
    +

    Filter on temporal extent

    +

    Usually you don’t need the complete time range provided by a collection +and you should specify an appropriate time window to load +as a temporal_extent pair containing a start and end date:

    +
    connection.load_collection(
    +    ...,
    +    temporal_extent=["2021-05-07", "2021-05-14"],
    +)
    +
    +
    +

    In most use cases, day-level granularity is enough and you can just express the dates as strings in the format "yyyy-mm-dd". +You can also pass datetime.date objects (from Python standard library) if you already have your dates in that format.

    +
    +

    Note

    +

    When you need finer, time-level granularity, you can pass datetime.datetime objects. +Or, when passed as a string, the openEO API requires date and time to be provided in RFC 3339 format. +For example for for 2020-03-17 at 12:34:56 in UTC:

    +
    "2020-03-17T12:34:56Z"
    +
    +
    +
    +
    +

    Left-closed intervals: start included, end excluded

    +

    Time ranges in openEO processes like load_collection and filter_temporal are handled as left-closed (“half-open”) temporal intervals: +the start instant is included in the interval, but the end instant is excluded from the interval.

    +

    For example, the interval defined by ["2020-03-05", "2020-03-15"] covers observations +from 2020-03-05 up to (and including) 2020-03-14 (just before midnight), +but does not include observations from 2020-03-15.

    +
              2020-03-05                             2020-03-14   2022-03-15
    +________|____________|_________________________|____________|____________|_____
    +
    +        [--------------------------------------------------(O
    +    including                                           excluding
    +2020-03-05 00:00:00.000                             2020-03-15 00:00:00.000
    +
    +
    +

    While this might look unintuitive at first, +working with half-open intervals avoids common and hard to discover pitfalls when combining multiple intervals, +like unintended window overlaps or double counting observations at interval borders.

    +
    +
    +

    Year/month shorthand notation

    +
    +

    Note

    +

    Year/month shorthand notation handling is available since version 0.23.0.

    +
    +
    +

    Rounding down periods to dates

    +

    The openEO Python Client Library supports some shorthand notations for the temporal extent, +which come in handy if you work with year/month based temporal intervals. +Date strings that only consist of a year or a month will be automatically +“rounded down” to the first day of that period. For example:

    +
    "2023"    -> "2023-01-01"
    +"2023-08" -> "2023-08-01"
    +
    +
    +

    This approach fits best with left-closed interval handling.

    +

    For example, the following two load_collection calls are equivalent:

    +
    # Filter for observations in 2021 (left-closed interval).
    +connection.load_collection(temporal_extent=["2021", "2022"], ...)
    +# The above is shorthand for:
    +connection.load_collection(temporal_extent=["2021-01-01", "2022-01-01"], ...)
    +
    +
    +

    The same applies for filter_temporal(), +which has a couple of additional call forms. +All these calls are equivalent:

    +
    # Filter for March, April and May (left-closed interval)
    +cube = cube.filter_temporal("2021-03", "2021-06")
    +cube = cube.filter_temporal(["2021-03", "2021-06"])
    +cube = cube.filter_temporal(start_date="2021-03", end_date="2021-06")
    +cube = cube.filter_temporal(extent=("2021-03", "2021-06"))
    +
    +# The above are shorthand for:
    +cube = cube.filter_temporal("2021-03-01", "2022-06-01")
    +
    +
    +
    +
    +

    Single string temporal extents

    +

    Apart from rounding down year or month string, the openEO Python Client Library provides an additional +extent handling feature in methods like +Connection.load_collection(temporal_extent=...) +and DataCube.filter_temporal(extent=...). +Normally, the extent argument should be a list or tuple containing start and end date, +but if a single string is given, representing a year, month (or day) period, +it is automatically expanded to the appropriate interval, +again following the left-closed interval principle. +For example:

    +
    extent="2022"        ->  extent=("2022-01-01", "2023-01-01")
    +extent="2022-05"     ->  extent=("2022-05-01", "2022-06-01")
    +extent="2022-05-17"  ->  extent=("2022-05-17", "2022-05-18")
    +
    +
    +

    The following snippet shows some examples of equivalent calls:

    +
    connection.load_collection(temporal_extent="2022", ...)
    +# The above is shorthand for:
    +connection.load_collection(temporal_extent=("2022-01-01", "2023-01-01"), ...)
    +
    +
    +cube = cube.filter_temporal(extent="2021-03")
    +# The above are shorthand for:
    +cube = cube.filter_temporal(extent=("2021-03-01", "2022-04-01"))
    +
    +
    +
    +
    +
    +
    +

    Filter on collection properties

    +

    Although openEO presents data in a data cube, a lot of collections are still backed by a product based catalog. This +allows filtering on properties of that catalog.

    +

    A very common use case is to pre-filter Sentinel-2 products on cloud cover. +This avoids loading clouded data unnecessarily and increases performance. +Connection.load_collection() provides +a dedicated max_cloud_cover argument (shortcut for the eo:cloud_cover property) for that:

    +
    connection.load_collection(
    +    "SENTINEL2_L2A",
    +    ...,
    +    max_cloud_cover=80,
    +)
    +
    +
    +

    For more general cases, you can use the properties argument to filter on any collection property. +For example, to filter on the relative orbit number of SAR data:

    +
    connection.load_collection(
    +    "SENTINEL1_GRD",
    +    ...,
    +    properties={
    +        "relativeOrbitNumber": lambda x: x==116
    +    },
    +)
    +
    +
    +

    Version 0.26.0 of the openEO Python Client Library adds +collection_property() +which makes defining such property filters more user-friendly by avoiding the lambda construct:

    +
    import openeo
    +
    +connection.load_collection(
    +    "SENTINEL1_GRD",
    +    ...,
    +    properties=[
    +        openeo.collection_property("relativeOrbitNumber") == 116,
    +    ],
    +)
    +
    +
    +

    Note that property names follow STAC metadata conventions, but some collections can have different names.

    +

    Property filters in openEO are also specified by small process graphs, that allow the use of the same generic processes +defined by openEO. This is the ‘lambda’ process that you see in the property dictionary. Do note that not all processes +make sense for product filtering, and can not always be properly translated into the query language of the catalog. +Hence, some experimentation may be needed to find a filter that works.

    +

    One important caveat in this example is that ‘relativeOrbitNumber’ is a catalog specific property name. Meaning that +different archives may choose a different name for a given property, and the properties that are available can depend +on the collection and the catalog that is used by it. This is not a problem caused by openEO, but by the limited +standardization between catalogs of EO data.

    +
    +
    +

    Handling large vector data sets

    +

    For simple use cases, it is common to directly embed geometries (vector data) in your openEO process graph. +Unfortunately, with large vector data sets this leads to very large process graphs +and you might hit certain limits, +resulting in HTTP errors like 413 Request Entity Too Large or 413 Payload Too Large.

    +

    This problem can be circumvented by first uploading your vector data to a file sharing service +(like Google Drive, DropBox, GitHub, …) +and use its public URL in the process graph instead +through Connection.vectorcube_from_paths. +For example, as follows:

    +
    # Load vector data from URL
    +url = "https://github.com/Open-EO/openeo-python-client/raw/master/tests/data/example_aoi.pq"
    +parcels = connection.vectorcube_from_paths([url], format="parquet")
    +
    +# Use the parcel vector data, for example to do aggregation.
    +cube = connection.load_collection(
    +    "SENTINEL2_L2A",
    +    bands=["B04", "B03", "B02"],
    +    temporal_extent=["2021-05-12", "2021-06-01"],
    +)
    +aggregations = cube.aggregate_spatial(
    +    geometries=parcels,
    +    reducer="mean",
    +)
    +
    +
    +

    Note that while openEO back-ends typically support multiple vector formats, like GeoJSON and GeoParquet, +it is usually recommended to use a compact format like GeoParquet, instead of GeoJSON. The list of supported formats +is also advertised by the backend, and can be queried with +Connection.list_file_formats.

    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/datacube_construction.html b/datacube_construction.html new file mode 100644 index 000000000..af248f7a4 --- /dev/null +++ b/datacube_construction.html @@ -0,0 +1,294 @@ + + + + + + + + DataCube construction — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    DataCube construction

    +
    +

    The load_collection process

    +

    The most straightforward way to start building your openEO data cube is through the load_collection process. +As mentioned earlier, this is provided by the +load_collection() method +on a Connection object, +which produces a DataCube instance. +For example:

    +
    cube = connection.load_collection("SENTINEL2_TOC")
    +
    +
    +

    While this should cover the majority of use cases, +there some cases +where one wants to build a DataCube object +from something else or something more than just a simple load_collection process.

    +
    +
    +

    Construct DataCube from process

    +

    Through user-defined processes one can encapsulate +one or more load_collection processes and additional processing steps in a single +reusable user-defined process. +For example, imagine a user-defined process “masked_s2” +that loads an openEO collection “SENTINEL2_TOC” and applies some kind of cloud masking. +The implementation details of the cloud masking are not important here, +but let’s assume there is a parameter “dilation” to fine-tune the cloud mask. +Also note that the collection id “SENTINEL2_TOC” is hardcoded in the user-defined process.

    +

    We can now construct a data cube from this user-defined process +with datacube_from_process() +as follows:

    +
    cube = connection.datacube_from_process("masked_s2", dilation=10)
    +
    +# Further processing of the cube:
    +cube = cube.filter_temporal("2020-09-01", "2020-09-10")
    +
    +
    +

    Note that datacube_from_process() can be +used with all kind of processes, not only user-defined processes. +For example, while this is not exactly a real EO data use case, +it will produce a valid openEO process graph that can be executed:

    +
    >>> cube = connection.datacube_from_process("mean", data=[2, 3, 5, 8])
    +>>> cube.execute()
    +4.5
    +
    +
    +
    +
    +

    Construct DataCube from JSON

    +

    openEO process graphs are typically stored and published in JSON format. +Most notably, user-defined processes are transferred between openEO client +and back-end in a JSON structure roughly like in this example:

    +
    {
    +  "id": "evi",
    +  "parameters": [
    +    {"name": "red", "schema": {"type": "number"}},
    +    {"name": "blue", "schema": {"type": "number"}},
    +    ...
    +  ],
    +  "process_graph": {
    +    "sub": {"process_id": "subtract", "arguments": {"x": {"from_parameter": "nir"}, "y": {"from_parameter": "red"}}},
    +    "p1": {"process_id": "multiply", "arguments": {"x": 6, "y": {"from_parameter": "red"}}},
    +    "div": {"process_id": "divide", "arguments": {"x": {"from_node": "sub"}, "y": {"from_node": "sum"}},
    +    ...
    +
    +
    +

    It is possible to construct a DataCube object that corresponds with this +process graph with the Connection.datacube_from_json method. +It can be given one of:

    +
    +
      +
    • a raw JSON string,

    • +
    • a path to a local JSON file,

    • +
    • an URL that points to a JSON resource

    • +
    +
    +

    The JSON structure should be one of:

    +
    +
      +
    • a mapping (dictionary) like the example above with at least a "process_graph" item, +and optionally a "parameters" item.

    • +
    • a mapping (dictionary) with {"process_id": ...} items

    • +
    +
    +
    +

    Some examples

    +

    Load a DataCube from a raw JSON string, containing a +simple “flat graph” representation:

    +
    raw_json = '''{
    +    "lc": {"process_id": "load_collection", "arguments": {"id": "SENTINEL2_TOC"}},
    +    "ak": {"process_id": "apply_kernel", "arguments": {"data": {"from_node": "lc"}, "kernel": [[1,2,1],[2,5,2],[1,2,1]]}, "result": true}
    +}'''
    +cube = connection.datacube_from_json(raw_json)
    +
    +
    +

    Load from a raw JSON string, containing a mapping with “process_graph” and “parameters”:

    +
    raw_json = '''{
    +    "parameters": [
    +        {"name": "kernel", "schema": {"type": "array"}, "default": [[1,2,1], [2,5,2], [1,2,1]]}
    +    ],
    +    "process_graph": {
    +        "lc": {"process_id": "load_collection", "arguments": {"id": "SENTINEL2_TOC"}},
    +        "ak": {"process_id": "apply_kernel", "arguments": {"data": {"from_node": "lc"}, "kernel": {"from_parameter": "kernel"}}, "result": true}
    +    }
    +}'''
    +cube = connection.datacube_from_json(raw_json)
    +
    +
    +

    Load directly from a file or URL containing these kind of JSON representations:

    +
    cube = connection.datacube_from_json("path/to/my_udp.json")
    +
    +cube = connection.datacube_from_json("https://openeo.example/process_graphs/my_udp")
    +
    +
    +
    +
    +

    Parameterization

    +

    When the process graph uses parameters, you must specify the desired parameter values +at the time of calling Connection.datacube_from_json.

    +

    For example, take this simple toy example of a process graph that takes the sum of 5 and a parameter “increment”:

    +
    raw_json = '''{"add": {
    +    "process_id": "add",
    +    "arguments": {"x": 5, "y": {"from_parameter": "increment"}},
    +    "result": true
    +}}'''
    +
    +
    +

    Trying to build a DataCube from it without specifying parameter values will fail +like this:

    +
    >>> cube = connection.datacube_from_json(raw_json)
    +ProcessGraphVisitException: No substitution value for parameter 'increment'.
    +
    +
    +

    Instead, specify the parameter value:

    +
    >>> cube = connection.datacube_from_json(raw_json, parameters={"increment": 4})
    +>>> cube.execute()
    +9
    +
    +
    +

    Parameters can also be defined with default values, which will be used when they are not specified +in the Connection.datacube_from_json call:

    +
    raw_json = '''{
    +    "parameters": [
    +        {"name": "increment", "schema": {"type": "number"}, "default": 100}
    +    ],
    +    "process_graph": {
    +        "add": {"process_id": "add", "arguments": {"x": 5, "y": {"from_parameter": "increment"}}, "result": true}
    +    }
    +}'''
    +
    +cube = connection.datacube_from_json(raw_json)
    +result = cube.execute())
    +# result will be 105
    +
    +
    +
    +

    Re-parameterization

    +

    TODO

    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/development.html b/development.html new file mode 100644 index 000000000..bef89f5a5 --- /dev/null +++ b/development.html @@ -0,0 +1,516 @@ + + + + + + + + Development and maintenance — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Development and maintenance

    +

    For development on the openeo package itself, +it is recommended to install a local git checkout of the project +in development mode (-e) +with additional development related dependencies ([dev]) +like this:

    +
    pip install -e .[dev]
    +
    +
    +

    If you are on Windows and experience problems installing this way, you can find some solutions in section Development Installation on Windows.

    +
    +

    Running the unit tests

    +

    The test suite of the openEO Python Client leverages +the nice pytest framework. +It is installed automatically when installing the openEO Python Client +with the [dev] extra as shown above. +Running the whole tests is as simple as executing:

    +
    pytest
    +
    +
    +

    There are a ton of command line options for fine-tuning +(e.g. select a subset of tests, how results should be reported, …). +Run pytest -h for a quick overview +or check the pytest documentation for more information.

    +

    For example:

    +
    # Skip tests that are marked as slow
    +pytest -m "not slow"
    +
    +
    +
    +
    +

    Building the documentation

    +

    Building the documentation requires Sphinx +and some plugins +(which are installed automatically as part of the [dev] install).

    +
    +

    Quick and easy

    +

    The easiest way to build the documentation is working from the docs folder +and using the Makefile:

    +
    # From `docs` folder
    +make html
    +
    +
    +

    (assumes you have make available, if not: use python -msphinx -M html .  _build.)

    +

    This will generate the docs in HTML format under docs/_build/html/. +Open the HTML files manually, +or use Python’s built-in web server to host them locally, e.g.:

    +
    # From `docs` folder
    +python -m http.server 8000
    +
    +
    +

    Then, visit http://127.0.0.1:8000/_build/html/ in your browser

    +
    +
    +

    Like a Pro

    +

    When doing larger documentation work, it can be tedious to manually rebuild the docs +and refresh your browser to check the result. +Instead, use sphinx-autobuild +to automatically rebuild on documentation changes and live-reload it in your browser. +After installation (pip install sphinx-autobuild in your development environment), +just run

    +
    # From project root
    +sphinx-autobuild docs/ --watch openeo/ docs/_build/html/
    +
    +
    +

    and then visit http://127.0.0.1:8000 . +When you change (and save) documentation source files, your browser should now +automatically refresh and show the newly built docs. Just like magic.

    +
    +
    +
    +

    Contributing code

    +

    User contributions (such as bug fixes and new features, both in source code and documentation) +are greatly appreciated and welcome.

    +
    +

    Pull requests

    +

    We use a traditional GitHub Pull Request (PR) workflow +for user contributions, which roughly follows these steps:

    +
      +
    • Create a personal fork of https://github.com/Open-EO/openeo-python-client +(unless you already have push permissions to an existing fork or the original repo)

    • +
    • Preferably: work on your contribution in a new feature branch

    • +
    • Push your feature branch to your fork and create a pull request

    • +
    • The pull request is the place for review, discussion and fine-tuning of your work

    • +
    • Once your pull request is in good shape it will be merged by a maintainer

    • +
    +
    +
    +

    Pre-commit for basic code quality checks

    +

    We started using the pre-commit tool +for basic fine-tuning of code style and quality in new contributions. +It’s currently not enforced, but enabling pre-commit is recommended and appreciated +when contributing code.

    +
    +

    Note

    +

    Note that the whole repository does not fully follow all code styles rules at the moment. +We’re just gradually introducing it, piggybacking on new contributions and commits.

    +
    +
    +

    Pre-commit set up

    +
      +
    • Install the general pre-commit command line tool:

      +
        +
      • The simplest option is to install it directly in the virtual environment +you are using for openEO Python client development (e.g. pip install pre-commit).

      • +
      • You can also install it globally on your system +(e.g. using pipx, conda, homebrew, …) +so you can use it across different projects.

      • +
      +
    • +
    • Install the project specific git hook scripts by running this in the root of your local git clone:

      +
      pre-commit install
      +
      +
      +

      This will automatically install additional scripts and tools in a sandbox +to run the various checks defined in the project’s .pre-commit-config.yaml configuration file.

      +
    • +
    +
    +
    +

    Pre-commit usage

    +

    When you commit new changes, the freshly installed pre-commit hook +will now automatically run each of the configured linters/formatters/… +Some of these just flag issues (e.g. invalid JSON files) +while others even automatically fix problems (e.g. clean up excessive whitespace).

    +

    If there is some kind of violation, the commit will be blocked. +Address these problems and try to commit again.

    +
    +

    Attention

    +

    Some pre-commit tools directly edit your files (e.g. formatting tweaks) +instead of just flagging issues. +This might feel intrusive at first, but once you get the hang of it, +it should allow to streamline your workflow.

    +

    In particular, it is recommended to use the staging feature of git to prepare your commit. +Pre-commit’s proposed changes are not staged automatically, +so you can more easily keep them separate and review.

    +
    +
    +

    Tip

    +

    You can temporarily disable pre-commit for these rare cases +where you intentionally want to commit violating code style, +e.g. through git commit command line option -n/--no-verify.

    +
    +
    +
    +
    +
    +

    Creating a release

    +

    This section describes the procedure to create +properly versioned releases of the openeo package +that can be downloaded by end users (e.g. through pip from pypi.org) +and depended on by other projects.

    +

    The releases will end up on:

    + +
    +

    Prerequisites

    +
      +
    • You have permissions to push branches and tags and maintain releases on +the openeo-python-client project on GitHub.

    • +
    • You have permissions to upload releases to the +openeo project on pypi.org

    • +
    • The Python virtual environment you work in has the latest versions +of the twine package installed. +If you plan to build the wheel yourself (instead of letting GitHub or Jenkins do this), +you also need recent enough versions of the setuptools and wheel packages.

    • +
    +
    +
    +

    Important files

    +
    +
    setup.py

    describes the metadata of the package, +like package name openeo and version +(which is extracted from openeo/_version.py).

    +
    +
    openeo/_version.py

    defines the version of the package. +During general development, this version string should contain +a pre-release +segment (e.g. a1 for alpha releases, b1 for beta releases, etc) +to avoid collision with final releases. For example:

    +
    __version__ = '0.8.0a1'
    +
    +
    +

    As discussed below, this pre-release suffix should +only be removed during the release procedure +and restored when bumping the version after the release procedure.

    +
    +
    CHANGELOG.md

    keeps track of important changes associated with each release. +It follows the Keep a Changelog convention +and should be properly updated with each bug fix, feature addition/removal, … +under the Unreleased section during development.

    +
    +
    +
    +
    +

    Procedure

    +

    These are the steps to create and publish a new release of the openeo package. +To avoid the confusion with ad-hoc injection of some abstract version placeholder +that has to be replaced properly, +we will use a concrete version 0.8.0 in the examples below.

    +
      +
    1. Make sure you are working on latest master branch, +without uncommitted changes and all tests are properly passing.

    2. +
    3. Create release commit:

      +
        +
      1. Drop the pre-release suffix from the version string in openeo/_version.py +so that it just a “final” semantic versioning string, e.g. 0.8.0

      2. +
      3. Update CHANGELOG.md: rename the “Unreleased” section title +to contain version and date, e.g.:

        +
        ## [0.8.0] - 2020-12-15
        +
        +
        +

        remove empty subsections +and start a new “Unreleased” section above it, like:

        +
        ## [Unreleased]
        +
        +### Added
        +
        +### Changed
        +
        +### Removed
        +
        +### Fixed
        +
        +
        +
      4. +
      5. Commit these changes in git with a commit message like Release 0.8.0 +and push to GitHub:

        +
        git add openeo/_version.py CHANGELOG.md
        +git commit -m 'Release 0.8.0'
        +git push origin master
        +
        +
        +
      6. +
      +
    4. +
    5. Optional, but recommended: wait for VITO Jenkins to build this updated master +(trigger it manually if necessary), +so that a build of a final, non-alpha release 0.8.0 +is properly uploaded to VITO artifactory.

    6. +
    7. Create release on PyPI:

      +
        +
      1. Obtain a wheel archive of the package, with one of these approaches:

        +
          +
        • Preferably, the path of least surprise: build wheel through GitHub Actions. +Go to workflow “Build wheel”, +manually trigger a build with “Run workflow” button, wait for it to finish successfully, +download generated artifact.zip, and finally: unzip it to obtain openeo-0.8.0-py3-none-any.whl

        • +
        • Or, if you know what you are doing and you’re sure you have a clean +local checkout, you can also build it locally:

          +
          python setup.py bdist_wheel
          +
          +
          +

          This should create dist/openeo-0.8.0-py3-none-any.whl

          +
        • +
        +
      2. +
      3. Upload this wheel to PyPI:

        +
        python -m twine upload openeo-0.8.0-py3-none-any.whl
        +
        +
        +

        Check the release history on PyPI +to verify the twine upload. +Another way to verify that the freshly created release installs +is using docker to do a quick install-and-burn, +for example as follows (check the installed version in pip’s output):

        +
        docker run --rm -it python python -m pip install --no-deps openeo
        +
        +
        +
      4. +
      +
    8. +
    9. Create a git version tag and push it to GitHub:

      +
      git tag v0.8.0
      +git push origin v0.8.0
      +
      +
      +
    10. +
    11. Create a release in GitHub: +Go to https://github.com/Open-EO/openeo-python-client/releases/new, +Enter v0.8.0 under “tag”, +enter title: openEO Python Client v0.8.0, +use the corresponding CHANGELOG.md section as description +and publish it +(no need to attach binaries).

    12. +
    13. Bump the version in openeo/_version.py, (usually the “minor” level) +and append a pre-release “a1” suffix again, for example:

      +
      __version__ = '0.9.0a1'
      +
      +
      +

      Commit this (e.g. with message _version.py: bump to 0.9.0a1) +and push to GitHub.

      +
    14. +
    15. Update conda-forge package too +(requires conda recipe maintainer role). +Normally, the “regro-cf-autotick-bot” will create a pull request. +If it builds fine, merge it. +If not, fix the issue +(typically in recipe/meta.yaml) +and merge.

    16. +
    17. Optionally: send a tweet about the release +or announce it in the openEO Platform Forum.

    18. +
    +
    +

    Verification

    +

    The new release should now be available/listed at:

    + +

    Here is a bash (subshell) oneliner to verify that the PyPI release works properly:

    +
    (
    +    cd /tmp &&\
    +    python -m venv venv-openeo &&\
    +    source venv-openeo/bin/activate &&\
    +    pip install -U openeo &&\
    +    python -c "import openeo;print(openeo);print(openeo.__version__)"
    +)
    +
    +
    +

    It tries to install the latest version of the openeo package in a temporary virtual env, +import it and print the package version.

    +
    +
    +
    +
    +

    Development Installation on Windows

    +

    Normally you can install the client the same way on Windows as on Linux, like so:

    +
    pip install -e .[dev]
    +
    +
    +
    +

    Alternative development installation

    +

    The standard pure-pip based installation should work with the most recent code. +However, in the past we sometimes had issues with this procedure. +Should you experience problems, consider using an alternative conda-based installation procedure:

    +
      +
    1. Create and activate a new conda environment for developing the openeo-python-client. +For example:

      +
      conda create -n openeopyclient
      +conda activate openeopyclient
      +
      +
      +
    2. +
    3. In that conda environment, install only the dependencies of openeo via conda, +but not the openeo package itself.

      +
      # Install openeo dependencies (from the conda-forge channel)
      +conda install --only-deps -c conda-forge openeo
      +
      +
      +
    4. +
    5. Do a pip install from the project root in editable mode (pip -e):

      +
      pip install -e .[dev]
      +
      +
      +
    6. +
    +
    +
    +
    +

    Update of generated files

    +

    Some parts of the openEO Python Client Library source code are +generated/compiled from upstream sources (e.g. official openEO specifications). +Because updates are not often required, +it’s just a semi-manual procedure (to run from the project root):

    +
    # Update the sub-repositories (like git submodules, but optional)
    +python specs/update-subrepos.py
    +
    +# Update `openeo/processes.py` from specifications in openeo-processes repository
    +python openeo/internal/processes/generator.py  specs/openeo-processes specs/openeo-processes/proposals --output openeo/processes.py
    +
    +# Update the openEO process mapping documentation page
    +python docs/process_mapping.py > docs/process_mapping.rst
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 000000000..4a43923bc --- /dev/null +++ b/genindex.html @@ -0,0 +1,2179 @@ + + + + + + + Index — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + + +

    Index

    + +
    + _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | X + +
    +

    _

    + + +
    + +

    A

    + + + +
    + +

    B

    + + + +
    + +

    C

    + + + +
    + +

    D

    + + + +
    + +

    E

    + + + +
    + +

    F

    + + + +
    + +

    G

    + + + +
    + +

    H

    + + +
    + +

    I

    + + + +
    + +

    J

    + + + +
    + +

    L

    + + + +
    + +

    M

    + + + +
    + +

    N

    + + + +
    + +

    O

    + + + +
    + +

    P

    + + + +
    + +

    Q

    + + +
    + +

    R

    + + + +
    + +

    S

    + + + +
    + +

    T

    + + + +
    + +

    U

    + + + +
    + +

    V

    + + + +
    + +

    X

    + + + +
    + + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..fa24bad86 --- /dev/null +++ b/index.html @@ -0,0 +1,364 @@ + + + + + + + + openEO Python Client — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    openEO Python Client

    +https://img.shields.io/badge/Status-Stable-yellow.svg

    Welcome to the documentation of openeo, +the official Python client library for interacting with openEO back-ends +to process remote sensing and Earth observation data. +It provides a Pythonic interface for the openEO API, +supporting data/process discovery, process graph building, +batch job management and much more.

    +
    +

    Usage example

    +

    A simple example, to give a feel of using this library:

    +
    import openeo
    +
    +# Connect to openEO back-end.
    +connection = openeo.connect("openeo.vito.be").authenticate_oidc()
    +
    +# Load data cube from TERRASCOPE_S2_NDVI_V2 collection.
    +cube = connection.load_collection(
    +    "TERRASCOPE_S2_NDVI_V2",
    +    spatial_extent={"west": 5.05, "south": 51.21, "east": 5.1, "north": 51.23},
    +    temporal_extent=["2022-05-01", "2022-05-30"],
    +    bands=["NDVI_10M"],
    +)
    +# Rescale digital number to physical values and take temporal maximum.
    +cube = cube.apply(lambda x: 0.004 * x - 0.08).max_time()
    +
    +cube.download("ndvi-max.tiff")
    +
    +
    +_images/welcome.png +
    +
    +

    Table of contents

    +
    + +
    +
    +
    +

    Indices and tables

    + +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/installation.html b/installation.html new file mode 100644 index 000000000..032a0f4f2 --- /dev/null +++ b/installation.html @@ -0,0 +1,224 @@ + + + + + + + + Installation — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Installation

    +

    It is an explicit goal of the openEO Python client library to be as easy to install as possible, +unlocking the openEO ecosystem to a broad audience. +The package is a pure Python implementation and its dependencies are carefully considered (in number and complexity).

    +
    +

    Basic install

    +

    At least Python 3.7 is required (since version 0.23.0). +Also, it is recommended to work in a some kind of virtual environment (venv, conda, …) +to avoid polluting the base install of Python on your operating system +or introducing conflicts with other applications. +How you organize your virtual environments heavily depends on your use case and workflow, +and is out of scope of this documentation.

    +
    +

    Installation with pip

    +

    The openEO Python client library is available from PyPI +and can be easily installed with a tool like pip, for example:

    +
    $ pip install openeo
    +
    +
    +

    To upgrade the package to the latest release:

    +
    $ pip install --upgrade openeo
    +
    +
    +
    +
    +

    Installation with Conda

    +

    The openEO Python client library is available on conda-forge +and can be easily installed in a conda environment, for example:

    +
    $ conda install -c conda-forge openeo
    +
    +
    +
    +
    +

    Verifying and troubleshooting

    +

    You can check if the installation worked properly +by trying to import the openeo package in a Python script, interactive shell or notebook:

    +
    import openeo
    +
    +print(openeo.client_version())
    +
    +
    +

    This should print the installed version of the openeo package.

    +

    If the first line gives an error like ModuleNotFoundError: No module named 'openeo', +some troubleshooting tips:

    +
      +
    • Restart you Python shell or notebook (or start a fresh one).

    • +
    • Double check that the installation went well, +e.g. try re-installing and keep an eye out for error/warning messages.

    • +
    • Make sure that you are working in the same (virtual) environment you installed the package in.

    • +
    +

    If you still have troubles installing and importing openeo, +feel free to reach out in the community forum +or the project’s issue tracker. +Try to describe your setup in enough detail: your operating system, +which virtual environment system you use, +the installation tool (pip, conda or something else), …

    +
    +
    +
    +

    Optional dependencies

    +

    Depending on your use case, you might also want to install some additional libraries. +For example:

    +
      +
    • netCDF4 or h5netcdf for loading and writing NetCDF files (e.g. integrated in xarray.load_dataset())

    • +
    • matplotlib for visualisation (e.g. integrated plot functionality in xarray )

    • +
    +
    +

    Enabling additional features

    +

    To use the on-demand preview feature and other Jupyter-enabled features, you need to install the necessary dependencies.

    +
    $ pip install openeo[jupyter]
    +
    +
    +
    +
    +
    +

    Source or development install

    +

    If you closely track the development of the openeo package at +github.com/Open-EO/openeo-python-client +and want to work with unreleased features or contribute to the development of the package, +you can install it as follows from the root of a git source checkout:

    +
    $ pip install -e .[dev]
    +
    +
    +

    The -e option enables “development mode”, which makes sure that changes you make to the source code +happen directly on the installed package, so that you don’t have to re-install the package each time +you make a change.

    +

    The [dev] (a so-called “extra”) installs additional development related dependencies, +for example to run the unit tests.

    +

    You can also find more information about installation for development on the Development and maintenance page.

    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/lib/openeo/__init__.py b/lib/openeo/__init__.py new file mode 100644 index 000000000..bf0c7caac --- /dev/null +++ b/lib/openeo/__init__.py @@ -0,0 +1,26 @@ +""" + + +""" + +__title__ = 'openeo' +__author__ = 'Jeroen Dries' + + +class BaseOpenEoException(Exception): + pass + + +from openeo._version import __version__ +from openeo.rest.connection import Connection, connect, session +from openeo.rest.datacube import UDF, DataCube +from openeo.rest.graph_building import collection_property +from openeo.rest.job import BatchJob, RESTJob + + +def client_version() -> str: + try: + import importlib.metadata + return importlib.metadata.version("openeo") + except Exception: + return __version__ diff --git a/lib/openeo/_version.py b/lib/openeo/_version.py new file mode 100644 index 000000000..d0ba45407 --- /dev/null +++ b/lib/openeo/_version.py @@ -0,0 +1 @@ +__version__ = "0.26.0a1" diff --git a/lib/openeo/api/__init__.py b/lib/openeo/api/__init__.py new file mode 100644 index 000000000..88cc8b8b5 --- /dev/null +++ b/lib/openeo/api/__init__.py @@ -0,0 +1,3 @@ +""" +Wrappers for openEO API concepts. +""" diff --git a/lib/openeo/api/logs.py b/lib/openeo/api/logs.py new file mode 100644 index 000000000..5a7ae02d5 --- /dev/null +++ b/lib/openeo/api/logs.py @@ -0,0 +1,99 @@ +import logging +from typing import Optional, Union + + +class LogEntry(dict): + """ + Log message and info for jobs and services + + Fields: + - ``id``: Unique ID for the log, string, REQUIRED + - ``code``: Error code, string, optional + - ``level``: Severity level, string (error, warning, info or debug), REQUIRED + - ``message``: Error message, string, REQUIRED + - ``time``: Date and time of the error event as RFC3339 date-time, string, available since API 1.1.0 + - ``path``: A "stack trace" for the process, array of dicts + - ``links``: Related links, array of dicts + - ``usage``: Usage metrics available as property 'usage', dict, available since API 1.1.0 + May contain the following metrics: cpu, memory, duration, network, disk, storage and other custom ones + Each of the metrics is also a dict with the following parts: value (numeric) and unit (string) + - ``data``: Arbitrary data the user wants to "log" for debugging purposes. + Please note that this property may not exist as there's a difference + between None and non-existing. None for example refers to no-data in + many cases while the absence of the property means that the user did + not provide any data for debugging. + """ + + _required = {"id", "level", "message"} + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Check required fields + missing = self._required.difference(self.keys()) + if missing: + raise ValueError("Missing required fields: {m}".format(m=sorted(missing))) + + @property + def id(self): + return self["id"] + + # Legacy alias + log_id = id + + @property + def message(self): + return self["message"] + + @property + def level(self): + return self["level"] + + # TODO: add properties for "code", "time", "path", "links" and "data" with sensible defaults? + + +def normalize_log_level( + log_level: Union[int, str, None], default: int = logging.DEBUG +) -> int: + """ + Helper function to convert a openEO API log level (e.g. string "error") + to the integer constants defined in Python's standard library ``logging`` module (e.g. ``logging.ERROR``). + + :param log_level: log level to normalize: a log level string in the style of + the openEO API ("error", "warning", "info", or "debug"), + an integer value (e.g. a ``logging`` constant), or ``None``. + + :param default: fallback log level to return on unknown log level strings or ``None`` input. + + :raises TypeError: when log_level is any other type than str, an int or None. + :return: One of the following log level constants from the standard module ``logging``: + ``logging.ERROR``, ``logging.WARNING``, ``logging.INFO``, or ``logging.DEBUG`` . + """ + if isinstance(log_level, str): + log_level = log_level.upper() + if log_level in ["CRITICAL", "ERROR", "FATAL"]: + return logging.ERROR + elif log_level in ["WARNING", "WARN"]: + return logging.WARNING + elif log_level == "INFO": + return logging.INFO + elif log_level == "DEBUG": + return logging.DEBUG + else: + return default + elif isinstance(log_level, int): + return log_level + elif log_level is None: + return default + else: + raise TypeError( + f"Value for log_level is not an int or str: type={type(log_level)}, value={log_level!r}" + ) + + +def log_level_name(log_level: Union[int, str, None]) -> str: + """ + Get the name of a normalized log level. + This value conforms to log level names used in the openEO API. + """ + return logging.getLevelName(normalize_log_level(log_level)).lower() diff --git a/lib/openeo/api/process.py b/lib/openeo/api/process.py new file mode 100644 index 000000000..bd8685ea7 --- /dev/null +++ b/lib/openeo/api/process.py @@ -0,0 +1,138 @@ +from __future__ import annotations + +import warnings +from typing import Union, Optional, List + + +class Parameter: + """ + Wrapper for a process parameter, as used in predefined and user-defined processes. + """ + # TODO unify with openeo.internal.processes.parse.Parameter? + + _DEFAULT_UNDEFINED = object() + + def __init__( + self, name: str, description: str = None, schema: Union[dict, str] = None, + default=_DEFAULT_UNDEFINED, optional=None + ): + self.name = name + if description is None: + # Description is required in openEO API, we are a bit more permissive here. + warnings.warn("Parameter without description: using name as description.") + description = name + self.description = description + self.schema = {"type": schema} if isinstance(schema, str) else (schema or {}) + self.default = default + self.optional = optional + + def to_dict(self) -> dict: + """Convert to dictionary for JSON-serialization.""" + d = {"name": self.name, "description": self.description, "schema": self.schema} + if self.optional is not None: + d["optional"] = self.optional + if self.default is not self._DEFAULT_UNDEFINED: + d["default"] = self.default + d["optional"] = True + return d + + @classmethod + def raster_cube(cls, name: str = "data", description: str = "A data cube.") -> Parameter: + """ + Helper to easily create a 'raster-cube' parameter. + + :param name: name of the parameter. + :param description: description of the parameter + :return: Parameter + """ + return cls(name=name, description=description, schema={"type": "object", "subtype": "raster-cube"}) + + @classmethod + def datacube(cls, name: str = "data", description: str = "A data cube.") -> Parameter: + """ + Helper to easily create a 'datacube' parameter. + + :param name: name of the parameter. + :param description: description of the parameter + :return: Parameter + + .. versionadded:: 0.22.0 + """ + return cls(name=name, description=description, schema={"type": "object", "subtype": "datacube"}) + + @classmethod + def string( + cls, + name: str, + description: str = None, + default=_DEFAULT_UNDEFINED, + values: Optional[List[str]] = None, + subtype: Optional[str] = None, + format: Optional[str] = None, + ) -> Parameter: + """Helper to create a 'string' type parameter.""" + schema = {"type": "string"} + if values is not None: + schema["enum"] = values + if subtype: + schema["subtype"] = subtype + if format: + schema["format"] = format + return cls(name=name, description=description, schema=schema, default=default) + + @classmethod + def integer(cls, name: str, description: str = None, default=_DEFAULT_UNDEFINED) -> Parameter: + """Helper to create a 'integer' type parameter.""" + return cls(name=name, description=description, schema={"type": "integer"}, default=default) + + @classmethod + def number(cls, name: str, description: str = None, default=_DEFAULT_UNDEFINED) -> Parameter: + """Helper to create a 'number' type parameter.""" + return cls(name=name, description=description, schema={"type": "number"}, default=default) + + @classmethod + def boolean(cls, name: str, description: str = None, default=_DEFAULT_UNDEFINED) -> Parameter: + """Helper to create a 'boolean' type parameter.""" + return cls(name=name, description=description, schema={"type": "boolean"}, default=default) + + @classmethod + def array( + cls, + name: str, + description: str = None, + default=_DEFAULT_UNDEFINED, + *, + item_schema: Optional[Union[str, dict]] = None, + ) -> Parameter: + """ + Helper to create an 'array' type parameter. + + :param item_schema: Schema of the array items given in JSON Schema style, e.g. ``{"type": "string"}``. + Simple schemas can also be specified as single string: + e.g. ``"string"`` will be expanded to ``{"type": "string"}``. + + .. versionchanged:: 0.23.0 + Added ``item_schema`` argument. + """ + schema = {"type": "array"} + if item_schema: + if isinstance(item_schema, str): + item_schema = {"type": item_schema} + schema["items"] = item_schema + return cls(name=name, description=description, schema=schema, default=default) + + @classmethod + def object( + cls, name: str, description: Optional[str] = None, default=_DEFAULT_UNDEFINED, *, subtype: Optional[str] = None + ) -> Parameter: + """ + Helper to create an 'object' type parameter + + :param subtype: subtype of the 'object' schema + + .. versionadded:: 0.26.0 + """ + schema = {"type": "object"} + if subtype: + schema["subtype"] = subtype + return cls(name=name, description=description, schema=schema, default=default) diff --git a/lib/openeo/capabilities.py b/lib/openeo/capabilities.py new file mode 100644 index 000000000..e59481ca3 --- /dev/null +++ b/lib/openeo/capabilities.py @@ -0,0 +1,210 @@ +from __future__ import annotations + +import contextlib +import re +from abc import ABC +from typing import Tuple, Union + + +# TODO Is this base class (still) useful? + + +class Capabilities(ABC): + """Represents capabilities of a connection / back end.""" + + def __init__(self, data): + pass + + def version(self): + """ Get openEO version. DEPRECATED: use api_version instead""" + # Field: version + # TODO: raise deprecation warning here? + return self.api_version() + + def api_version(self) -> str: + """Get OpenEO API version.""" + raise NotImplementedError + + @property + def api_version_check(self) -> ComparableVersion: + """Helper to easily check if the API version is at least or below some threshold version.""" + api_version = self.api_version() + if not api_version: + raise ApiVersionException("No API version found") + return ComparableVersion(api_version) + + def list_features(self): + """ List all supported features / endpoints.""" + # Field: endpoints + pass + + def has_features(self, method_name): + """ Check whether a feature / endpoint is supported.""" + # Field: endpoints > ... + pass + + def currency(self): + """ Get default billing currency.""" + # Field: billing > currency + pass + + def list_plans(self): + """ List all billing plans.""" + # Field: billing > plans + pass + + +# Type annotation aliases +_VersionTuple = Tuple[Union[int, str], ...] + + +class ComparableVersion: + """ + Helper to compare a version (e.g. API version) against another (threshold) version + + >>> v = ComparableVersion('1.2.3') + >>> v.at_least('1.2.1') + True + >>> v.at_least('1.10.2') + False + >>> v > "2.0" + False + + To express a threshold condition you sometimes want the reference or threshold value on + the left hand side or right hand side of the logical expression. + There are two groups of methods to handle each case: + + - right hand side referencing methods. These read more intuitively. For example: + + `a.at_least(b)`: a is equal or higher than b + `a.below(b)`: a is lower than b + + - left hand side referencing methods. These allow "currying" a threshold value + in a reusable condition callable. For example: + + `a.or_higher(b)`: b is equal or higher than a + `a.accept_lower(b)`: b is lower than a + + Implementation is loosely based on (now deprecated) `distutils.version.LooseVersion`, + which pragmatically parses version strings as a sequence of numbers (compared numerically) + or alphabetic strings (compared lexically), e.g.: 1.5.1, 1.5.2b2, 161, 8.02, 2g6, 2.2beta29. + """ + + _component_re = re.compile(r'(\d+ | [a-zA-Z]+ | \.)', re.VERBOSE) + + def __init__(self, version: Union[str, 'ComparableVersion', tuple]): + if isinstance(version, ComparableVersion): + self._version = version._version + elif isinstance(version, tuple): + self._version = version + elif isinstance(version, str): + self._version = self._parse(version) + else: + raise ValueError(version) + + @classmethod + def _parse(cls, version_string: str) -> _VersionTuple: + components = [ + x for x in cls._component_re.split(version_string) + if x and x != '.' + ] + for i, obj in enumerate(components): + with contextlib.suppress(ValueError): + components[i] = int(obj) + return tuple(components) + + @property + def parts(self) -> _VersionTuple: + """Version components as a tuple""" + return self._version + + def __repr__(self): + return '{c}({v!r})'.format(c=type(self).__name__, v=self._version) + + def __str__(self): + return ".".join(map(str, self._version)) + + def __hash__(self): + return hash(self._version) + + def to_string(self): + return str(self) + + @staticmethod + def _pad(a: Union[str, ComparableVersion], b: Union[str, ComparableVersion]) -> Tuple[_VersionTuple, _VersionTuple]: + """Pad version tuples with zero/empty to get same length for intuitive comparison""" + a = ComparableVersion(a)._version + b = ComparableVersion(b)._version + if len(a) > len(b): + b = b + tuple(0 if isinstance(x, int) else "" for x in a[len(b) :]) + elif len(b) > len(a): + a = a + tuple(0 if isinstance(x, int) else "" for x in b[len(a) :]) + return a, b + + def __eq__(self, other: Union[str, ComparableVersion]) -> bool: + a, b = self._pad(self, other) + return a == b + + def __ge__(self, other: Union[str, ComparableVersion]) -> bool: + a, b = self._pad(self, other) + return a >= b + + def __gt__(self, other: Union[str, ComparableVersion]) -> bool: + a, b = self._pad(self, other) + return a > b + + def __le__(self, other: Union[str, ComparableVersion]) -> bool: + a, b = self._pad(self, other) + return a <= b + + def __lt__(self, other: Union[str, ComparableVersion]) -> bool: + a, b = self._pad(self, other) + return a < b + + def equals(self, other: Union[str, 'ComparableVersion']): + return self == other + + # Right hand side referencing expressions. + def at_least(self, other: Union[str, 'ComparableVersion']): + """Self is at equal or higher than other.""" + return self >= other + + def above(self, other: Union[str, 'ComparableVersion']): + """Self is higher than other.""" + return self > other + + def at_most(self, other: Union[str, 'ComparableVersion']): + """Self is equal or lower than other.""" + return self <= other + + def below(self, other: Union[str, 'ComparableVersion']): + """Self is lower than other.""" + return self < other + + # Left hand side referencing expressions. + def or_higher(self, other: Union[str, 'ComparableVersion']): + """Other is equal or higher than self.""" + return ComparableVersion(other) >= self + + def or_lower(self, other: Union[str, 'ComparableVersion']): + """Other is equal or lower than self""" + return ComparableVersion(other) <= self + + def accept_lower(self, other: Union[str, 'ComparableVersion']): + """Other is lower than self.""" + return ComparableVersion(other) < self + + def accept_higher(self, other: Union[str, 'ComparableVersion']): + """Other is higher than self.""" + return ComparableVersion(other) > self + + def require_at_least(self, other: Union[str, "ComparableVersion"]): + """Raise exception if self is not at least other.""" + if not self.at_least(other): + raise ApiVersionException( + f"openEO API version should be at least {other!s}, but got {self!s}." + ) + + +class ApiVersionException(RuntimeError): + pass diff --git a/lib/openeo/config.py b/lib/openeo/config.py new file mode 100644 index 000000000..8c46a1924 --- /dev/null +++ b/lib/openeo/config.py @@ -0,0 +1,209 @@ +""" + +openEO client configuration (e.g. through config files) + +""" + +from __future__ import annotations + +import logging +import os +import platform +from configparser import ConfigParser +from copy import deepcopy +from pathlib import Path +from typing import Any, Iterator, List, Optional, Sequence, Union + +from openeo.util import in_interactive_mode + +_log = logging.getLogger(__name__) + +DEFAULT_APP_NAME = "openeo-python-client" + + +def _get_user_dir( + app_name=DEFAULT_APP_NAME, + xdg_env_var="XDG_CONFIG_HOME", + win_env_var="APPDATA", + fallback="~/.config", + win_fallback="~\\AppData\\Roaming", + macos_fallback="~/Library/Preferences", + auto_create=True, +) -> Path: + """ + Get platform specific config/data/cache folder + """ + # Platform specific root locations (from highest priority to lowest) + env = os.environ + if platform.system() == "Windows": + roots = [env.get(win_env_var), win_fallback, fallback] + elif platform.system() == "Darwin": + roots = [env.get(xdg_env_var), macos_fallback, fallback] + else: + # Assume unix + roots = [env.get(xdg_env_var), fallback] + + # Filter out None's, expand user prefix and append app name + dirs = [Path(r).expanduser() / app_name for r in roots if r] + # Prepend with OPENEO_CONFIG_HOME if set. + if env.get("OPENEO_CONFIG_HOME"): + dirs.insert(0, Path(env.get("OPENEO_CONFIG_HOME"))) + + # Use highest prio dir that already exists. + for p in dirs: + if p.exists() and p.is_dir(): + return p + + # No existing dir: create highest prio one (if possible) + if auto_create: + for p in dirs: + try: + p.mkdir(parents=True) + _log.info("Created user dir for {a!r}: {p}".format(a=app_name, p=p)) + return p + except OSError: + pass + + raise Exception("Failed to find user dir for {a!r}. Tried: {p!r}".format(a=app_name, p=dirs)) + + +def get_user_config_dir(app_name=DEFAULT_APP_NAME, auto_create=True) -> Path: + """ + Get platform specific config folder + """ + return _get_user_dir( + app_name=app_name, + xdg_env_var="XDG_CONFIG_HOME", + win_env_var="APPDATA", + fallback="~/.config", + win_fallback="~\\AppData\\Roaming", + macos_fallback="~/Library/Preferences", + auto_create=auto_create, + ) + + +def get_user_data_dir(app_name=DEFAULT_APP_NAME, auto_create=True) -> Path: + """ + Get platform specific data folder + """ + return _get_user_dir( + app_name=app_name, + xdg_env_var="XDG_DATA_HOME", + win_env_var="APPDATA", + fallback="~/.local/share", + win_fallback="~\\AppData\\Roaming", + macos_fallback="~/Library", + auto_create=auto_create, + ) + + +class ClientConfig: + """ + openEO client configuration. Essentially a flat mapping of config key-value pairs. + """ + + # TODO: support for loading JSON based config files? + + def __init__(self): + self._config = {} + self._sources = [] + + @classmethod + def _key(cls, key: Union[str, Sequence[str]]): + """Normalize a key: make lower case and flatten sequences""" + if not isinstance(key, str): + key = ".".join(str(k) for k in key) + return key.lower() + + def _set(self, key: Union[str, Sequence[str]], value: Any): + """Set config value at key""" + self._config[self._key(key)] = value + + def get(self, key: Union[str, Sequence[str]], default=None) -> Any: + """Get setting at given key""" + # TODO: option to cast/convert to certain type? + return self._config.get(self._key(key), default) + + def load_ini_file(self, path: Union[str, Path]) -> ClientConfig: + cp = ConfigParser() + read_ok = cp.read(path) + self._sources.extend(read_ok) + return self.load_config_parser(cp) + + def load_config_parser(self, parser: ConfigParser) -> ClientConfig: + for section in parser.sections(): + for option, value in parser.items(section=section): + self._set(key=(section, option), value=value) + return self + + def dump(self) -> dict: + return deepcopy(self._config) + + @property + def sources(self) -> List[str]: + return [str(s) for s in self._sources] + + def __repr__(self): + return f"<{type(self).__name__} from {self.sources}>" + + +class ConfigLoader: + @classmethod + def config_locations(cls) -> Iterator[Path]: + """Config location candidates""" + # From highest to lowest priority + if "OPENEO_CLIENT_CONFIG" in os.environ: + yield Path(os.environ["OPENEO_CLIENT_CONFIG"]) + yield Path.cwd() / "openeo-client-config.ini" + if "OPENEO_CONFIG_HOME" in os.environ: + yield Path(os.environ["OPENEO_CONFIG_HOME"]) / "openeo-client-config.ini" + if "XDG_CONFIG_HOME" in os.environ: + yield Path(os.environ["XDG_CONFIG_HOME"]) / DEFAULT_APP_NAME / "openeo-client-config.ini" + yield Path.home() / ".openeo-client-config.ini" + + @classmethod + def load(cls) -> ClientConfig: + # TODO: (option to) merge layered configs instead of returning on first hit? + config = ClientConfig() + for path in cls.config_locations(): + _log.debug(f"Config file candidate: {path}") + if path.exists(): + if path.suffix.lower() == ".ini": + _log.debug(f"Loading config from {path}") + try: + config.load_ini_file(path) + break + except Exception: + _log.warning(f"Failed to load config from {path}", exc_info=True) + return config + + +# Global config (lazily loaded by :py:func:`get_config`) +_global_config = None + + +def get_config() -> ClientConfig: + """Get global openEO client config (:py:class:`ClientConfig`) (lazy loaded).""" + global _global_config + if _global_config is None: + _global_config = ConfigLoader.load() + # Note: explicit `', '.join()` instead of implicit `repr` on full `sources` list + # as the latter causes ugly escaping of Windows path separator. + message = f"Loaded openEO client config from sources: [{', '.join(_global_config.sources)}]" + _log.info(message) + if _global_config.sources: + config_log(message) + + return _global_config + + +def get_config_option(key: Optional[str] = None, default=None) -> str: + """Get config value for given key from global config (lazy loaded).""" + return get_config().get(key=key, default=default) + + +def config_log(message: str): + """Print a config related message if verbosity is configured for that.""" + verbose = get_config_option("general.verbose", default="auto") + if verbose == "print" or (verbose == "auto" and in_interactive_mode()): + print(message) diff --git a/lib/openeo/dates.py b/lib/openeo/dates.py new file mode 100644 index 000000000..834c23f90 --- /dev/null +++ b/lib/openeo/dates.py @@ -0,0 +1,202 @@ +from __future__ import annotations + +import datetime as dt +import re +from enum import Enum +from typing import Any, Tuple, Union + +from openeo.util import rfc3339 + + +def get_temporal_extent( + *args, + start_date: Union[str, dt.date, None, Any] = None, + end_date: Union[str, dt.date, None, Any] = None, + extent: Union[list, tuple, str, None] = None, + convertor=rfc3339.normalize, +) -> Tuple[Union[str, None], Union[str, None]]: + """ + Helper to derive a date extent from various call forms: + + >>> get_temporal_extent("2019-01-01") + ("2019-01-01", None) + >>> get_temporal_extent("2019-01-01", "2019-05-15") + ("2019-01-01", "2019-05-15") + >>> get_temporal_extent(["2019-01-01", "2019-05-15"]) + ("2019-01-01", "2019-05-15") + >>> get_temporal_extent(start_date="2019-01-01", end_date="2019-05-15"]) + ("2019-01-01", "2019-05-15") + >>> get_temporal_extent(extent=["2019-01-01", "2019-05-15"]) + ("2019-01-01", "2019-05-15") + + It also supports resolving year/month shorthand notation (rounding down to first day of year or month): + + >>> get_temporal_extent("2019") + ("2019-01-01", None) + >>> get_temporal_extent(start_date="2019-02", end_date="2019-03"]) + ("2019-02-01", "2019-03-01") + + And even interpretes extents given as a single string: + + >>> get_temporal_extent(extent="2021") + ("2021-01-01", "2022-01-01") + + """ + if (bool(len(args) > 0) + bool(start_date or end_date) + bool(extent)) > 1: + raise ValueError("At most one of `*args`, `start_date/end_date`, or `extent` should be provided") + if args: + # Convert positional `*args` to `start_date`/`end_date` argument + if len(args) == 2: + start_date, end_date = args + elif len(args) == 1: + arg = args[0] + if isinstance(arg, (list, tuple)): + if len(args) > 2: + raise ValueError(f"Unable to handle {args} as a temporal extent") + start_date, end_date = tuple(arg) + (None,) * (2 - len(arg)) + else: + start_date, end_date = arg, None + else: + raise ValueError(f"Unable to handle {args} as a temporal extent") + elif extent: + if isinstance(extent, (list, tuple)) and len(extent) == 2: + start_date, end_date = extent + elif isinstance(extent, str): + # Special case: extent is given as a single string (e.g. "2021" for full year extent + # or "2021-04" for full month extent): convert that to the appropriate extent tuple. + start_date, end_date = _convert_abbreviated_date(extent), _get_end_of_time_slot(extent) + else: + raise ValueError(f"Unable to handle {extent} as a temporal extent") + start_date = _convert_abbreviated_date(start_date) + end_date = _convert_abbreviated_date(end_date) + return convertor(start_date) if start_date else None, convertor(end_date) if end_date else None + + +class _TypeOfDateString(Enum): + """Enum that denotes which kind of date a string represents. + + This is an internal helper class, not intended to be public. + """ + + INVALID = 0 # It was neither of the options below + YEAR = 1 + MONTH = 2 + DAY = 3 + DATETIME = 4 + + +_REGEX_DAY = re.compile(r"^(\d{4})[:/_-](\d{2})[:/_-](\d{2})$") +_REGEX_MONTH = re.compile(r"^(\d{4})[:/_-](\d{2})$") +_REGEX_YEAR = re.compile(r"^\d{4}$") + + +def _get_end_of_time_slot(date: str) -> Union[dt.date, str]: + """Calculate the end of a left-closed period: the first day after a year or month.""" + if not isinstance(date, str): + return date + + date_converted = _convert_abbreviated_date(date) + granularity = _type_of_date_string(date) + if granularity == _TypeOfDateString.YEAR: + return dt.date(date_converted.year + 1, 1, 1) + elif granularity == _TypeOfDateString.MONTH: + if date_converted.month == 12: + return dt.date(date_converted.year + 1, 1, 1) + else: + return dt.date(date_converted.year, date_converted.month + 1, 1) + elif granularity == _TypeOfDateString.DAY: + # TODO: also support day granularity in _convert_abbreviated_date so that we don't need ad-hoc parsing here + return dt.date(*(int(x) for x in _REGEX_DAY.match(date).group(1, 2, 3))) + dt.timedelta(days=1) + else: + # Don't convert: it is a day or datetime. + return date + + +def _convert_abbreviated_date( + date: Union[str, dt.date, dt.datetime, Any], +) -> Union[str, dt.date, dt.datetime, Any]: + """ + Helper function to convert a year- or month-abreviated strings (e.g. "2021" or "2021-03") into a date + (first day of the corresponding period). Other values are returned as original. + + :param date: some kind of date representation: + + - A string, formatted "yyyy", "yyyy-mm", "yyyy-mm-dd" or with even more granularity + - Any other type (e.g. ``datetime.date``, ``datetime.datetime``, a parameter, ...) + + :return: + If input was a string representing a year or a month: + a ``datetime.date`` that represents the first day of that year or month. + Otherwise, the original version is returned as-is. + + :raises ValueError: + when ``date`` was a string but not recognized as a date representation + + Examples + -------- + + >>> # For year and month: "round down" to fist day: + >>> _convert_abbreviated_date("2021") + datetime.date(2021, 1, 1) + >>> _convert_abbreviated_date("2022-08") + datetime.date(2022, 8, 1) + + >>> # Preserve other values + >>> _convert_abbreviated_date("2022-08-15") + '2022-08-15' + """ + if not isinstance(date, str): + return date + + # TODO: avoid double regex matching? Once in _type_of_date_string and once here. + type_of_date = _type_of_date_string(date) + if type_of_date == _TypeOfDateString.INVALID: + raise ValueError( + f"The value of date='{date}' does not represent any of: " + + "a year ('yyyy'), a year + month ('yyyy-dd'), a date, or a datetime." + ) + + if type_of_date in [_TypeOfDateString.DATETIME, _TypeOfDateString.DAY]: + # TODO: also convert these to `date` or `datetime` for more internal consistency. + return date + + if type_of_date == _TypeOfDateString.MONTH: + match_month = _REGEX_MONTH.match(date) + year = int(match_month.group(1)) + month = int(match_month.group(2)) + else: + year = int(date) + month = 1 + + return dt.date(year, month, 1) + + +def _type_of_date_string(date: str) -> _TypeOfDateString: + """Returns which type of date the string represents: year, month, day or datetime.""" + + if not isinstance(date, str): + raise TypeError("date must be a string") + + try: + rfc3339.parse_datetime(date) + return _TypeOfDateString.DATETIME + except ValueError: + pass + + # Using a separate and stricter regular expressions to detect day, month, + # or year. Having a regex that only matches one type of period makes it + # easier to check it is effectively only a year, or only a month, + # but not a day. Datetime strings are more complex so we use rfc3339 to + # check whether or not it represents a datetime. + match_day = _REGEX_DAY.match(date) + match_month = _REGEX_MONTH.match(date) + match_year = _REGEX_YEAR.match(date) + + if match_day: + return _TypeOfDateString.DAY + if match_month: + return _TypeOfDateString.MONTH + if match_year: + return _TypeOfDateString.YEAR + + return _TypeOfDateString.INVALID diff --git a/lib/openeo/extra/__init__.py b/lib/openeo/extra/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/openeo/extra/job_management.py b/lib/openeo/extra/job_management.py new file mode 100644 index 000000000..3e67fc1f3 --- /dev/null +++ b/lib/openeo/extra/job_management.py @@ -0,0 +1,455 @@ +import contextlib +import datetime +import json +import logging +import time +from pathlib import Path +from typing import Callable, Dict, NamedTuple, Optional, Union + +import pandas as pd +import requests +import shapely.wkt +from requests.adapters import HTTPAdapter, Retry + +from openeo import BatchJob, Connection +from openeo.rest import OpenEoApiError +from openeo.util import deep_get + + +_log = logging.getLogger(__name__) + + +class _Backend(NamedTuple): + """Container for backend info/settings""" + + # callable to create a backend connection + get_connection: Callable[[], Connection] + # Maximum number of jobs to allow in parallel on a backend + parallel_jobs: int + + +MAX_RETRIES = 5 + +class MultiBackendJobManager: + """ + Tracker for multiple jobs on multiple backends. + + Usage example: + + .. code-block:: python + + import pandas as pd + import openeo + from openeo.extra.job_management import MultiBackendJobManager + + manager = MultiBackendJobManager() + manager.add_backend("foo", connection=openeo.connect("http://foo.test")) + manager.add_backend("bar", connection=openeo.connect("http://bar.test")) + + jobs_df = pd.DataFrame(...) + output_file = "jobs.csv" + + def start_job( + row: pd.Series, + connection: openeo.Connection, + **kwargs + ) -> openeo.BatchJob: + year = row["year"] + cube = connection.load_collection( + ..., + temporal_extent=[f"{year}-01-01", f"{year+1}-01-01"], + ) + ... + return cube.create_job(...) + + manager.run_jobs(df=jobs_df, start_job=start_job, output_file=output_file) + + See :py:meth:`.run_jobs` for more information on the ``start_job`` callable. + + .. versionadded:: 0.14.0 + """ + + def __init__( + self, poll_sleep: int = 60, root_dir: Optional[Union[str, Path]] = "." + ): + """Create a MultiBackendJobManager. + + :param poll_sleep: + How many seconds to sleep between polls. + + :param root_dir: + Root directory to save files for the jobs, e.g. metadata and error logs. + This defaults to "." the current directory. + + Each job gets its own subfolder in this root directory. + You can use the following methods to find the relevant paths, + based on the job ID: + - get_job_dir + - get_error_log_path + - get_job_metadata_path + """ + self.backends: Dict[str, _Backend] = {} + self.poll_sleep = poll_sleep + self._connections: Dict[str, _Backend] = {} + + # An explicit None or "" should also default to "." + self._root_dir = Path(root_dir or ".") + + def add_backend( + self, + name: str, + connection: Union[Connection, Callable[[], Connection]], + parallel_jobs: int = 2, + ): + """ + Register a backend with a name and a Connection getter. + + :param name: + Name of the backend. + :param connection: + Either a Connection to the backend, or a callable to create a backend connection. + :param parallel_jobs: + Maximum number of jobs to allow in parallel on a backend. + """ + + # TODO: Code might become simpler if we turn _Backend into class move this logic there. + # We would need to keep add_backend here as part of the public API though. + # But the amount of unrelated "stuff to manage" would be less (better cohesion) + if isinstance(connection, Connection): + c = connection + connection = lambda: c + assert callable(connection) + self.backends[name] = _Backend( + get_connection=connection, parallel_jobs=parallel_jobs + ) + + def _get_connection(self, backend_name: str, resilient: bool = True) -> Connection: + """Get a connection for the backend and optionally make it resilient (adds retry behavior) + + The default is to get a resilient connection, but if necessary you can turn it off with + resilient=False + """ + + # TODO: Code could be simplified if _Backend is a class and this method is moved there. + # TODO: Is it better to make this a public method? + + # Reuse the connection if we can, in order to avoid modifying the same connection several times. + # This is to avoid adding the retry HTTPAdapter multiple times. + # Remember that the get_connection attribute on _Backend can be a Connection object instead + # of a callable, so we don't want to assume it is a fresh connection that doesn't have the + # retry adapter yet. + if backend_name in self._connections: + return self._connections[backend_name] + + connection = self.backends[backend_name].get_connection() + # If we really need it we can skip making it resilient, but by default it should be resilient. + if resilient: + self._make_resilient(connection) + + self._connections[backend_name] = connection + return connection + + def _make_resilient(self, connection): + """Add an HTTPAdapter that retries the request if it fails. + + Retry for the following HTTP 50x statuses: + 502 Bad Gateway + 503 Service Unavailable + 504 Gateway Timeout + """ + status_forcelist = [502, 503, 504] + retries = Retry( + total=MAX_RETRIES, + read=MAX_RETRIES, + other=MAX_RETRIES, + status=MAX_RETRIES, + backoff_factor=0.1, + status_forcelist=status_forcelist, + allowed_methods=["HEAD", "GET", "OPTIONS", "POST"], + ) + connection.session.mount("https://", HTTPAdapter(max_retries=retries)) + connection.session.mount("http://", HTTPAdapter(max_retries=retries)) + + def _normalize_df(self, df: pd.DataFrame) -> pd.DataFrame: + """Ensure we have the required columns and the expected type for the geometry column. + + :param df: The dataframe to normalize. + :return: a new dataframe that is normalized. + """ + + # check for some required columns. + required_with_default = [ + ("status", "not_started"), + ("id", None), + ("start_time", None), + ("cpu", None), + ("memory", None), + ("duration", None), + ("backend_name", None), + ] + new_columns = { + col: val for (col, val) in required_with_default if col not in df.columns + } + df = df.assign(**new_columns) + # Workaround for loading of geopandas "geometry" column. + if "geometry" in df.columns and df["geometry"].dtype.name != "geometry": + df["geometry"] = df["geometry"].apply(shapely.wkt.loads) + return df + + def _persists(self, df, output_file): + df.to_csv(output_file, index=False) + _log.info(f"Wrote job metadata to {output_file.absolute()}") + + def run_jobs( + self, + df: pd.DataFrame, + start_job: Callable[[], BatchJob], + output_file: Union[str, Path], + ): + """Runs jobs, specified in a dataframe, and tracks parameters. + + :param df: + DataFrame that specifies the jobs, and tracks the jobs' statuses. + + :param start_job: + A callback which will be invoked with, amongst others, + the row of the dataframe for which a job should be created and/or started. + This callable should return a :py:class:`openeo.rest.job.BatchJob` object. + + The following parameters will be passed to ``start_job``: + + ``row`` (:py:class:`pandas.Series`): + The row in the pandas dataframe that stores the jobs state and other tracked data. + + ``connection_provider``: + A getter to get a connection by backend name. + Typically, you would need either the parameter ``connection_provider``, + or the parameter ``connection``, but likely you will not need both. + + ``connection`` (:py:class:`Connection`): + The :py:class:`Connection` itself, that has already been created. + Typically, you would need either the parameter ``connection_provider``, + or the parameter ``connection``, but likely you will not need both. + + ``provider`` (``str``): + The name of the backend that will run the job. + + You do not have to define all the parameters described below, but if you leave + any of them out, then remember to include the ``*args`` and ``**kwargs`` parameters. + Otherwise you will have an exception because :py:meth:`run_jobs` passes unknown parameters to ``start_job``. + + :param output_file: + Path to output file (CSV) containing the status and metadata of the jobs. + """ + # TODO: Defining start_jobs as a Protocol might make its usage more clear, and avoid complicated doctrings, + # but Protocols are only supported in Python 3.8 and higher. + # TODO: this resume functionality better fits outside of this function + # (e.g. if `output_file` exists: `df` is fully discarded) + output_file = Path(output_file) + if output_file.exists() and output_file.is_file(): + # Resume from existing CSV + _log.info(f"Resuming `run_jobs` from {output_file.absolute()}") + df = pd.read_csv(output_file) + status_histogram = df.groupby("status").size().to_dict() + _log.info(f"Status histogram: {status_histogram}") + + df = self._normalize_df(df) + + while ( + df[ + (df.status != "finished") + & (df.status != "skipped") + & (df.status != "start_failed") + & (df.status != "error") + ].size + > 0 + ): + with ignore_connection_errors(context="get statuses"): + self._update_statuses(df) + status_histogram = df.groupby("status").size().to_dict() + _log.info(f"Status histogram: {status_histogram}") + self._persists(df, output_file) + + if len(df[df.status == "not_started"]) > 0: + # Check number of jobs running at each backend + running = df[ + (df.status == "created") + | (df.status == "queued") + | (df.status == "running") + ] + per_backend = running.groupby("backend_name").size().to_dict() + _log.info(f"Running per backend: {per_backend}") + for backend_name in self.backends: + backend_load = per_backend.get(backend_name, 0) + if backend_load < self.backends[backend_name].parallel_jobs: + to_add = ( + self.backends[backend_name].parallel_jobs - backend_load + ) + to_launch = df[df.status == "not_started"].iloc[0:to_add] + for i in to_launch.index: + self._launch_job(start_job, df, i, backend_name) + self._persists(df, output_file) + + time.sleep(self.poll_sleep) + + def _launch_job(self, start_job, df, i, backend_name): + """Helper method for launching jobs + + :param start_job: + A callback which will be invoked with the row of the dataframe for which a job should be started. + This callable should return a :py:class:`openeo.rest.job.BatchJob` object. + + See also: + `MultiBackendJobManager.run_jobs` for the parameters and return type of this callable + + Even though it is called here in `_launch_job` and that is where the constraints + really come from, the public method `run_jobs` needs to document `start_job` anyway, + so let's avoid duplication in the docstrings. + + :param df: + DataFrame that specifies the jobs, and tracks the jobs' statuses. + + :param i: + index of the job's row in dataframe df + + :param backend_name: + name of the backend that will execute the job. + """ + + df.loc[i, "backend_name"] = backend_name + row = df.loc[i] + try: + _log.info(f"Starting job on backend {backend_name} for {row.to_dict()}") + connection = self._get_connection(backend_name, resilient=True) + + job = start_job( + row=row, + connection_provider=self._get_connection, + connection=connection, + provider=backend_name, + ) + except requests.exceptions.ConnectionError as e: + _log.warning(f"Failed to start job for {row.to_dict()}", exc_info=True) + df.loc[i, "status"] = "start_failed" + else: + df.loc[i, "start_time"] = datetime.datetime.now().isoformat() + if job: + df.loc[i, "id"] = job.job_id + with ignore_connection_errors(context="get status"): + status = job.status() + df.loc[i, "status"] = status + if status == "created": + # start job if not yet done by callback + try: + job.start() + df.loc[i, "status"] = job.status() + except OpenEoApiError as e: + _log.error(e) + df.loc[i, "status"] = "start_failed" + else: + df.loc[i, "status"] = "skipped" + + def on_job_done(self, job: BatchJob, row): + """ + Handles jobs that have finished. Can be overridden to provide custom behaviour. + + Default implementation downloads the results into a folder containing the title. + + :param job: The job that has finished. + :param row: DataFrame row containing the job's metadata. + """ + # TODO: param `row` is never accessed in this method. Remove it? Is this intended for future use? + + job_metadata = job.describe() + job_dir = self.get_job_dir(job.job_id) + metadata_path = self.get_job_metadata_path(job.job_id) + + self.ensure_job_dir_exists(job.job_id) + job.get_results().download_files(target=job_dir) + + with open(metadata_path, "w") as f: + json.dump(job_metadata, f, ensure_ascii=False) + + def on_job_error(self, job: BatchJob, row): + """ + Handles jobs that stopped with errors. Can be overridden to provide custom behaviour. + + Default implementation writes the error logs to a JSON file. + + :param job: The job that has finished. + :param row: DataFrame row containing the job's metadata. + """ + # TODO: param `row` is never accessed in this method. Remove it? Is this intended for future use? + + error_logs = job.logs(level="error") + error_log_path = self.get_error_log_path(job.job_id) + + if len(error_logs) > 0: + self.ensure_job_dir_exists(job.job_id) + error_log_path.write_text(json.dumps(error_logs, indent=2)) + + def get_job_dir(self, job_id: str) -> Path: + """Path to directory where job metadata, results and error logs are be saved.""" + return self._root_dir / f"job_{job_id}" + + def get_error_log_path(self, job_id: str) -> Path: + """Path where error log file for the job is saved.""" + return self.get_job_dir(job_id) / f"job_{job_id}_errors.json" + + def get_job_metadata_path(self, job_id: str) -> Path: + """Path where job metadata file is saved.""" + return self.get_job_dir(job_id) / f"job_{job_id}.json" + + def ensure_job_dir_exists(self, job_id: str) -> Path: + """Create the job folder if it does not exist yet.""" + job_dir = self.get_job_dir(job_id) + if not job_dir.exists(): + job_dir.mkdir(parents=True) + + def _update_statuses(self, df: pd.DataFrame): + """Update status (and stats) of running jobs (in place).""" + active = df.loc[ + (df.status == "created") + | (df.status == "queued") + | (df.status == "running") + ] + for i in active.index: + job_id = df.loc[i, "id"] + backend_name = df.loc[i, "backend_name"] + + try: + con = self._get_connection(backend_name) + the_job = con.job(job_id) + job_metadata = the_job.describe() + _log.info( + f"Status of job {job_id!r} (on backend {backend_name}) is {job_metadata['status']!r}" + ) + if job_metadata["status"] == "finished": + self.on_job_done(the_job, df.loc[i]) + if df.loc[i, "status"] != "error" and job_metadata["status"] == "error": + self.on_job_error(the_job, df.loc[i]) + + df.loc[i, "status"] = job_metadata["status"] + for key in job_metadata.get("usage", {}).keys(): + df.loc[i, key] = _format_usage_stat(job_metadata, key) + + except OpenEoApiError as e: + print(f"error for job {job_id!r} on backend {backend_name}") + print(e) + + +def _format_usage_stat(job_metadata: dict, field: str) -> str: + value = deep_get(job_metadata, "usage", field, "value", default=0) + unit = deep_get(job_metadata, "usage", field, "unit", default="") + return f"{value} {unit}".strip() + + +@contextlib.contextmanager +def ignore_connection_errors(context: Optional[str] = None): + """Context manager to ignore connection errors.""" + try: + yield + except requests.exceptions.ConnectionError as e: + _log.warning(f"Ignoring connection error (context {context or 'n/a'}): {e}") + # Back off a bit + time.sleep(5) diff --git a/lib/openeo/extra/spectral_indices/__init__.py b/lib/openeo/extra/spectral_indices/__init__.py new file mode 100644 index 000000000..d83c37813 --- /dev/null +++ b/lib/openeo/extra/spectral_indices/__init__.py @@ -0,0 +1,2 @@ + +from openeo.extra.spectral_indices.spectral_indices import * diff --git a/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/LICENSE b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/LICENSE new file mode 100644 index 000000000..7bd30da58 --- /dev/null +++ b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 David Montero Loaiza + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/bands.json b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/bands.json new file mode 100644 index 000000000..052f82015 --- /dev/null +++ b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/bands.json @@ -0,0 +1,785 @@ +{ + "A": { + "common_name": "coastal", + "long_name": "Aersols", + "max_wavelength": 455, + "min_wavelength": 400, + "platforms": { + "landsat8": { + "band": "B1", + "bandwidth": 20.0, + "name": "Coastal Aerosol", + "platform": "Landsat 8", + "wavelength": 440.0 + }, + "landsat9": { + "band": "B1", + "bandwidth": 20.0, + "name": "Coastal Aerosol", + "platform": "Landsat 8", + "wavelength": 440.0 + }, + "planetscope": { + "band": "B1", + "bandwidth": 21.0, + "name": "Coastal Blue", + "platform": "PlanetScope", + "wavelength": 441.5 + }, + "sentinel2a": { + "band": "B1", + "bandwidth": 21, + "name": "Aerosols", + "platform": "Sentinel-2A", + "wavelength": 442.7 + }, + "sentinel2b": { + "band": "B1", + "bandwidth": 21, + "name": "Aerosols", + "platform": "Sentinel-2B", + "wavelength": 442.3 + }, + "wv2": { + "band": "B1", + "bandwidth": 50.0, + "name": "Coastal Blue", + "platform": "WorldView-2", + "wavelength": 425.0 + }, + "wv3": { + "band": "B1", + "bandwidth": 50.0, + "name": "Coastal Blue", + "platform": "WorldView-3", + "wavelength": 425.0 + } + }, + "short_name": "A" + }, + "B": { + "common_name": "blue", + "long_name": "Blue", + "max_wavelength": 530, + "min_wavelength": 450, + "platforms": { + "landsat4": { + "band": "B1", + "bandwidth": 70.0, + "name": "Blue", + "platform": "Landsat 4", + "wavelength": 485.0 + }, + "landsat5": { + "band": "B1", + "bandwidth": 70.0, + "name": "Blue", + "platform": "Landsat 5", + "wavelength": 485.0 + }, + "landsat7": { + "band": "B1", + "bandwidth": 70.0, + "name": "Blue", + "platform": "Landsat 7", + "wavelength": 485.0 + }, + "landsat8": { + "band": "B2", + "bandwidth": 60.0, + "name": "Blue", + "platform": "Landsat 8", + "wavelength": 480.0 + }, + "landsat9": { + "band": "B2", + "bandwidth": 60.0, + "name": "Blue", + "platform": "Landsat 9", + "wavelength": 480.0 + }, + "modis": { + "band": "B3", + "bandwidth": 20.0, + "name": "Blue", + "platform": "Terra/Aqua: MODIS", + "wavelength": 469.0 + }, + "planetscope": { + "band": "B2", + "bandwidth": 50.0, + "name": "Blue", + "platform": "PlanetScope", + "wavelength": 490.0 + }, + "sentinel2a": { + "band": "B2", + "bandwidth": 66.0, + "name": "Blue", + "platform": "Sentinel-2A", + "wavelength": 492.4 + }, + "sentinel2b": { + "band": "B2", + "bandwidth": 66.0, + "name": "Blue", + "platform": "Sentinel-2B", + "wavelength": 492.1 + }, + "wv2": { + "band": "B2", + "bandwidth": 60.0, + "name": "Blue", + "platform": "WorldView-2", + "wavelength": 480.0 + }, + "wv3": { + "band": "B2", + "bandwidth": 60.0, + "name": "Blue", + "platform": "WorldView-3", + "wavelength": 480.0 + } + }, + "short_name": "B" + }, + "G": { + "common_name": "green", + "long_name": "Green", + "max_wavelength": 600, + "min_wavelength": 510, + "platforms": { + "landsat4": { + "band": "B2", + "bandwidth": 80.0, + "name": "Green", + "platform": "Landsat 4", + "wavelength": 560.0 + }, + "landsat5": { + "band": "B2", + "bandwidth": 80.0, + "name": "Green", + "platform": "Landsat 5", + "wavelength": 560.0 + }, + "landsat7": { + "band": "B2", + "bandwidth": 80.0, + "name": "Green", + "platform": "Landsat 7", + "wavelength": 560.0 + }, + "landsat8": { + "band": "B3", + "bandwidth": 60.0, + "name": "Green", + "platform": "Landsat 8", + "wavelength": 560.0 + }, + "landsat9": { + "band": "B3", + "bandwidth": 60.0, + "name": "Green", + "platform": "Landsat 9", + "wavelength": 560.0 + }, + "modis": { + "band": "B4", + "bandwidth": 20.0, + "name": "Green", + "platform": "Terra/Aqua: MODIS", + "wavelength": 555.0 + }, + "planetscope": { + "band": "B4", + "bandwidth": 36.0, + "name": "Green", + "platform": "PlanetScope", + "wavelength": 565.0 + }, + "sentinel2a": { + "band": "B3", + "bandwidth": 36.0, + "name": "Green", + "platform": "Sentinel-2A", + "wavelength": 559.8 + }, + "sentinel2b": { + "band": "B3", + "bandwidth": 36.0, + "name": "Green", + "platform": "Sentinel-2B", + "wavelength": 559.0 + }, + "wv2": { + "band": "B3", + "bandwidth": 70.0, + "name": "Green", + "platform": "WorldView-2", + "wavelength": 545.0 + }, + "wv3": { + "band": "B3", + "bandwidth": 70.0, + "name": "Green", + "platform": "WorldView-3", + "wavelength": 545.0 + } + }, + "short_name": "G" + }, + "G1": { + "common_name": "green", + "long_name": "Green 1", + "max_wavelength": 550, + "min_wavelength": 510, + "platforms": { + "modis": { + "band": "B11", + "bandwidth": 10.0, + "name": "Green", + "platform": "Terra/Aqua: MODIS", + "wavelength": 531.0 + }, + "planetscope": { + "band": "B3", + "bandwidth": 36.0, + "name": "Green", + "platform": "PlanetScope", + "wavelength": 531.0 + } + }, + "short_name": "G1" + }, + "N": { + "common_name": "nir", + "long_name": "Near-Infrared (NIR)", + "max_wavelength": 900, + "min_wavelength": 760, + "platforms": { + "landsat4": { + "band": "B4", + "bandwidth": 140.0, + "name": "Near-Infrared (NIR)", + "platform": "Landsat 4", + "wavelength": 830.0 + }, + "landsat5": { + "band": "B4", + "bandwidth": 140.0, + "name": "Near-Infrared (NIR)", + "platform": "Landsat 5", + "wavelength": 830.0 + }, + "landsat7": { + "band": "B4", + "bandwidth": 130.0, + "name": "Near-Infrared (NIR)", + "platform": "Landsat 7", + "wavelength": 835.0 + }, + "landsat8": { + "band": "B5", + "bandwidth": 30.0, + "name": "Near-Infrared (NIR)", + "platform": "Landsat 8", + "wavelength": 865.0 + }, + "landsat9": { + "band": "B5", + "bandwidth": 30.0, + "name": "Near-Infrared (NIR)", + "platform": "Landsat 9", + "wavelength": 865.0 + }, + "modis": { + "band": "B2", + "bandwidth": 35.0, + "name": "Near-Infrared (NIR)", + "platform": "Terra/Aqua: MODIS", + "wavelength": 858.5 + }, + "planetscope": { + "band": "B8", + "bandwidth": 40.0, + "name": "Near-Infrared (NIR)", + "platform": "PlanetScope", + "wavelength": 865.0 + }, + "sentinel2a": { + "band": "B8", + "bandwidth": 106.0, + "name": "Near-Infrared (NIR)", + "platform": "Sentinel-2A", + "wavelength": 832.8 + }, + "sentinel2b": { + "band": "B8", + "bandwidth": 106.0, + "name": "Near-Infrared (NIR)", + "platform": "Sentinel-2B", + "wavelength": 833.0 + }, + "wv2": { + "band": "B7", + "bandwidth": 125.0, + "name": "Near-IR1", + "platform": "WorldView-2", + "wavelength": 832.5 + }, + "wv3": { + "band": "B7", + "bandwidth": 125.0, + "name": "Near-IR1", + "platform": "WorldView-3", + "wavelength": 832.5 + } + }, + "short_name": "N" + }, + "N2": { + "common_name": "nir08", + "long_name": "Near-Infrared (NIR) 2", + "max_wavelength": 880, + "min_wavelength": 850, + "platforms": { + "sentinel2a": { + "band": "B8A", + "bandwidth": 21.0, + "name": "Near-Infrared (NIR) 2 (Red Edge 4 in Google Earth Engine)", + "platform": "Sentinel-2A", + "wavelength": 864.7 + }, + "sentinel2b": { + "band": "B8A", + "bandwidth": 21.0, + "name": "Near-Infrared (NIR) 2 (Red Edge 4 in Google Earth Engine)", + "platform": "Sentinel-2B", + "wavelength": 864.0 + } + }, + "short_name": "N2" + }, + "R": { + "common_name": "red", + "long_name": "Red", + "max_wavelength": 690, + "min_wavelength": 620, + "platforms": { + "landsat4": { + "band": "B3", + "bandwidth": 60.0, + "name": "Red", + "platform": "Landsat 4", + "wavelength": 660.0 + }, + "landsat5": { + "band": "B3", + "bandwidth": 60.0, + "name": "Red", + "platform": "Landsat 5", + "wavelength": 660.0 + }, + "landsat7": { + "band": "B3", + "bandwidth": 60.0, + "name": "Red", + "platform": "Landsat 7", + "wavelength": 660.0 + }, + "landsat8": { + "band": "B4", + "bandwidth": 30.0, + "name": "Red", + "platform": "Landsat 8", + "wavelength": 655.0 + }, + "landsat9": { + "band": "B4", + "bandwidth": 30.0, + "name": "Red", + "platform": "Landsat 9", + "wavelength": 655.0 + }, + "modis": { + "band": "B1", + "bandwidth": 50.0, + "name": "Red", + "platform": "Terra/Aqua: MODIS", + "wavelength": 645.0 + }, + "planetscope": { + "band": "B6", + "bandwidth": 30.0, + "name": "Red", + "platform": "PlanetScope", + "wavelength": 665.0 + }, + "sentinel2a": { + "band": "B4", + "bandwidth": 31.0, + "name": "Red", + "platform": "Sentinel-2A", + "wavelength": 664.6 + }, + "sentinel2b": { + "band": "B4", + "bandwidth": 31.0, + "name": "Red", + "platform": "Sentinel-2B", + "wavelength": 665.0 + }, + "wv2": { + "band": "B5", + "bandwidth": 60.0, + "name": "Red", + "platform": "WorldView-2", + "wavelength": 660.0 + }, + "wv3": { + "band": "B5", + "bandwidth": 60.0, + "name": "Red", + "platform": "WorldView-3", + "wavelength": 660.0 + } + }, + "short_name": "R" + }, + "RE1": { + "common_name": "rededge", + "long_name": "Red Edge 1", + "max_wavelength": 715, + "min_wavelength": 695, + "platforms": { + "planetscope": { + "band": "B7", + "bandwidth": 16.0, + "name": "Red Edge", + "platform": "PlanetScope", + "wavelength": 705.0 + }, + "sentinel2a": { + "band": "B5", + "bandwidth": 15.0, + "name": "Red Edge 1", + "platform": "Sentinel-2A", + "wavelength": 704.1 + }, + "sentinel2b": { + "band": "B5", + "bandwidth": 15.0, + "name": "Red Edge 1", + "platform": "Sentinel-2B", + "wavelength": 703.8 + } + }, + "short_name": "RE1" + }, + "RE2": { + "common_name": "rededge", + "long_name": "Red Edge 2", + "max_wavelength": 750, + "min_wavelength": 730, + "platforms": { + "sentinel2a": { + "band": "B6", + "bandwidth": 15.0, + "name": "Red Edge 2", + "platform": "Sentinel-2A", + "wavelength": 740.5 + }, + "sentinel2b": { + "band": "B6", + "bandwidth": 15.0, + "name": "Red Edge 2", + "platform": "Sentinel-2B", + "wavelength": 739.1 + } + }, + "short_name": "RE2" + }, + "RE3": { + "common_name": "rededge", + "long_name": "Red Edge 3", + "max_wavelength": 795, + "min_wavelength": 765, + "platforms": { + "sentinel2a": { + "band": "B7", + "bandwidth": 20.0, + "name": "Red Edge 3", + "platform": "Sentinel-2A", + "wavelength": 782.8 + }, + "sentinel2b": { + "band": "B7", + "bandwidth": 20.0, + "name": "Red Edge 3", + "platform": "Sentinel-2B", + "wavelength": 779.7 + } + }, + "short_name": "RE3" + }, + "S1": { + "common_name": "swir16", + "long_name": "Short-wave Infrared (SWIR) 1", + "max_wavelength": 1750, + "min_wavelength": 1550, + "platforms": { + "landsat4": { + "band": "B5", + "bandwidth": 200.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Landsat 4", + "wavelength": 1650.0 + }, + "landsat5": { + "band": "B5", + "bandwidth": 200.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Landsat 5", + "wavelength": 1650.0 + }, + "landsat7": { + "band": "B5", + "bandwidth": 200.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Landsat 7", + "wavelength": 1650.0 + }, + "landsat8": { + "band": "B6", + "bandwidth": 80.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Landsat 8", + "wavelength": 1610.0 + }, + "landsat9": { + "band": "B6", + "bandwidth": 80.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Landsat 9", + "wavelength": 1610.0 + }, + "modis": { + "band": "B6", + "bandwidth": 24.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Terra/Aqua: MODIS", + "wavelength": 1640.0 + }, + "sentinel2a": { + "band": "B11", + "bandwidth": 91.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Sentinel-2A", + "wavelength": 1613.7 + }, + "sentinel2b": { + "band": "B11", + "bandwidth": 94.0, + "name": "Short-wave Infrared (SWIR) 1", + "platform": "Sentinel-2B", + "wavelength": 1610.4 + } + }, + "short_name": "S1" + }, + "S2": { + "common_name": "swir22", + "long_name": "Short-wave Infrared (SWIR) 2", + "max_wavelength": 2350, + "min_wavelength": 2080, + "platforms": { + "landsat4": { + "band": "B7", + "bandwidth": 270.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Landsat 4", + "wavelength": 2215.0 + }, + "landsat5": { + "band": "B7", + "bandwidth": 270.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Landsat 5", + "wavelength": 2215.0 + }, + "landsat7": { + "band": "B7", + "bandwidth": 260.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Landsat 7", + "wavelength": 2220.0 + }, + "landsat8": { + "band": "B7", + "bandwidth": 180.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Landsat 8", + "wavelength": 2200.0 + }, + "landsat9": { + "band": "B7", + "bandwidth": 180.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Landsat 9", + "wavelength": 2200.0 + }, + "modis": { + "band": "B7", + "bandwidth": 50.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Terra/Aqua: MODIS", + "wavelength": 2130.0 + }, + "sentinel2a": { + "band": "B12", + "bandwidth": 175.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Sentinel-2A", + "wavelength": 2202.4 + }, + "sentinel2b": { + "band": "B12", + "bandwidth": 185.0, + "name": "Short-wave Infrared (SWIR) 2", + "platform": "Sentinel-2B", + "wavelength": 2185.7 + } + }, + "short_name": "S2" + }, + "T": { + "common_name": "lwir", + "long_name": "Thermal Infrared", + "max_wavelength": 12500, + "min_wavelength": 10400, + "platforms": { + "landsat4": { + "band": "B6", + "bandwidth": 2100.0, + "name": "Thermal Infrared", + "platform": "Landsat 4", + "wavelength": 11450.0 + }, + "landsat5": { + "band": "B6", + "bandwidth": 2100.0, + "name": "Thermal Infrared", + "platform": "Landsat 5", + "wavelength": 11450.0 + }, + "landsat7": { + "band": "B6", + "bandwidth": 2100.0, + "name": "Thermal Infrared", + "platform": "Landsat 7", + "wavelength": 11450.0 + } + }, + "short_name": "T" + }, + "T1": { + "common_name": "lwir11", + "long_name": "Thermal Infrared 1", + "max_wavelength": 11190, + "min_wavelength": 10600, + "platforms": { + "landsat8": { + "band": "B10", + "bandwidth": 590.0, + "name": "Thermal Infrared 1", + "platform": "Landsat 8", + "wavelength": 10895.0 + }, + "landsat9": { + "band": "B10", + "bandwidth": 590.0, + "name": "Thermal Infrared 1", + "platform": "Landsat 9", + "wavelength": 10895.0 + } + }, + "short_name": "T1" + }, + "T2": { + "common_name": "lwir12", + "long_name": "Thermal Infrared 2", + "max_wavelength": 12510, + "min_wavelength": 11500, + "platforms": { + "landsat8": { + "band": "B11", + "bandwidth": 1010.0, + "name": "Thermal Infrared 2", + "platform": "Landsat 8", + "wavelength": 12005.0 + }, + "landsat9": { + "band": "B11", + "bandwidth": 1010.0, + "name": "Thermal Infrared 2", + "platform": "Landsat 9", + "wavelength": 12005.0 + } + }, + "short_name": "T2" + }, + "WV": { + "common_name": "nir09", + "long_name": "Water Vapour", + "max_wavelength": 960, + "min_wavelength": 930, + "platforms": { + "sentinel2a": { + "band": "B9", + "bandwidth": 20.0, + "name": "Water Vapour", + "platform": "Sentinel-2A", + "wavelength": 945.1 + }, + "sentinel2b": { + "band": "B9", + "bandwidth": 21.0, + "name": "Water Vapour", + "platform": "Sentinel-2B", + "wavelength": 943.2 + } + }, + "short_name": "WV" + }, + "Y": { + "common_name": "yellow", + "long_name": "Yellow", + "max_wavelength": 625, + "min_wavelength": 585, + "platforms": { + "planetscope": { + "band": "B5", + "bandwidth": 20.0, + "name": "Yellow", + "platform": "PlanetScope", + "wavelength": 610.0 + }, + "wv2": { + "band": "B4", + "bandwidth": 40.0, + "name": "Yellow", + "platform": "WorldView-2", + "wavelength": 605.0 + }, + "wv3": { + "band": "B4", + "bandwidth": 40.0, + "name": "Yellow", + "platform": "WorldView-3", + "wavelength": 605.0 + } + }, + "short_name": "Y" + } +} diff --git a/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/constants.json b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/constants.json new file mode 100644 index 000000000..3aa7cd7b5 --- /dev/null +++ b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/constants.json @@ -0,0 +1,107 @@ +{ + "C1": { + "default": 6.0, + "description": "Coefficient 1 for the aerosol resistance term", + "short_name": "C1" + }, + "C2": { + "default": 7.5, + "description": "Coefficient 2 for the aerosol resistance term", + "short_name": "C2" + }, + "L": { + "default": 1.0, + "description": "Canopy background adjustment", + "short_name": "L" + }, + "PAR": { + "default": null, + "description": "Photosynthetically Active Radiation", + "short_name": "PAR" + }, + "alpha": { + "default": 0.1, + "description": "Weighting coefficient used for WDRVI", + "short_name": "alpha" + }, + "beta": { + "default": 0.05, + "description": "Calibration parameter used for NDSInw", + "short_name": "beta" + }, + "c": { + "default": 1.0, + "description": "Trade-off parameter in the polynomial kernel", + "short_name": "c" + }, + "cexp": { + "default": 1.16, + "description": "Exponent used for OCVI", + "short_name": "cexp" + }, + "fdelta": { + "default": 0.581, + "description": "Adjustment factor used for SEVI", + "short_name": "fdelta" + }, + "g": { + "default": 2.5, + "description": "Gain factor", + "short_name": "g" + }, + "gamma": { + "default": 1.0, + "description": "Weighting coefficient used for ARVI", + "short_name": "gamma" + }, + "k": { + "default": 0.0, + "description": "Slope parameter by soil used for NIRvH2", + "short_name": "k" + }, + "lambdaG": { + "default": null, + "description": "Green wavelength (nm) used for NDGI", + "short_name": "lambdaG" + }, + "lambdaN": { + "default": null, + "description": "NIR wavelength (nm) used for NIRvH2 and NDGI", + "short_name": "lambdaN" + }, + "lambdaR": { + "default": null, + "description": "Red wavelength (nm) used for NIRvH2 and NDGI", + "short_name": "lambdaR" + }, + "nexp": { + "default": 2.0, + "description": "Exponent used for GDVI", + "short_name": "nexp" + }, + "omega": { + "default": 2.0, + "description": "Weighting coefficient used for MBWI", + "short_name": "omega" + }, + "p": { + "default": 2.0, + "description": "Kernel degree in the polynomial kernel", + "short_name": "p" + }, + "sigma": { + "default": 0.5, + "description": "Length-scale parameter in the RBF kernel", + "short_name": "sigma" + }, + "sla": { + "default": 1.0, + "description": "Soil line slope", + "short_name": "sla" + }, + "slb": { + "default": 0.0, + "description": "Soil line intercept", + "short_name": "slb" + } +} diff --git a/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/spectral-indices-dict.json b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/spectral-indices-dict.json new file mode 100644 index 000000000..04fbce636 --- /dev/null +++ b/lib/openeo/extra/spectral_indices/resources/awesome-spectral-indices/spectral-indices-dict.json @@ -0,0 +1,4616 @@ +{ + "SpectralIndices": { + "AFRI1600": { + "application_domain": "vegetation", + "bands": [ + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-17", + "formula": "(N - 0.66 * S1) / (N + 0.66 * S1)", + "long_name": "Aerosol Free Vegetation Index (1600 nm)", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/S0034-4257(01)00190-0", + "short_name": "AFRI1600" + }, + "AFRI2100": { + "application_domain": "vegetation", + "bands": [ + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-17", + "formula": "(N - 0.5 * S2) / (N + 0.5 * S2)", + "long_name": "Aerosol Free Vegetation Index (2100 nm)", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/S0034-4257(01)00190-0", + "short_name": "AFRI2100" + }, + "ANDWI": { + "application_domain": "water", + "bands": [ + "B", + "G", + "R", + "N", + "S1", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "(B + G + R - N - S1 - S2)/(B + G + R + N + S1 + S2)", + "long_name": "Augmented Normalized Difference Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.envsoft.2021.105030", + "short_name": "ANDWI" + }, + "ARI": { + "application_domain": "vegetation", + "bands": [ + "G", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-20", + "formula": "(1 / G) - (1 / RE1)", + "long_name": "Anthocyanin Reflectance Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1562/0031-8655(2001)074%3C0038:OPANEO%3E2.0.CO;2", + "short_name": "ARI" + }, + "ARI2": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "N * ((1 / G) - (1 / RE1))", + "long_name": "Anthocyanin Reflectance Index 2", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1562/0031-8655(2001)074%3C0038:OPANEO%3E2.0.CO;2", + "short_name": "ARI2" + }, + "ARVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "gamma", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-11", + "formula": "(N - (R - gamma * (R - B))) / (N + (R - gamma * (R - B)))", + "long_name": "Atmospherically Resistant Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1109/36.134076", + "short_name": "ARVI" + }, + "ATSAVI": { + "application_domain": "vegetation", + "bands": [ + "sla", + "N", + "R", + "slb" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "sla * (N - sla * R - slb) / (sla * N + R - sla * slb + 0.08 * (1 + sla ** 2.0))", + "long_name": "Adjusted Transformed Soil-Adjusted Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(91)90009-U", + "short_name": "ATSAVI" + }, + "AVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(N * (1.0 - R) * (N - R)) ** (1/3)", + "long_name": "Advanced Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.465.8749&rep=rep1&type=pdf", + "short_name": "AVI" + }, + "AWEInsh": { + "application_domain": "water", + "bands": [ + "G", + "S1", + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "4.0 * (G - S1) - 0.25 * N + 2.75 * S2", + "long_name": "Automated Water Extraction Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.rse.2013.08.029", + "short_name": "AWEInsh" + }, + "AWEIsh": { + "application_domain": "water", + "bands": [ + "B", + "G", + "N", + "S1", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "B + 2.5 * G - 1.5 * (N + S1) - 0.25 * S2", + "long_name": "Automated Water Extraction Index with Shadows Elimination", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.rse.2013.08.029", + "short_name": "AWEIsh" + }, + "BAI": { + "application_domain": "burn", + "bands": [ + "R", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "1.0 / ((0.1 - R) ** 2.0 + (0.06 - N) ** 2.0)", + "long_name": "Burned Area Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://digital.csic.es/bitstream/10261/6426/1/Martin_Isabel_Serie_Geografica.pdf", + "short_name": "BAI" + }, + "BAIM": { + "application_domain": "burn", + "bands": [ + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-20", + "formula": "1.0/((0.05 - N) ** 2.0) + ((0.2 - S2) ** 2.0)", + "long_name": "Burned Area Index adapted to MODIS", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.foreco.2006.08.248", + "short_name": "BAIM" + }, + "BAIS2": { + "application_domain": "burn", + "bands": [ + "RE2", + "RE3", + "N2", + "R", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(1.0 - ((RE2 * RE3 * N2) / R) ** 0.5) * (((S2 - N2)/(S2 + N2) ** 0.5) + 1.0)", + "long_name": "Burned Area Index for Sentinel 2", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/ecrs-2-05177", + "short_name": "BAIS2" + }, + "BCC": { + "application_domain": "vegetation", + "bands": [ + "B", + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "B / (R + G + B)", + "long_name": "Blue Chromatic Coordinate", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(87)90088-5", + "short_name": "BCC" + }, + "BI": { + "application_domain": "soil", + "bands": [ + "S1", + "R", + "N", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "((S1 + R) - (N + B))/((S1 + R) + (N + B))", + "long_name": "Bare Soil Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.465.8749&rep=rep1&type=pdf", + "short_name": "BI" + }, + "BITM": { + "application_domain": "soil", + "bands": [ + "B", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-11-20", + "formula": "(((B**2.0)+(G**2.0)+(R**2.0))/3.0)**0.5", + "long_name": "Landsat TM-based Brightness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(98)00030-3", + "short_name": "BITM" + }, + "BIXS": { + "application_domain": "soil", + "bands": [ + "G", + "R" + ], + "contributor": "https://github.com/remi-braun", + "date_of_addition": "2022-11-20", + "formula": "(((G**2.0)+(R**2.0))/2.0)**0.5", + "long_name": "SPOT HRV XS-based Brightness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(98)00030-3", + "short_name": "BIXS" + }, + "BLFEI": { + "application_domain": "urban", + "bands": [ + "G", + "R", + "S2", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-02-09", + "formula": "(((G+R+S2)/3.0)-S1)/(((G+R+S2)/3.0)+S1)", + "long_name": "Built-Up Land Features Extraction Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/10106049.2018.1497094", + "short_name": "BLFEI" + }, + "BNDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "B" + ], + "contributor": "https://github.com/MATRIX4284", + "date_of_addition": "2021-04-07", + "formula": "(N - B)/(N + B)", + "long_name": "Blue Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S1672-6308(07)60027-4", + "short_name": "BNDVI" + }, + "BRBA": { + "application_domain": "urban", + "bands": [ + "R", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "R/S1", + "long_name": "Band Ratio for Built-up Area", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://www.omicsonline.org/scientific-reports/JGRS-SR136.pdf", + "short_name": "BRBA" + }, + "BWDRVI": { + "application_domain": "vegetation", + "bands": [ + "alpha", + "N", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-20", + "formula": "(alpha * N - B) / (alpha * N + B)", + "long_name": "Blue Wide Dynamic Range Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2135/cropsci2007.01.0031", + "short_name": "BWDRVI" + }, + "BaI": { + "application_domain": "soil", + "bands": [ + "R", + "S1", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "R + S1 - N", + "long_name": "Bareness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1109/IGARSS.2005.1525743", + "short_name": "BaI" + }, + "CCI": { + "application_domain": "vegetation", + "bands": [ + "G1", + "R" + ], + "contributor": "https://github.com/joanvlasschaert", + "date_of_addition": "2023-03-12", + "formula": "(G1 - R)/(G1 + R)", + "long_name": "Chlorophyll Carotenoid Index", + "platforms": [ + "MODIS" + ], + "reference": "https://doi.org/10.1073/pnas.1606162113", + "short_name": "CCI" + }, + "CIG": { + "application_domain": "vegetation", + "bands": [ + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N / G) - 1.0", + "long_name": "Chlorophyll Index Green", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1078/0176-1617-00887", + "short_name": "CIG" + }, + "CIRE": { + "application_domain": "vegetation", + "bands": [ + "N", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-13", + "formula": "(N / RE1) - 1", + "long_name": "Chlorophyll Index Red Edge", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1078/0176-1617-00887", + "short_name": "CIRE" + }, + "CSI": { + "application_domain": "burn", + "bands": [ + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "N/S2", + "long_name": "Char Soil Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.rse.2005.04.014", + "short_name": "CSI" + }, + "CSIT": { + "application_domain": "burn", + "bands": [ + "N", + "S2", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "N / (S2 * T / 10000.0)", + "long_name": "Char Soil Index Thermal", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1080/01431160600954704", + "short_name": "CSIT" + }, + "CVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N * R) / (G ** 2.0)", + "long_name": "Chlorophyll Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1007/s11119-010-9204-3", + "short_name": "CVI" + }, + "DBI": { + "application_domain": "urban", + "bands": [ + "B", + "T1", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "((B - T1)/(B + T1)) - ((N - R)/(N + R))", + "long_name": "Dry Built-Up Index", + "platforms": [ + "Landsat-OLI" + ], + "reference": "https://doi.org/10.3390/land7030081", + "short_name": "DBI" + }, + "DBSI": { + "application_domain": "soil", + "bands": [ + "S1", + "G", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "((S1 - G)/(S1 + G)) - ((N - R)/(N + R))", + "long_name": "Dry Bareness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/land7030081", + "short_name": "DBSI" + }, + "DPDD": { + "application_domain": "radar", + "bands": [ + "VV", + "VH" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "(VV + VH)/2.0 ** 0.5", + "long_name": "Dual-Pol Diagonal Distance", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.1016/j.rse.2018.09.003", + "short_name": "DPDD" + }, + "DSI": { + "application_domain": "vegetation", + "bands": [ + "S1", + "N" + ], + "contributor": "https://github.com/remi-braun", + "date_of_addition": "2022-10-26", + "formula": "S1/N", + "long_name": "Drought Stress Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://www.asprs.org/wp-content/uploads/pers/1999journal/apr/1999_apr_495-501.pdf", + "short_name": "DSI" + }, + "DSWI1": { + "application_domain": "vegetation", + "bands": [ + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-10-29", + "formula": "N/S1", + "long_name": "Disease-Water Stress Index 1", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160310001618031", + "short_name": "DSWI1" + }, + "DSWI2": { + "application_domain": "vegetation", + "bands": [ + "S1", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-10-29", + "formula": "S1/G", + "long_name": "Disease-Water Stress Index 2", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160310001618031", + "short_name": "DSWI2" + }, + "DSWI3": { + "application_domain": "vegetation", + "bands": [ + "S1", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-10-29", + "formula": "S1/R", + "long_name": "Disease-Water Stress Index 3", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160310001618031", + "short_name": "DSWI3" + }, + "DSWI4": { + "application_domain": "vegetation", + "bands": [ + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-10-29", + "formula": "G/R", + "long_name": "Disease-Water Stress Index 4", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/01431160310001618031", + "short_name": "DSWI4" + }, + "DSWI5": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "S1", + "R" + ], + "contributor": "https://github.com/remi-braun", + "date_of_addition": "2022-10-26", + "formula": "(N + G)/(S1 + R)", + "long_name": "Disease-Water Stress Index 5", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160310001618031", + "short_name": "DSWI5" + }, + "DVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "N - R", + "long_name": "Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(94)00114-3", + "short_name": "DVI" + }, + "DVIplus": { + "application_domain": "vegetation", + "bands": [ + "lambdaN", + "lambdaR", + "lambdaG", + "G", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-20", + "formula": "((lambdaN - lambdaR)/(lambdaN - lambdaG)) * G + (1.0 - ((lambdaN - lambdaR)/(lambdaN - lambdaG))) * N - R", + "long_name": "Difference Vegetation Index Plus", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2019.03.028", + "short_name": "DVIplus" + }, + "DpRVIHH": { + "application_domain": "radar", + "bands": [ + "HV", + "HH" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-12-25", + "formula": "(4.0 * HV)/(HH + HV)", + "long_name": "Dual-Polarized Radar Vegetation Index HH", + "platforms": [ + "Sentinel-1 (Dual Polarisation HH-HV)" + ], + "reference": "https://www.tandfonline.com/doi/abs/10.5589/m12-043", + "short_name": "DpRVIHH" + }, + "DpRVIVV": { + "application_domain": "radar", + "bands": [ + "VH", + "VV" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-12-25", + "formula": "(4.0 * VH)/(VV + VH)", + "long_name": "Dual-Polarized Radar Vegetation Index VV", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.3390/app9040655", + "short_name": "DpRVIVV" + }, + "EBBI": { + "application_domain": "urban", + "bands": [ + "S1", + "N", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-17", + "formula": "(S1 - N) / (10.0 * ((S1 + T) ** 0.5))", + "long_name": "Enhanced Built-Up and Bareness Index", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.3390/rs4102957", + "short_name": "EBBI" + }, + "EMBI": { + "application_domain": "soil", + "bands": [ + "S1", + "S2", + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "((((S1 - S2 - N)/(S1 + S2 + N)) + 0.5) - ((G - S1)/(G + S1)) - 0.5)/((((S1 - S2 - N)/(S1 + S2 + N)) + 0.5) + ((G - S1)/(G + S1)) + 1.5)", + "long_name": "Enhanced Modified Bare Soil Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.jag.2022.102703", + "short_name": "EMBI" + }, + "EVI": { + "application_domain": "vegetation", + "bands": [ + "g", + "N", + "R", + "C1", + "C2", + "B", + "L" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "g * (N - R) / (N + C1 * R - C2 * B + L)", + "long_name": "Enhanced Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(96)00112-5", + "short_name": "EVI" + }, + "EVI2": { + "application_domain": "vegetation", + "bands": [ + "g", + "N", + "R", + "L" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "g * (N - R) / (N + 2.4 * R + L)", + "long_name": "Two-Band Enhanced Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2008.06.006", + "short_name": "EVI2" + }, + "ExG": { + "application_domain": "vegetation", + "bands": [ + "G", + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "2 * G - R - B", + "long_name": "Excess Green Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.13031/2013.27838", + "short_name": "ExG" + }, + "ExGR": { + "application_domain": "vegetation", + "bands": [ + "G", + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(2.0 * G - R - B) - (1.3 * R - G)", + "long_name": "ExG - ExR Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.compag.2008.03.009", + "short_name": "ExGR" + }, + "ExR": { + "application_domain": "vegetation", + "bands": [ + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "1.3 * R - G", + "long_name": "Excess Red Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1117/12.336896", + "short_name": "ExR" + }, + "FCVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "G", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-20", + "formula": "N - ((R + G + B)/3.0)", + "long_name": "Fluorescence Correction Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2020.111676", + "short_name": "FCVI" + }, + "GARI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "B", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - (G - (B - R))) / (N - (G + (B - R)))", + "long_name": "Green Atmospherically Resistant Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(96)00072-7", + "short_name": "GARI" + }, + "GBNDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - (G + B))/(N + (G + B))", + "long_name": "Green-Blue Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S1672-6308(07)60027-4", + "short_name": "GBNDVI" + }, + "GCC": { + "application_domain": "vegetation", + "bands": [ + "G", + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "G / (R + G + B)", + "long_name": "Green Chromatic Coordinate", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(87)90088-5", + "short_name": "GCC" + }, + "GDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "nexp", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "((N ** nexp) - (R ** nexp)) / ((N ** nexp) + (R ** nexp))", + "long_name": "Generalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.3390/rs6021211", + "short_name": "GDVI" + }, + "GEMI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "((2.0*((N ** 2.0)-(R ** 2.0)) + 1.5*N + 0.5*R)/(N + R + 0.5))*(1.0 - 0.25*((2.0 * ((N ** 2.0) - (R ** 2)) + 1.5 * N + 0.5 * R)/(N + R + 0.5)))-((R - 0.125)/(1 - R))", + "long_name": "Global Environment Monitoring Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "http://dx.doi.org/10.1007/bf00031911", + "short_name": "GEMI" + }, + "GLI": { + "application_domain": "vegetation", + "bands": [ + "G", + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(2.0 * G - R - B) / (2.0 * G + R + B)", + "long_name": "Green Leaf Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "http://dx.doi.org/10.1080/10106040108542184", + "short_name": "GLI" + }, + "GM1": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "RE2/G", + "long_name": "Gitelson and Merzlyak Index 1", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0176-1617(96)80284-7", + "short_name": "GM1" + }, + "GM2": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "RE2/RE1", + "long_name": "Gitelson and Merzlyak Index 2", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0176-1617(96)80284-7", + "short_name": "GM2" + }, + "GNDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - G)/(N + G)", + "long_name": "Green Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(96)00072-7", + "short_name": "GNDVI" + }, + "GOSAVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(N - G) / (N + G + 0.16)", + "long_name": "Green Optimized Soil Adjusted Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2134/agronj2004.0314", + "short_name": "GOSAVI" + }, + "GRNDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - (G + R))/(N + (G + R))", + "long_name": "Green-Red Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S1672-6308(07)60027-4", + "short_name": "GRNDVI" + }, + "GRVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "N/G", + "long_name": "Green Ratio Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2134/agronj2004.0314", + "short_name": "GRVI" + }, + "GSAVI": { + "application_domain": "vegetation", + "bands": [ + "L", + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(1.0 + L) * (N - G) / (N + G + L)", + "long_name": "Green Soil Adjusted Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2134/agronj2004.0314", + "short_name": "GSAVI" + }, + "GVMI": { + "application_domain": "vegetation", + "bands": [ + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "((N + 0.1) - (S2 + 0.02)) / ((N + 0.1) + (S2 + 0.02))", + "long_name": "Global Vegetation Moisture Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/S0034-4257(02)00037-8", + "short_name": "GVMI" + }, + "IAVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "gamma", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(N - (R - gamma * (B - R)))/(N + (R - gamma * (B - R)))", + "long_name": "New Atmospherically Resistant Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://www.jipb.net/EN/abstract/abstract23925.shtml", + "short_name": "IAVI" + }, + "IBI": { + "application_domain": "urban", + "bands": [ + "S1", + "N", + "R", + "L", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-02-09", + "formula": "(((S1-N)/(S1+N))-(((N-R)*(1.0+L)/(N+R+L))+((G-S1)/(G+S1)))/2.0)/(((S1-N)/(S1+N))+(((N-R)*(1.0+L)/(N+R+L))+((G-S1)/(G+S1)))/2.0)", + "long_name": "Index-Based Built-Up Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160802039957", + "short_name": "IBI" + }, + "IKAW": { + "application_domain": "vegetation", + "bands": [ + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(R - B)/(R + B)", + "long_name": "Kawashima Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1006/anbo.1997.0544", + "short_name": "IKAW" + }, + "IPVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "N/(N + R)", + "long_name": "Infrared Percentage Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(90)90085-Z", + "short_name": "IPVI" + }, + "IRECI": { + "application_domain": "vegetation", + "bands": [ + "RE3", + "R", + "RE1", + "RE2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-17", + "formula": "(RE3 - R) / (RE1 / RE2)", + "long_name": "Inverted Red-Edge Chlorophyll Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/j.isprsjprs.2013.04.007", + "short_name": "IRECI" + }, + "LSWI": { + "application_domain": "water", + "bands": [ + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-20", + "formula": "(N - S1)/(N + S1)", + "long_name": "Land Surface Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.rse.2003.11.008", + "short_name": "LSWI" + }, + "MBI": { + "application_domain": "soil", + "bands": [ + "S1", + "S2", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "((S1 - S2 - N)/(S1 + S2 + N)) + 0.5", + "long_name": "Modified Bare Soil Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/land10030231", + "short_name": "MBI" + }, + "MBWI": { + "application_domain": "water", + "bands": [ + "omega", + "G", + "R", + "N", + "S1", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "(omega * G) - R - N - S1 - S2", + "long_name": "Multi-Band Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.jag.2018.01.018", + "short_name": "MBWI" + }, + "MCARI": { + "application_domain": "vegetation", + "bands": [ + "RE1", + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-13", + "formula": "((RE1 - R) - 0.2 * (RE1 - G)) * (RE1 / R)", + "long_name": "Modified Chlorophyll Absorption in Reflectance Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "http://dx.doi.org/10.1016/S0034-4257(00)00113-9", + "short_name": "MCARI" + }, + "MCARI1": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "1.2 * (2.5 * (N - R) - 1.3 * (N - G))", + "long_name": "Modified Chlorophyll Absorption in Reflectance Index 1", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2003.12.013", + "short_name": "MCARI1" + }, + "MCARI2": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "(1.5 * (2.5 * (N - R) - 1.3 * (N - G))) / ((((2.0 * N + 1) ** 2) - (6.0 * N - 5 * (R ** 0.5)) - 0.5) ** 0.5)", + "long_name": "Modified Chlorophyll Absorption in Reflectance Index 2", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2003.12.013", + "short_name": "MCARI2" + }, + "MCARI705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "((RE2 - RE1) - 0.2 * (RE2 - G)) * (RE2 / RE1)", + "long_name": "Modified Chlorophyll Absorption in Reflectance Index (705 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/j.agrformet.2008.03.005", + "short_name": "MCARI705" + }, + "MCARIOSAVI": { + "application_domain": "vegetation", + "bands": [ + "RE1", + "R", + "G", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "(((RE1 - R) - 0.2 * (RE1 - G)) * (RE1 / R)) / (1.16 * (N - R) / (N + R + 0.16))", + "long_name": "MCARI/OSAVI Ratio", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(00)00113-9", + "short_name": "MCARIOSAVI" + }, + "MCARIOSAVI705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "(((RE2 - RE1) - 0.2 * (RE2 - G)) * (RE2 / RE1)) / (1.16 * (RE2 - RE1) / (RE2 + RE1 + 0.16))", + "long_name": "MCARI/OSAVI Ratio (705 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/j.agrformet.2008.03.005", + "short_name": "MCARIOSAVI705" + }, + "MGRVI": { + "application_domain": "vegetation", + "bands": [ + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "(G ** 2.0 - R ** 2.0) / (G ** 2.0 + R ** 2.0)", + "long_name": "Modified Green Red Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.jag.2015.02.012", + "short_name": "MGRVI" + }, + "MIRBI": { + "application_domain": "burn", + "bands": [ + "S2", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "10.0 * S2 - 9.8 * S1 + 2.0", + "long_name": "Mid-Infrared Burn Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160110053185", + "short_name": "MIRBI" + }, + "MLSWI26": { + "application_domain": "water", + "bands": [ + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-20", + "formula": "(1.0 - N - S1)/(1.0 - N + S1)", + "long_name": "Modified Land Surface Water Index (MODIS Bands 2 and 6)", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs71215805", + "short_name": "MLSWI26" + }, + "MLSWI27": { + "application_domain": "water", + "bands": [ + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-20", + "formula": "(1.0 - N - S2)/(1.0 - N + S2)", + "long_name": "Modified Land Surface Water Index (MODIS Bands 2 and 7)", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs71215805", + "short_name": "MLSWI27" + }, + "MNDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - S2)/(N + S2)", + "long_name": "Modified Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/014311697216810", + "short_name": "MNDVI" + }, + "MNDWI": { + "application_domain": "water", + "bands": [ + "G", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(G - S1) / (G + S1)", + "long_name": "Modified Normalized Difference Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160600589179", + "short_name": "MNDWI" + }, + "MNLI": { + "application_domain": "vegetation", + "bands": [ + "L", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-11", + "formula": "(1 + L)*((N ** 2) - R)/((N ** 2) + R + L)", + "long_name": "Modified Non-Linear Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1109/TGRS.2003.812910", + "short_name": "MNLI" + }, + "MRBVI": { + "application_domain": "vegetation", + "bands": [ + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(R ** 2.0 - B ** 2.0)/(R ** 2.0 + B ** 2.0)", + "long_name": "Modified Red Blue Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.3390/s20185055", + "short_name": "MRBVI" + }, + "MSAVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-13", + "formula": "0.5 * (2.0 * N + 1 - (((2 * N + 1) ** 2) - 8 * (N - R)) ** 0.5)", + "long_name": "Modified Soil-Adjusted Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(94)90134-1", + "short_name": "MSAVI" + }, + "MSI": { + "application_domain": "vegetation", + "bands": [ + "S1", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "S1/N", + "long_name": "Moisture Stress Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/0034-4257(89)90046-1", + "short_name": "MSI" + }, + "MSR": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "(N / R - 1) / ((N / R + 1) ** 0.5)", + "long_name": "Modified Simple Ratio", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/07038992.1996.10855178", + "short_name": "MSR" + }, + "MSR705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "(RE2 / RE1 - 1) / ((RE2 / RE1 + 1) ** 0.5)", + "long_name": "Modified Simple Ratio (705 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/j.agrformet.2008.03.005", + "short_name": "MSR705" + }, + "MTCI": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-13", + "formula": "(RE2 - RE1) / (RE1 - R)", + "long_name": "MERIS Terrestrial Chlorophyll Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1080/0143116042000274015", + "short_name": "MTCI" + }, + "MTVI1": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "1.2 * (1.2 * (N - G) - 2.5 * (R - G))", + "long_name": "Modified Triangular Vegetation Index 1", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2003.12.013", + "short_name": "MTVI1" + }, + "MTVI2": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "(1.5 * (1.2 * (N - G) - 2.5 * (R - G))) / ((((2.0 * N + 1) ** 2) - (6.0 * N - 5 * (R ** 0.5)) - 0.5) ** 0.5)", + "long_name": "Modified Triangular Vegetation Index 2", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2003.12.013", + "short_name": "MTVI2" + }, + "MuWIR": { + "application_domain": "water", + "bands": [ + "B", + "G", + "N", + "S2", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-09", + "formula": "-4.0 * ((B - G)/(B + G)) + 2.0 * ((G - N)/(G + N)) + 2.0 * ((G - S2)/(G + S2)) - ((G - S1)/(G + S1))", + "long_name": "Revised Multi-Spectral Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs10101643", + "short_name": "MuWIR" + }, + "NBAI": { + "application_domain": "urban", + "bands": [ + "S2", + "S1", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "((S2 - S1)/G)/((S2 + S1)/G)", + "long_name": "Normalized Built-up Area Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://www.omicsonline.org/scientific-reports/JGRS-SR136.pdf", + "short_name": "NBAI" + }, + "NBLI": { + "application_domain": "soil", + "bands": [ + "R", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(R - T)/(R + T)", + "long_name": "Normalized Difference Bare Land Index", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.3390/rs9030249", + "short_name": "NBLI" + }, + "NBLIOLI": { + "application_domain": "soil", + "bands": [ + "R", + "T1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2023-03-12", + "formula": "(R - T1)/(R + T1)", + "long_name": "Normalized Difference Bare Land Index for Landsat-OLI", + "platforms": [ + "Landsat-OLI" + ], + "reference": "https://doi.org/10.3390/rs9030249", + "short_name": "NBLIOLI" + }, + "NBR": { + "application_domain": "burn", + "bands": [ + "N", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - S2) / (N + S2)", + "long_name": "Normalized Burn Ratio", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3133/ofr0211", + "short_name": "NBR" + }, + "NBR2": { + "application_domain": "burn", + "bands": [ + "S1", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-20", + "formula": "(S1 - S2) / (S1 + S2)", + "long_name": "Normalized Burn Ratio 2", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://www.usgs.gov/core-science-systems/nli/landsat/landsat-normalized-burn-ratio-2", + "short_name": "NBR2" + }, + "NBRSWIR": { + "application_domain": "burn", + "bands": [ + "S2", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "(S2 - S1 - 0.02)/(S2 + S1 + 0.1)", + "long_name": "Normalized Burn Ratio SWIR", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/22797254.2020.1738900", + "short_name": "NBRSWIR" + }, + "NBRT1": { + "application_domain": "burn", + "bands": [ + "N", + "S2", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - (S2 * T / 10000.0)) / (N + (S2 * T / 10000.0))", + "long_name": "Normalized Burn Ratio Thermal 1", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1080/01431160500239008", + "short_name": "NBRT1" + }, + "NBRT2": { + "application_domain": "burn", + "bands": [ + "N", + "T", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "((N / (T / 10000.0)) - S2) / ((N / (T / 10000.0)) + S2)", + "long_name": "Normalized Burn Ratio Thermal 2", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1080/01431160500239008", + "short_name": "NBRT2" + }, + "NBRT3": { + "application_domain": "burn", + "bands": [ + "N", + "T", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "((N - (T / 10000.0)) - S2) / ((N - (T / 10000.0)) + S2)", + "long_name": "Normalized Burn Ratio Thermal 3", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1080/01431160500239008", + "short_name": "NBRT3" + }, + "NBRplus": { + "application_domain": "burn", + "bands": [ + "S2", + "N2", + "G", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "(S2 - N2 - G - B)/(S2 + N2 + G + B)", + "long_name": "Normalized Burn Ratio Plus", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/rs14071727", + "short_name": "NBRplus" + }, + "NBSIMS": { + "application_domain": "snow", + "bands": [ + "G", + "R", + "N", + "B", + "S2", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-09", + "formula": "0.36 * (G + R + N) - (((B + S2)/G) + S1)", + "long_name": "Non-Binary Snow Index for Multi-Component Surfaces", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs13142777", + "short_name": "NBSIMS" + }, + "NBUI": { + "application_domain": "urban", + "bands": [ + "S1", + "N", + "T", + "R", + "L", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "((S1 - N)/(10.0 * (T + S1) ** 0.5)) - (((N - R) * (1.0 + L))/(N - R + L)) - (G - S1)/(G + S1)", + "long_name": "New Built-Up Index", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://hdl.handle.net/1959.11/29500", + "short_name": "NBUI" + }, + "ND705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(RE2 - RE1)/(RE2 + RE1)", + "long_name": "Normalized Difference (705 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(02)00010-X", + "short_name": "ND705" + }, + "NDBI": { + "application_domain": "urban", + "bands": [ + "S1", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "(S1 - N) / (S1 + N)", + "long_name": "Normalized Difference Built-Up Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "http://dx.doi.org/10.1080/01431160304987", + "short_name": "NDBI" + }, + "NDBaI": { + "application_domain": "soil", + "bands": [ + "S1", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-17", + "formula": "(S1 - T) / (S1 + T)", + "long_name": "Normalized Difference Bareness Index", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1109/IGARSS.2005.1526319", + "short_name": "NDBaI" + }, + "NDCI": { + "application_domain": "water", + "bands": [ + "RE1", + "R" + ], + "contributor": "https://github.com/kalab-oto", + "date_of_addition": "2022-10-10", + "formula": "(RE1 - R)/(RE1 + R)", + "long_name": "Normalized Difference Chlorophyll Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/j.rse.2011.10.016", + "short_name": "NDCI" + }, + "NDDI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(((N - R)/(N + R)) - ((G - N)/(G + N)))/(((N - R)/(N + R)) + ((G - N)/(G + N)))", + "long_name": "Normalized Difference Drought Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1029/2006GL029127", + "short_name": "NDDI" + }, + "NDGI": { + "application_domain": "vegetation", + "bands": [ + "lambdaN", + "lambdaR", + "lambdaG", + "G", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-20", + "formula": "(((lambdaN - lambdaR)/(lambdaN - lambdaG)) * G + (1.0 - ((lambdaN - lambdaR)/(lambdaN - lambdaG))) * N - R)/(((lambdaN - lambdaR)/(lambdaN - lambdaG)) * G + (1.0 - ((lambdaN - lambdaR)/(lambdaN - lambdaG))) * N + R)", + "long_name": "Normalized Difference Greenness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2019.03.028", + "short_name": "NDGI" + }, + "NDGlaI": { + "application_domain": "snow", + "bands": [ + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(G - R)/(G + R)", + "long_name": "Normalized Difference Glacier Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/01431160802385459", + "short_name": "NDGlaI" + }, + "NDII": { + "application_domain": "vegetation", + "bands": [ + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-20", + "formula": "(N - S1)/(N + S1)", + "long_name": "Normalized Difference Infrared Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://www.asprs.org/wp-content/uploads/pers/1983journal/jan/1983_jan_77-83.pdf", + "short_name": "NDII" + }, + "NDISIb": { + "application_domain": "urban", + "bands": [ + "T", + "B", + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(T - (B + N + S1) / 3.0)/(T + (B + N + S1) / 3.0)", + "long_name": "Normalized Difference Impervious Surface Index Blue", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.14358/PERS.76.5.557", + "short_name": "NDISIb" + }, + "NDISIg": { + "application_domain": "urban", + "bands": [ + "T", + "G", + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(T - (G + N + S1) / 3.0)/(T + (G + N + S1) / 3.0)", + "long_name": "Normalized Difference Impervious Surface Index Green", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.14358/PERS.76.5.557", + "short_name": "NDISIg" + }, + "NDISImndwi": { + "application_domain": "urban", + "bands": [ + "T", + "G", + "S1", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(T - (((G - S1)/(G + S1)) + N + S1) / 3.0)/(T + (((G - S1)/(G + S1)) + N + S1) / 3.0)", + "long_name": "Normalized Difference Impervious Surface Index with MNDWI", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.14358/PERS.76.5.557", + "short_name": "NDISImndwi" + }, + "NDISIndwi": { + "application_domain": "urban", + "bands": [ + "T", + "G", + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(T - (((G - N)/(G + N)) + N + S1) / 3.0)/(T + (((G - N)/(G + N)) + N + S1) / 3.0)", + "long_name": "Normalized Difference Impervious Surface Index with NDWI", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.14358/PERS.76.5.557", + "short_name": "NDISIndwi" + }, + "NDISIr": { + "application_domain": "urban", + "bands": [ + "T", + "R", + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(T - (R + N + S1) / 3.0)/(T + (R + N + S1) / 3.0)", + "long_name": "Normalized Difference Impervious Surface Index Red", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.14358/PERS.76.5.557", + "short_name": "NDISIr" + }, + "NDMI": { + "application_domain": "vegetation", + "bands": [ + "N", + "S1" + ], + "contributor": "https://github.com/bpurinton", + "date_of_addition": "2021-12-01", + "formula": "(N - S1)/(N + S1)", + "long_name": "Normalized Difference Moisture Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/S0034-4257(01)00318-2", + "short_name": "NDMI" + }, + "NDPI": { + "application_domain": "vegetation", + "bands": [ + "N", + "alpha", + "R", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-20", + "formula": "(N - (alpha * R + (1.0 - alpha) * S1))/(N + (alpha * R + (1.0 - alpha) * S1))", + "long_name": "Normalized Difference Phenology Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.rse.2017.04.031", + "short_name": "NDPI" + }, + "NDPolI": { + "application_domain": "radar", + "bands": [ + "VV", + "VH" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "(VV - VH)/(VV + VH)", + "long_name": "Normalized Difference Polarization Index", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://www.isprs.org/proceedings/XXXVII/congress/4_pdf/267.pdf", + "short_name": "NDPolI" + }, + "NDPonI": { + "application_domain": "water", + "bands": [ + "S1", + "G" + ], + "contributor": "https://github.com/CvenGeo", + "date_of_addition": "2022-10-03", + "formula": "(S1-G)/(S1+G)", + "long_name": "Normalized Difference Pond Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.rse.2006.07.012", + "short_name": "NDPonI" + }, + "NDREI": { + "application_domain": "vegetation", + "bands": [ + "N", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-13", + "formula": "(N - RE1) / (N + RE1)", + "long_name": "Normalized Difference Red Edge Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/1011-1344(93)06963-4", + "short_name": "NDREI" + }, + "NDSI": { + "application_domain": "snow", + "bands": [ + "G", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(G - S1) / (G + S1)", + "long_name": "Normalized Difference Snow Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1109/IGARSS.1994.399618", + "short_name": "NDSI" + }, + "NDSII": { + "application_domain": "snow", + "bands": [ + "G", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(G - N)/(G + N)", + "long_name": "Normalized Difference Snow Ice Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/01431160802385459", + "short_name": "NDSII" + }, + "NDSIWV": { + "application_domain": "soil", + "bands": [ + "G", + "Y" + ], + "contributor": "https://github.com/remi-braun", + "date_of_addition": "2022-11-20", + "formula": "(G - Y)/(G + Y)", + "long_name": "WorldView Normalized Difference Soil Index", + "platforms": [], + "reference": "https://www.semanticscholar.org/paper/Using-WorldView-2-Vis-NIR-MSI-Imagery-to-Support-Wolf/5e5063ccc4ee76b56b721c866e871d47a77f9fb4", + "short_name": "NDSIWV" + }, + "NDSInw": { + "application_domain": "snow", + "bands": [ + "N", + "S1", + "beta" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(N - S1 - beta)/(N + S1)", + "long_name": "Normalized Difference Snow Index with no Water", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/w12051339", + "short_name": "NDSInw" + }, + "NDSWIR": { + "application_domain": "burn", + "bands": [ + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "(N - S1)/(N + S1)", + "long_name": "Normalized Difference SWIR", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1109/TGRS.2003.819190", + "short_name": "NDSWIR" + }, + "NDSaII": { + "application_domain": "snow", + "bands": [ + "R", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(R - S1) / (R + S1)", + "long_name": "Normalized Difference Snow and Ice Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1080/01431160119766", + "short_name": "NDSaII" + }, + "NDSoI": { + "application_domain": "soil", + "bands": [ + "S2", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(S2 - G)/(S2 + G)", + "long_name": "Normalized Difference Soil Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.jag.2015.02.010", + "short_name": "NDSoiI" + }, + "NDTI": { + "application_domain": "water", + "bands": [ + "R", + "G" + ], + "contributor": "https://github.com/CvenGeo", + "date_of_addition": "2022-10-03", + "formula": "(R-G)/(R+G)", + "long_name": "Normalized Difference Turbidity Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2006.07.012", + "short_name": "NDTI" + }, + "NDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - R)/(N + R)", + "long_name": "Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://ntrs.nasa.gov/citations/19740022614", + "short_name": "NDVI" + }, + "NDVI705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "(RE2 - RE1) / (RE2 + RE1)", + "long_name": "Normalized Difference Vegetation Index (705 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0176-1617(11)81633-0", + "short_name": "NDVI705" + }, + "NDVIMNDWI": { + "application_domain": "water", + "bands": [ + "N", + "R", + "G", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "((N - R)/(N + R)) - ((G - S1)/(G + S1))", + "long_name": "NDVI-MNDWI Model", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1007/978-3-662-45737-5_51", + "short_name": "NDVIMNDWI" + }, + "NDVIT": { + "application_domain": "burn", + "bands": [ + "N", + "R", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(N - (R * T / 10000.0))/(N + (R * T / 10000.0))", + "long_name": "Normalized Difference Vegetation Index Thermal", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1080/01431160600954704", + "short_name": "NDVIT" + }, + "NDWI": { + "application_domain": "water", + "bands": [ + "G", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(G - N) / (G + N)", + "long_name": "Normalized Difference Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/01431169608948714", + "short_name": "NDWI" + }, + "NDWIns": { + "application_domain": "water", + "bands": [ + "G", + "alpha", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(G - alpha * N)/(G + N)", + "long_name": "Normalized Difference Water Index with no Snow Cover and Glaciers", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.3390/w12051339", + "short_name": "NDWIns" + }, + "NDYI": { + "application_domain": "vegetation", + "bands": [ + "G", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(G - B) / (G + B)", + "long_name": "Normalized Difference Yellowness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2016.06.016", + "short_name": "NDYI" + }, + "NGRDI": { + "application_domain": "vegetation", + "bands": [ + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(G - R) / (G + R)", + "long_name": "Normalized Green Red Difference Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(79)90013-0", + "short_name": "NGRDI" + }, + "NHFD": { + "application_domain": "urban", + "bands": [ + "RE1", + "A" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-17", + "formula": "(RE1 - A) / (RE1 + A)", + "long_name": "Non-Homogeneous Feature Difference", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://www.semanticscholar.org/paper/Using-WorldView-2-Vis-NIR-MSI-Imagery-to-Support-Wolf/5e5063ccc4ee76b56b721c866e871d47a77f9fb4", + "short_name": "NHFD" + }, + "NIRv": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-16", + "formula": "((N - R) / (N + R)) * N", + "long_name": "Near-Infrared Reflectance of Vegetation", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1126/sciadv.1602244", + "short_name": "NIRv" + }, + "NIRvH2": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "k", + "lambdaN", + "lambdaR" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "N - R - k * (lambdaN - lambdaR)", + "long_name": "Hyperspectral Near-Infrared Reflectance of Vegetation", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2021.112723", + "short_name": "NIRvH2" + }, + "NIRvP": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "PAR" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-18", + "formula": "((N - R) / (N + R)) * N * PAR", + "long_name": "Near-Infrared Reflectance of Vegetation and Incoming PAR", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.rse.2021.112763", + "short_name": "NIRvP" + }, + "NLI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-11", + "formula": "((N ** 2) - R)/((N ** 2) + R)", + "long_name": "Non-Linear Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/02757259409532252", + "short_name": "NLI" + }, + "NMDI": { + "application_domain": "vegetation", + "bands": [ + "N", + "S1", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-11", + "formula": "(N - (S1 - S2))/(N + (S1 - S2))", + "long_name": "Normalized Multi-band Drought Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1029/2007GL031021", + "short_name": "NMDI" + }, + "NRFIg": { + "application_domain": "vegetation", + "bands": [ + "G", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(G - S2) / (G + S2)", + "long_name": "Normalized Rapeseed Flowering Index Green", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs13010105", + "short_name": "NRFIg" + }, + "NRFIr": { + "application_domain": "vegetation", + "bands": [ + "R", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(R - S2) / (R + S2)", + "long_name": "Normalized Rapeseed Flowering Index Red", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs13010105", + "short_name": "NRFIr" + }, + "NSDS": { + "application_domain": "soil", + "bands": [ + "S1", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "(S1 - S2)/(S1 + S2)", + "long_name": "Normalized Shortwave Infrared Difference Soil-Moisture", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/land10030231", + "short_name": "NSDS" + }, + "NSDSI1": { + "application_domain": "soil", + "bands": [ + "S1", + "S2" + ], + "contributor": "https://github.com/CvenGeo", + "date_of_addition": "2022-10-03", + "formula": "(S1-S2)/S1", + "long_name": "Normalized Shortwave-Infrared Difference Bare Soil Moisture Index 1", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.isprsjprs.2019.06.012", + "short_name": "NSDSI1" + }, + "NSDSI2": { + "application_domain": "soil", + "bands": [ + "S1", + "S2" + ], + "contributor": "https://github.com/CvenGeo", + "date_of_addition": "2022-10-03", + "formula": "(S1-S2)/S2", + "long_name": "Normalized Shortwave-Infrared Difference Bare Soil Moisture Index 2", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.isprsjprs.2019.06.012", + "short_name": "NSDSI2" + }, + "NSDSI3": { + "application_domain": "soil", + "bands": [ + "S1", + "S2" + ], + "contributor": "https://github.com/CvenGeo", + "date_of_addition": "2022-10-03", + "formula": "(S1-S2)/(S1+S2)", + "long_name": "Normalized Shortwave-Infrared Difference Bare Soil Moisture Index 3", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.isprsjprs.2019.06.012", + "short_name": "NSDSI3" + }, + "NSTv1": { + "application_domain": "burn", + "bands": [ + "N", + "S2", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-10-06", + "formula": "((N-S2)/(N+S2))*T", + "long_name": "NIR-SWIR-Temperature Version 1", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1016/j.rse.2011.06.010", + "short_name": "NSTv1" + }, + "NSTv2": { + "application_domain": "burn", + "bands": [ + "N", + "S2", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-10-06", + "formula": "(N-(S2+T))/(N+(S2+T))", + "long_name": "NIR-SWIR-Temperature Version 2", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1016/j.rse.2011.06.010", + "short_name": "NSTv2" + }, + "NWI": { + "application_domain": "water", + "bands": [ + "B", + "N", + "S1", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "(B - (N + S1 + S2))/(B + (N + S1 + S2))", + "long_name": "New Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.11873/j.issn.1004-0323.2009.2.167", + "short_name": "NWI" + }, + "NormG": { + "application_domain": "vegetation", + "bands": [ + "G", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "G/(N + G + R)", + "long_name": "Normalized Green", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2134/agronj2004.0314", + "short_name": "NormG" + }, + "NormNIR": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "N/(N + G + R)", + "long_name": "Normalized NIR", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2134/agronj2004.0314", + "short_name": "NormNIR" + }, + "NormR": { + "application_domain": "vegetation", + "bands": [ + "R", + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "R/(N + G + R)", + "long_name": "Normalized Red", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2134/agronj2004.0314", + "short_name": "NormR" + }, + "OCVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "R", + "cexp" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-13", + "formula": "(N / G) * (R / G) ** cexp", + "long_name": "Optimized Chlorophyll Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "http://dx.doi.org/10.1007/s11119-008-9075-z", + "short_name": "OCVI" + }, + "OSAVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-11", + "formula": "(N - R) / (N + R + 0.16)", + "long_name": "Optimized Soil-Adjusted Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(95)00186-7", + "short_name": "OSAVI" + }, + "PISI": { + "application_domain": "urban", + "bands": [ + "B", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-18", + "formula": "0.8192 * B - 0.5735 * N + 0.0750", + "long_name": "Perpendicular Impervious Surface Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.3390/rs10101521", + "short_name": "PISI" + }, + "PSRI": { + "application_domain": "vegetation", + "bands": [ + "R", + "B", + "RE2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(R - B)/RE2", + "long_name": "Plant Senescing Reflectance Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1034/j.1399-3054.1999.106119.x", + "short_name": "PSRI" + }, + "QpRVI": { + "application_domain": "radar", + "bands": [ + "HV", + "HH", + "VV" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-12-24", + "formula": "(8.0 * HV)/(HH + VV + 2.0 * HV)", + "long_name": "Quad-Polarized Radar Vegetation Index", + "platforms": [], + "reference": "https://doi.org/10.1109/IGARSS.2001.976856", + "short_name": "QpRVI" + }, + "RCC": { + "application_domain": "vegetation", + "bands": [ + "R", + "G", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "R / (R + G + B)", + "long_name": "Red Chromatic Coordinate", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(87)90088-5", + "short_name": "RCC" + }, + "RDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "(N - R) / ((N + R) ** 0.5)", + "long_name": "Renormalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(94)00114-3", + "short_name": "RDVI" + }, + "REDSI": { + "application_domain": "vegetation", + "bands": [ + "RE3", + "R", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "((705.0 - 665.0) * (RE3 - R) - (783.0 - 665.0) * (RE1 - R)) / (2.0 * R)", + "long_name": "Red-Edge Disease Stress Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/s18030868", + "short_name": "REDSI" + }, + "RENDVI": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-09", + "formula": "(RE2 - RE1)/(RE2 + RE1)", + "long_name": "Red Edge Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0176-1617(11)81633-0", + "short_name": "RENDVI" + }, + "RFDI": { + "application_domain": "radar", + "bands": [ + "HH", + "HV" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-12-25", + "formula": "(HH - HV)/(HH + HV)", + "long_name": "Radar Forest Degradation Index", + "platforms": [ + "Sentinel-1 (Dual Polarisation HH-HV)" + ], + "reference": "https://doi.org/10.5194/bg-9-179-2012", + "short_name": "RFDI" + }, + "RGBVI": { + "application_domain": "vegetation", + "bands": [ + "G", + "B", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(G ** 2.0 - B * R)/(G ** 2.0 + B * R)", + "long_name": "Red Green Blue Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.jag.2015.02.012", + "short_name": "RGBVI" + }, + "RGRI": { + "application_domain": "vegetation", + "bands": [ + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "R/G", + "long_name": "Red-Green Ratio Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.jag.2014.03.018", + "short_name": "RGRI" + }, + "RI": { + "application_domain": "vegetation", + "bands": [ + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-09", + "formula": "(R - G)/(R + G)", + "long_name": "Redness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://www.documentation.ird.fr/hor/fdi:34390", + "short_name": "RI" + }, + "RI4XS": { + "application_domain": "soil", + "bands": [ + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-11-20", + "formula": "(R**2.0)/(G**4.0)", + "long_name": "SPOT HRV XS-based Redness Index 4", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(98)00030-3", + "short_name": "RI4XS" + }, + "RVI": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "RE2 / R", + "long_name": "Ratio Vegetation Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.2134/agronj1968.00021962006000060016x", + "short_name": "RVI" + }, + "S2REP": { + "application_domain": "vegetation", + "bands": [ + "RE3", + "R", + "RE1", + "RE2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-17", + "formula": "705.0 + 35.0 * ((((RE3 + R) / 2.0) - RE1) / (RE2 - RE1))", + "long_name": "Sentinel-2 Red-Edge Position", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/j.isprsjprs.2013.04.007", + "short_name": "S2REP" + }, + "S2WI": { + "application_domain": "water", + "bands": [ + "RE1", + "S2" + ], + "contributor": "https://github.com/MATRIX4284", + "date_of_addition": "2022-03-06", + "formula": "(RE1 - S2)/(RE1 + S2)", + "long_name": "Sentinel-2 Water Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/w13121647", + "short_name": "S2WI" + }, + "S3": { + "application_domain": "snow", + "bands": [ + "N", + "R", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(N * (R - S1)) / ((N + R) * (N + S1))", + "long_name": "S3 Snow Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3178/jjshwr.12.28", + "short_name": "S3" + }, + "SARVI": { + "application_domain": "vegetation", + "bands": [ + "L", + "N", + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-11", + "formula": "(1 + L)*(N - (R - (R - B))) / (N + (R - (R - B)) + L)", + "long_name": "Soil Adjusted and Atmospherically Resistant Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1109/36.134076", + "short_name": "SARVI" + }, + "SAVI": { + "application_domain": "vegetation", + "bands": [ + "L", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(1.0 + L) * (N - R) / (N + R + L)", + "long_name": "Soil-Adjusted Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(88)90106-X", + "short_name": "SAVI" + }, + "SAVI2": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "slb", + "sla" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "N / (R + (slb / sla))", + "long_name": "Soil-Adjusted Vegetation Index 2", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/01431169008955053", + "short_name": "SAVI2" + }, + "SAVIT": { + "application_domain": "burn", + "bands": [ + "L", + "N", + "R", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(1.0 + L) * (N - (R * T / 10000.0)) / (N + (R * T / 10000.0) + L)", + "long_name": "Soil-Adjusted Vegetation Index Thermal", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1080/01431160600954704", + "short_name": "SAVIT" + }, + "SEVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R", + "fdelta" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "(N/R) + fdelta * (1.0/R)", + "long_name": "Shadow-Eliminated Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/17538947.2018.1495770", + "short_name": "SEVI" + }, + "SI": { + "application_domain": "vegetation", + "bands": [ + "B", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "((1.0 - B) * (1.0 - G) * (1.0 - R)) ** (1/3)", + "long_name": "Shadow Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.465.8749&rep=rep1&type=pdf", + "short_name": "SI" + }, + "SIPI": { + "application_domain": "vegetation", + "bands": [ + "N", + "A", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-17", + "formula": "(N - A) / (N - R)", + "long_name": "Structure Insensitive Pigment Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI" + ], + "reference": "https://eurekamag.com/research/009/395/009395053.php", + "short_name": "SIPI" + }, + "SR": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "N/R", + "long_name": "Simple Ratio", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.2307/1936256", + "short_name": "SR" + }, + "SR2": { + "application_domain": "vegetation", + "bands": [ + "N", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-09", + "formula": "N/G", + "long_name": "Simple Ratio (800 and 550 nm)", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1080/01431169308904370", + "short_name": "SR2" + }, + "SR3": { + "application_domain": "vegetation", + "bands": [ + "N2", + "G", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-09", + "formula": "N2/(G * RE1)", + "long_name": "Simple Ratio (860, 550 and 708 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(98)00046-7", + "short_name": "SR3" + }, + "SR555": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "RE2 / G", + "long_name": "Simple Ratio (555 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0176-1617(11)81633-0", + "short_name": "SR555" + }, + "SR705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "RE2 / RE1", + "long_name": "Simple Ratio (705 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0176-1617(11)81633-0", + "short_name": "SR705" + }, + "SWI": { + "application_domain": "snow", + "bands": [ + "G", + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(G * (N - S1)) / ((G + N) * (N + S1))", + "long_name": "Snow Water Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs11232774", + "short_name": "SWI" + }, + "SWM": { + "application_domain": "water", + "bands": [ + "B", + "G", + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-20", + "formula": "(B + G)/(N + S1)", + "long_name": "Sentinel Water Mask", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://eoscience.esa.int/landtraining2017/files/posters/MILCZAREK.pdf", + "short_name": "SWM" + }, + "SeLI": { + "application_domain": "vegetation", + "bands": [ + "N2", + "RE1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-08", + "formula": "(N2 - RE1) / (N2 + RE1)", + "long_name": "Sentinel-2 LAI Green Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/s19040904", + "short_name": "SeLI" + }, + "TCARI": { + "application_domain": "vegetation", + "bands": [ + "RE1", + "R", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-13", + "formula": "3 * ((RE1 - R) - 0.2 * (RE1 - G) * (RE1 / R))", + "long_name": "Transformed Chlorophyll Absorption in Reflectance Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(02)00018-4", + "short_name": "TCARI" + }, + "TCARIOSAVI": { + "application_domain": "vegetation", + "bands": [ + "RE1", + "R", + "G", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "(3 * ((RE1 - R) - 0.2 * (RE1 - G) * (RE1 / R))) / (1.16 * (N - R) / (N + R + 0.16))", + "long_name": "TCARI/OSAVI Ratio", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(02)00018-4", + "short_name": "TCARIOSAVI" + }, + "TCARIOSAVI705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1", + "G" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-11-06", + "formula": "(3 * ((RE2 - RE1) - 0.2 * (RE2 - G) * (RE2 / RE1))) / (1.16 * (RE2 - RE1) / (RE2 + RE1 + 0.16))", + "long_name": "TCARI/OSAVI Ratio (705 and 750 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/j.agrformet.2008.03.005", + "short_name": "TCARIOSAVI705" + }, + "TCI": { + "application_domain": "vegetation", + "bands": [ + "RE1", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "1.2 * (RE1 - G) - 1.5 * (R - G) * (RE1 / R) ** 0.5", + "long_name": "Triangular Chlorophyll Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "http://dx.doi.org/10.1109/TGRS.2007.904836", + "short_name": "TCI" + }, + "TDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-09", + "formula": "1.5 * ((N - R)/((N ** 2.0 + R + 0.5) ** 0.5))", + "long_name": "Transformed Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1109/IGARSS.2002.1026867", + "short_name": "TDVI" + }, + "TGI": { + "application_domain": "vegetation", + "bands": [ + "R", + "G", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "- 0.5 * (190 * (R - G) - 120 * (R - B))", + "long_name": "Triangular Greenness Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "http://dx.doi.org/10.1016/j.jag.2012.07.020", + "short_name": "TGI" + }, + "TRRVI": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "R", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "((RE2 - R) / (RE2 + R)) / (((N - R) / (N + R)) + 1.0)", + "long_name": "Transformed Red Range Vegetation Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/rs12152359", + "short_name": "TRRVI" + }, + "TSAVI": { + "application_domain": "vegetation", + "bands": [ + "sla", + "N", + "R", + "slb" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "sla * (N - sla * R - slb) / (sla * N + R - sla * slb)", + "long_name": "Transformed Soil-Adjusted Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1109/IGARSS.1989.576128", + "short_name": "TSAVI" + }, + "TTVI": { + "application_domain": "vegetation", + "bands": [ + "RE3", + "RE2", + "N2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "0.5 * ((865.0 - 740.0) * (RE3 - RE2) - (N2 - RE2) * (783.0 - 740))", + "long_name": "Transformed Triangular Vegetation Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/rs12010016", + "short_name": "TTVI" + }, + "TVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(((N - R)/(N + R)) + 0.5) ** 0.5", + "long_name": "Transformed Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://ntrs.nasa.gov/citations/19740022614", + "short_name": "TVI" + }, + "TWI": { + "application_domain": "water", + "bands": [ + "RE1", + "RE2", + "G", + "S2", + "B", + "N" + ], + "contributor": "https://github.com/remi-braun", + "date_of_addition": "2023-02-10", + "formula": "(2.84 * (RE1 - RE2) / (G + S2)) + ((1.25 * (G - B) - (N - B)) / (N + 1.25 * G - 0.25 * B))", + "long_name": "Triangle Water Index", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.3390/rs14215289", + "short_name": "TWI" + }, + "TriVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "0.5 * (120 * (N - G) - 200 * (R - G))", + "long_name": "Triangular Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "http://dx.doi.org/10.1016/S0034-4257(00)00197-8", + "short_name": "TriVI" + }, + "UI": { + "application_domain": "urban", + "bands": [ + "S2", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-02-07", + "formula": "(S2 - N)/(S2 + N)", + "long_name": "Urban Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://www.isprs.org/proceedings/XXXI/congress/part7/321_XXXI-part7.pdf", + "short_name": "UI" + }, + "VARI": { + "application_domain": "vegetation", + "bands": [ + "G", + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(G - R) / (G + R - B)", + "long_name": "Visible Atmospherically Resistant Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(01)00289-9", + "short_name": "VARI" + }, + "VARI700": { + "application_domain": "vegetation", + "bands": [ + "RE1", + "R", + "B" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-20", + "formula": "(RE1 - 1.7 * R + 0.7 * B) / (RE1 + 1.3 * R - 1.3 * B)", + "long_name": "Visible Atmospherically Resistant Index (700 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(01)00289-9", + "short_name": "VARI700" + }, + "VDDPI": { + "application_domain": "radar", + "bands": [ + "VV", + "VH" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "(VV + VH)/VV", + "long_name": "Vertical Dual De-Polarization Index", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.1016/j.rse.2018.09.003", + "short_name": "VDDPI" + }, + "VHVVD": { + "application_domain": "radar", + "bands": [ + "VH", + "VV" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "VH - VV", + "long_name": "VH-VV Difference", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.3390/app9040655", + "short_name": "VHVVD" + }, + "VHVVP": { + "application_domain": "radar", + "bands": [ + "VH", + "VV" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "VH * VV", + "long_name": "VH-VV Product", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.1109/IGARSS47720.2021.9554099", + "short_name": "VHVVP" + }, + "VHVVR": { + "application_domain": "radar", + "bands": [ + "VH", + "VV" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "VH/VV", + "long_name": "VH-VV Ratio", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.1109/IGARSS47720.2021.9554099", + "short_name": "VHVVR" + }, + "VI6T": { + "application_domain": "burn", + "bands": [ + "N", + "T" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "(N - T/10000.0)/(N + T/10000.0)", + "long_name": "VI6T Index", + "platforms": [ + "Landsat-TM", + "Landsat-ETM+" + ], + "reference": "https://doi.org/10.1080/01431160500239008", + "short_name": "VI6T" + }, + "VI700": { + "application_domain": "vegetation", + "bands": [ + "RE1", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-20", + "formula": "(RE1 - R) / (RE1 + R)", + "long_name": "Vegetation Index (700 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(01)00289-9", + "short_name": "VI700" + }, + "VIBI": { + "application_domain": "urban", + "bands": [ + "N", + "R", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-09-22", + "formula": "((N-R)/(N+R))/(((N-R)/(N+R)) + ((S1-N)/(S1+N)))", + "long_name": "Vegetation Index Built-up Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "http://dx.doi.org/10.1080/01431161.2012.687842", + "short_name": "VIBI" + }, + "VIG": { + "application_domain": "vegetation", + "bands": [ + "G", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-20", + "formula": "(G - R) / (G + R)", + "long_name": "Vegetation Index Green", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/S0034-4257(01)00289-9", + "short_name": "VIG" + }, + "VVVHD": { + "application_domain": "radar", + "bands": [ + "VV", + "VH" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "VV - VH", + "long_name": "VV-VH Difference", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.1109/IGARSS47720.2021.9554099", + "short_name": "VVVHD" + }, + "VVVHR": { + "application_domain": "radar", + "bands": [ + "VV", + "VH" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "VV/VH", + "long_name": "VV-VH Ratio", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.3390/app9040655", + "short_name": "VVVHR" + }, + "VVVHS": { + "application_domain": "radar", + "bands": [ + "VV", + "VH" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-19", + "formula": "VV + VH", + "long_name": "VV-VH Sum", + "platforms": [ + "Sentinel-1 (Dual Polarisation VV-VH)" + ], + "reference": "https://doi.org/10.1109/IGARSS47720.2021.9554099", + "short_name": "VVVHS" + }, + "VgNIRBI": { + "application_domain": "urban", + "bands": [ + "G", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-02-09", + "formula": "(G - N)/(G + N)", + "long_name": "Visible Green-Based Built-Up Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.ecolind.2015.03.037", + "short_name": "VgNIRBI" + }, + "VrNIRBI": { + "application_domain": "urban", + "bands": [ + "R", + "N" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-02-09", + "formula": "(R - N)/(R + N)", + "long_name": "Visible Red-Based Built-Up Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/j.ecolind.2015.03.037", + "short_name": "VrNIRBI" + }, + "WDRVI": { + "application_domain": "vegetation", + "bands": [ + "alpha", + "N", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "(alpha * N - R) / (alpha * N + R)", + "long_name": "Wide Dynamic Range Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1078/0176-1617-01176", + "short_name": "WDRVI" + }, + "WDVI": { + "application_domain": "vegetation", + "bands": [ + "N", + "sla", + "R" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-14", + "formula": "N - sla * R", + "long_name": "Weighted Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1016/0034-4257(89)90076-X", + "short_name": "WDVI" + }, + "WI1": { + "application_domain": "water", + "bands": [ + "G", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(G - S2) / (G + S2)", + "long_name": "Water Index 1", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs11182186", + "short_name": "WI1" + }, + "WI2": { + "application_domain": "water", + "bands": [ + "B", + "S2" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-09-18", + "formula": "(B - S2) / (B + S2)", + "long_name": "Water Index 2", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.3390/rs11182186", + "short_name": "WI2" + }, + "WI2015": { + "application_domain": "water", + "bands": [ + "G", + "R", + "N", + "S1", + "S2" + ], + "contributor": "https://github.com/remi-braun", + "date_of_addition": "2022-10-26", + "formula": "1.7204 + 171 * G + 3 * R - 70 * N - 45 * S1 - 71 * S2", + "long_name": "Water Index 2015", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1016/j.rse.2015.12.055", + "short_name": "WI2015" + }, + "WRI": { + "application_domain": "water", + "bands": [ + "G", + "R", + "N", + "S1" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-01-17", + "formula": "(G + R)/(N + S1)", + "long_name": "Water Ratio Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS" + ], + "reference": "https://doi.org/10.1109/GEOINFORMATICS.2010.5567762", + "short_name": "WRI" + }, + "kEVI": { + "application_domain": "kernel", + "bands": [ + "g", + "kNN", + "kNR", + "C1", + "C2", + "kNB", + "kNL" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-10", + "formula": "g * (kNN - kNR) / (kNN + C1 * kNR - C2 * kNB + kNL)", + "long_name": "Kernel Enhanced Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1126/sciadv.abc7447", + "short_name": "kEVI" + }, + "kIPVI": { + "application_domain": "kernel", + "bands": [ + "kNN", + "kNR" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "kNN/(kNN + kNR)", + "long_name": "Kernel Infrared Percentage Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1126/sciadv.abc7447", + "short_name": "kIPVI" + }, + "kNDVI": { + "application_domain": "kernel", + "bands": [ + "kNN", + "kNR" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "(kNN - kNR)/(kNN + kNR)", + "long_name": "Kernel Normalized Difference Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1126/sciadv.abc7447", + "short_name": "kNDVI" + }, + "kRVI": { + "application_domain": "kernel", + "bands": [ + "kNN", + "kNR" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-04-07", + "formula": "kNN / kNR", + "long_name": "Kernel Ratio Vegetation Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1126/sciadv.abc7447", + "short_name": "kRVI" + }, + "kVARI": { + "application_domain": "kernel", + "bands": [ + "kGG", + "kGR", + "kGB" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2021-05-10", + "formula": "(kGG - kGR) / (kGG + kGR - kGB)", + "long_name": "Kernel Visible Atmospherically Resistant Index", + "platforms": [ + "Sentinel-2", + "Landsat-OLI", + "Landsat-TM", + "Landsat-ETM+", + "MODIS", + "Planet-Fusion" + ], + "reference": "https://doi.org/10.1126/sciadv.abc7447", + "short_name": "kVARI" + }, + "mND705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "RE1", + "A" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(RE2 - RE1)/(RE2 + RE1 - A)", + "long_name": "Modified Normalized Difference (705, 750 and 445 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(02)00010-X", + "short_name": "mND705" + }, + "mSR705": { + "application_domain": "vegetation", + "bands": [ + "RE2", + "A" + ], + "contributor": "https://github.com/davemlz", + "date_of_addition": "2022-04-08", + "formula": "(RE2 - A)/(RE2 + A)", + "long_name": "Modified Simple Ratio (705 and 445 nm)", + "platforms": [ + "Sentinel-2" + ], + "reference": "https://doi.org/10.1016/S0034-4257(02)00010-X", + "short_name": "mSR705" + } + } +} diff --git a/lib/openeo/extra/spectral_indices/resources/extra-indices-dict.json b/lib/openeo/extra/spectral_indices/resources/extra-indices-dict.json new file mode 100644 index 000000000..f8b0e55f7 --- /dev/null +++ b/lib/openeo/extra/spectral_indices/resources/extra-indices-dict.json @@ -0,0 +1,98 @@ +{ + "SpectralIndices": { + "ANIR": { + "bands": + [ + "R", + "N", + "S1" + ], + "contributor": "vito", + "date_of_addition": "2021-10-27", + "formula": "exec('import numpy as np') or exec('from openeo.processes import clip') or np.arccos(clip((( np.sqrt( (0.8328 - 0.6646)**2 + (N - R)**2 )**2 + np.sqrt( (1.610 - 0.8328)**2 + (S1 - N)**2 )**2 - np.sqrt( (1.610 - 0.6646)**2 + (S1 - R)**2 )**2 ) / (2 * np.sqrt( (0.8328 - 0.6646)**2 + (N - R)**2 ) * np.sqrt( (1.610 - 0.8328)**2 + (S1 - N)**2 ))), -1,1)) * (1. / np.pi)", + "long_name": "Angle at Near InfraRed", + "reference": "", + "short_name": "ANIR", + "type": "vegetation" + }, + "NDRE1": { + "bands": [ + "N", + "RE1" + ], + "contributor": "vito", + "date_of_addition": "2021-10-27", + "formula": "(N - RE1) / (N + RE1)", + "long_name": "Normalized Difference Red Edge 1", + "reference": "", + "short_name": "NDRE1", + "type": "vegetation" + }, + "NDRE2": { + "bands": [ + "N", + "RE2" + ], + "contributor": "vito", + "date_of_addition": "2021-10-27", + "formula": "(N - RE2) / (N + RE2)", + "long_name": "Normalized Difference Red Edge 2", + "reference": "", + "short_name": "NDRE2", + "type": "vegetation" + }, + "NDRE5": { + "bands": [ + "RE1", + "RE3" + ], + "contributor": "vito", + "date_of_addition": "2021-10-27", + "formula": "(RE3 - RE1) / (RE3 + RE1)", + "long_name": "Normalized Difference Red Edge 5", + "reference": "", + "short_name": "NDRE5", + "type": "vegetation" + }, + "BI2": { + "bands": [ + "G", + "R", + "N" + ], + "contributor": "vito", + "date_of_addition": "2022-01-27", + "formula": "((R**2+N**2+G**2)**0.5)/3", + "long_name": "Brightness index 2", + "reference": "https://digifed.org/", + "short_name": "BI2", + "type": "soil" + }, + "BI_B08": { + "bands": [ + "R", + "N" + ], + "contributor": "vito", + "date_of_addition": "2022-01-27", + "formula": "(R**2+N**2)**0.5", + "long_name": "Brightness index B08", + "reference": "https://digifed.org/", + "short_name": "BI_B08", + "type": "soil" + }, + "LSWI_B12": { + "bands": [ + "N", + "S2" + ], + "contributor": "vito", + "date_of_addition": "2022-01-27", + "formula": "(N-S2)/(N+S2)", + "long_name": "Sentinel-2 land surface water index", + "reference": "https://digifed.org/", + "short_name": "LSWI_B12", + "type": "water" + } + } +} diff --git a/lib/openeo/extra/spectral_indices/spectral_indices.py b/lib/openeo/extra/spectral_indices/spectral_indices.py new file mode 100644 index 000000000..8ac3c0b93 --- /dev/null +++ b/lib/openeo/extra/spectral_indices/spectral_indices.py @@ -0,0 +1,475 @@ +import functools +import json +import re +from typing import Dict, List, Optional, Set + +from openeo import BaseOpenEoException +from openeo.processes import ProcessBuilder, array_create, array_modify +from openeo.rest.datacube import DataCube + +try: + import importlib_resources +except ImportError: + import importlib.resources as importlib_resources + + +@functools.lru_cache(maxsize=1) +def load_indices() -> Dict[str, dict]: + """Load set of supported spectral indices.""" + # TODO: encapsulate all this json loading in a single Awesome Spectral Indices registry class? + specs = {} + + for path in [ + "resources/awesome-spectral-indices/spectral-indices-dict.json", + # TODO #506 Deprecate extra-indices-dict.json as a whole + # and provide an alternative mechanism to work with custom indices + "resources/extra-indices-dict.json", + ]: + with importlib_resources.files("openeo.extra.spectral_indices") / path as resource_path: + data = json.loads(resource_path.read_text(encoding="utf8")) + overwrites = set(specs.keys()).intersection(data["SpectralIndices"].keys()) + if overwrites: + raise RuntimeError(f"Duplicate spectral indices: {overwrites} from {path}") + specs.update(data["SpectralIndices"]) + + return specs + + +@functools.lru_cache(maxsize=1) +def load_constants() -> Dict[str, float]: + """Load constants defined by Awesome Spectral Indices.""" + # TODO: encapsulate all this json loading in a single Awesome Spectral Indices registry class? + with importlib_resources.files( + "openeo.extra.spectral_indices" + ) / "resources/awesome-spectral-indices/constants.json" as resource_path: + data = json.loads(resource_path.read_text(encoding="utf8")) + + return {k: v["default"] for k, v in data.items() if isinstance(v["default"], (int, float))} + + +@functools.lru_cache(maxsize=1) +def _load_bands() -> Dict[str, dict]: + """Load band name mapping defined by Awesome Spectral Indices.""" + # TODO: encapsulate all this json loading in a single Awesome Spectral Indices registry class? + with importlib_resources.files( + "openeo.extra.spectral_indices" + ) / "resources/awesome-spectral-indices/bands.json" as resource_path: + data = json.loads(resource_path.read_text(encoding="utf8")) + return data + + +class BandMappingException(BaseOpenEoException): + """Failure to determine band-variable mapping.""" + + +class _BandMapping: + """ + Helper class to extract mappings between band names and variable names used in Awesome Spectral Indices formulas. + """ + + _EXTRA = { + "sentinel1": {"HH": "HH", "HV": "HV", "VH": "VH", "VV": "VV"}, + } + + def __init__(self): + # Load bands.json from Awesome Spectral Indices + self._band_data = _load_bands() + + @staticmethod + def _normalize_platform(platform: str) -> str: + platform = platform.lower().replace("-", "").replace(" ", "") + if platform in {"sentinel2a", "sentinel2b"}: + platform = "sentinel2" + return platform + + @staticmethod + def _normalize_band_name(band_name: str) -> str: + band_name = band_name.upper() + # Normalize band names like "B01" to "B1" + band_name = re.sub(r"^B0+(\d+)$", r"B\1", band_name) + return band_name + + @functools.lru_cache(maxsize=1) + def get_platforms(self) -> Set[str]: + """Get list of supported (normalized) satellite platforms.""" + platforms = {p for var_data in self._band_data.values() for p in var_data.get("platforms", {}).keys()} + platforms.update(self._EXTRA.keys()) + platforms.update({self._normalize_platform(p) for p in platforms}) + return platforms + + def guess_platform(self, name: str) -> str: + """Guess platform from given collection id or name.""" + # First check original id, then retry with removed separators as last resort. + for haystack in [name.lower(), re.sub("[_ -]", "", name.lower())]: + for platform in sorted(self.get_platforms(), key=len, reverse=True): + if platform in haystack: + return platform + raise BandMappingException(f"Unable to guess satellite platform from id {name!r}.") + + def variable_to_band_name_map(self, platform: str) -> Dict[str, str]: + """ + Build mapping from Awesome Spectral Indices variable names to (normalized) band names for given satellite platform. + """ + platform_normalized = self._normalize_platform(platform) + if platform_normalized in self._EXTRA: + return self._EXTRA[platform_normalized] + + var_to_band = { + var: pf_data["band"] + for var, var_data in self._band_data.items() + for pf, pf_data in var_data.get("platforms", {}).items() + if self._normalize_platform(pf) == platform_normalized + } + if not var_to_band: + raise BandMappingException(f"Empty band mapping derived for satellite platform {platform!r}") + return var_to_band + + def actual_band_name_to_variable_map(self, platform: str, band_names: List[str]) -> Dict[str, str]: + """Build mapping from actual band names (as given) to Awesome Spectral Indices variable names.""" + var_to_band = self.variable_to_band_name_map(platform=platform) + band_to_var = { + band_name: var + for var, normalized_band_name in var_to_band.items() + for band_name in band_names + if self._normalize_band_name(band_name) == normalized_band_name + } + return band_to_var + + +def list_indices() -> List[str]: + """List names of supported spectral indices""" + specs = load_indices() + return list(specs.keys()) + + +def _check_params(item, params): + range_vals = ["input_range", "output_range"] + if set(params) != set(range_vals): + raise ValueError( + f"You have set the parameters {params} on {item}, while the following are required {range_vals}" + ) + for rng in range_vals: + if params[rng] is None: + continue + if len(params[rng]) != 2: + raise ValueError( + f"The list of provided values {params[rng]} for parameter {rng} for {item} is not of length 2" + ) + # TODO: allow float too? + if not all(isinstance(val, int) for val in params[rng]): + raise ValueError("The ranges you supplied are not all of type int") + if (params["input_range"] is None) != (params["output_range"] is None): + raise ValueError(f"The index_range and output_range of {item} should either be both supplied, or both None") + + +def _check_validity_index_dict(index_dict: dict, index_specs: dict): + # TODO: this `index_dict` API needs some more rethinking: + # - the dictionary has no explicit order of indices, which can be important for end user + # - allow "collection" to be missing (e.g. if no rescaling is desired, or input data is not kept)? + # - option to define default output range, instead of having it to specify it for each index? + # - keep "rescaling" feature separate/orthogonal from "spectral indices" feature. It could be useful as + # a more generic machine learning data preparation feature + input_vals = ["collection", "indices"] + if set(index_dict.keys()) != set(input_vals): + raise ValueError( + f"The first level of the dictionary should contain the keys 'collection' and 'indices', but they contain {index_dict.keys()}" + ) + _check_params("collection", index_dict["collection"]) + for index, params in index_dict["indices"].items(): + if index not in index_specs.keys(): + raise NotImplementedError("Index " + index + " is not supported.") + _check_params(index, params) + + +def _callback( + x: ProcessBuilder, + index_dict: dict, + index_specs: dict, + append: bool, + band_names: List[str], + band_to_var: Dict[str, str], +) -> ProcessBuilder: + index_values = [] + x_res = x + + # TODO: use `label` parameter of `array_element` to avoid index based band references + variables = {band_to_var[bn]: x.array_element(i) for i, bn in enumerate(band_names) if bn in band_to_var} + eval_globals = { + **load_constants(), + **variables, + } + # TODO: user might want to control order of indices, which is tricky through a dictionary. + for index, params in index_dict["indices"].items(): + index_result = eval(index_specs[index]["formula"], eval_globals) + if params["input_range"] is not None: + index_result = index_result.linear_scale_range(*params["input_range"], *params["output_range"]) + index_values.append(index_result) + if index_dict["collection"]["input_range"] is not None: + x_res = x_res.linear_scale_range( + *index_dict["collection"]["input_range"], *index_dict["collection"]["output_range"] + ) + if append: + return array_modify(data=x_res, values=index_values, index=len(band_names)) + else: + return array_create(data=index_values) + + +def compute_and_rescale_indices( + datacube: DataCube, + index_dict: dict, + *, + append: bool = False, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Computes a list of indices from a data cube + + :param datacube: input data cube + :param index_dict: a dictionary that contains the input- and output range of the collection on which you calculate the indices + as well as the indices that you want to calculate with their responding input- and output ranges + It follows the following format:: + + { + "collection": { + "input_range": [0,8000], + "output_range": [0,250] + }, + "indices": { + "NDVI": { + "input_range": [-1,1], + "output_range": [0,250] + }, + } + } + + If you don't want to rescale your data, you can fill the input-, index- and output-range with ``None``. + + See `list_indices()` for supported indices. + + :param append: append the indices as bands to the given data cube + instead of creating a new cube with only the calculated indices + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: the datacube with the indices attached as bands + + .. warning:: this "rescaled" index helper uses an experimental API (e.g. `index_dict` argument) that is subject to change. + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + + """ + index_specs = load_indices() + + _check_validity_index_dict(index_dict, index_specs) + + if variable_map is None: + # Automatic band mapping + band_mapping = _BandMapping() + if platform is None: + if datacube.metadata and datacube.metadata.get("id"): + platform = band_mapping.guess_platform(name=datacube.metadata.get("id")) + else: + raise BandMappingException("Unable to determine satellite platform from data cube metadata") + band_to_var = band_mapping.actual_band_name_to_variable_map( + platform=platform, band_names=datacube.metadata.band_names + ) + else: + band_to_var = {b: v for v, b in variable_map.items()} + + res = datacube.apply_dimension( + dimension="bands", + process=lambda x: _callback( + x, + index_dict=index_dict, + index_specs=index_specs, + append=append, + band_names=datacube.metadata.band_names, + band_to_var=band_to_var, + ), + ) + if append: + return res.rename_labels("bands", target=datacube.metadata.band_names + list(index_dict["indices"].keys())) + else: + return res.rename_labels("bands", target=list(index_dict["indices"].keys())) + + +def append_and_rescale_indices( + datacube: DataCube, + index_dict: dict, + *, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Computes a list of indices from a datacube and appends them to the existing datacube + + :param datacube: input data cube + :param index_dict: a dictionary that contains the input- and output range of the collection on which you calculate the indices + as well as the indices that you want to calculate with their responding input- and output ranges + It follows the following format:: + + { + "collection": { + "input_range": [0,8000], + "output_range": [0,250] + }, + "indices": { + "NDVI": { + "input_range": [-1,1], + "output_range": [0,250] + }, + } + } + + See `list_indices()` for supported indices. + + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube with appended indices + + .. warning:: this "rescaled" index helper uses an experimental API (e.g. `index_dict` argument) that is subject to change. + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + return compute_and_rescale_indices( + datacube=datacube, index_dict=index_dict, append=True, variable_map=variable_map, platform=platform + ) + + +def compute_indices( + datacube: DataCube, + indices: List[str], + *, + append: bool = False, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Compute multiple spectral indices from the given data cube. + + :param datacube: input data cube + :param indices: list of names of the indices to compute and append. See `list_indices()` for supported indices. + :param append: append the indices as bands to the given data cube + instead of creating a new cube with only the calculated indices + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube containing the indices as bands + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + # TODO: it's bit weird to have to specify all these None's in this structure + index_dict = { + "collection": { + "input_range": None, + "output_range": None, + }, + "indices": {index: {"input_range": None, "output_range": None} for index in indices}, + } + return compute_and_rescale_indices( + datacube=datacube, index_dict=index_dict, append=append, variable_map=variable_map, platform=platform + ) + + +def append_indices( + datacube: DataCube, + indices: List[str], + *, + variable_map: Optional[Dict[str, str]] = None, + platform: Optional[str] = None, +) -> DataCube: + """ + Compute multiple spectral indices and append them to the given data cube. + + :param datacube: input data cube + :param indices: list of names of the indices to compute and append. See `list_indices()` for supported indices. + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube with appended indices + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + + return compute_indices( + datacube=datacube, indices=indices, append=True, variable_map=variable_map, platform=platform + ) + + +def compute_index( + datacube: DataCube, index: str, *, variable_map: Optional[Dict[str, str]] = None, platform: Optional[str] = None +) -> DataCube: + """ + Compute a single spectral index from a data cube. + + :param datacube: input data cube + :param index: name of the index to compute. See `list_indices()` for supported indices. + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube containing the index as band + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + # TODO: option to compute the index with `reduce_dimension` instead of `apply_dimension`? + return compute_indices( + datacube=datacube, indices=[index], append=False, variable_map=variable_map, platform=platform + ) + + +def append_index( + datacube: DataCube, index: str, *, variable_map: Optional[Dict[str, str]] = None, platform: Optional[str] = None +) -> DataCube: + """ + Compute a single spectral index and append it to the given data cube. + + :param cube: input data cube + :param index: name of the index to compute and append. See `list_indices()` for supported indices. + :param variable_map: (optional) mapping from Awesome Spectral Indices formula variable to actual cube band names. + To be specified if the given data cube has non-standard band names, + or the satellite platform can not be recognized from the data cube metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + :param platform: optionally specify the satellite platform (to determine band name mapping) + if the given data cube has no or an unhandled collection id in its metadata. + See :ref:`spectral_indices_manual_band_mapping` for more information. + + :return: data cube with appended index + + .. versionadded:: 0.26.0 + Added `variable_map` and `platform` arguments. + """ + return compute_indices( + datacube=datacube, indices=[index], append=True, variable_map=variable_map, platform=platform + ) diff --git a/lib/openeo/internal/__init__.py b/lib/openeo/internal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/openeo/internal/compat.py b/lib/openeo/internal/compat.py new file mode 100644 index 000000000..f128d4f24 --- /dev/null +++ b/lib/openeo/internal/compat.py @@ -0,0 +1,13 @@ +""" +Compatibility layer and small backports. +""" + +import contextlib + +try: + from contextlib import nullcontext +except ImportError: + # nullcontext for pre-3.7 python + @contextlib.contextmanager + def nullcontext(enter_result=None): + yield enter_result diff --git a/lib/openeo/internal/documentation.py b/lib/openeo/internal/documentation.py new file mode 100644 index 000000000..ba588967d --- /dev/null +++ b/lib/openeo/internal/documentation.py @@ -0,0 +1,56 @@ +""" +Utilities to build/automate/extend documentation +""" +import collections +import inspect +import textwrap +from functools import partial +from typing import Callable, Optional, Tuple + +# TODO: give this a proper public API? +_process_registry = collections.defaultdict(list) + + +def openeo_process(f: Optional[Callable] = None, process_id: Optional[str] = None, mode: Optional[str] = None): + """ + Decorator for function or method to associate it with a standard openEO process + + :param f: function or method + :param process_id: openEO process_id (to be given when it can not be guessed from function name) + :return: + """ + # TODO: include openEO version? + # TODO: support non-standard/proposed/experimental? + # TODO: handling of `mode` (or something alike): apply/reduce_dimension/... callback, (band) math operator, ...? + # TODO: documentation test that "seealso" urls are valid + # TODO: inject more references/metadata in __doc__ + if f is None: + # Parameterized decorator call + return partial(openeo_process, process_id=process_id) + + process_id = process_id or f.__name__ + url = f"https://processes.openeo.org/#{process_id}" + seealso = f'.. seealso:: openeo.org documentation on `process "{process_id}" <{url}>`_.' + f.__doc__ = textwrap.dedent(f.__doc__ or "") + "\n\n" + seealso + + _process_registry[process_id].append((f, mode)) + return f + + +def openeo_endpoint(endpoint: str) -> Callable[[Callable], Callable]: + """ + Parameterized decorator to annotate given function or method with the openEO endpoint it interacts with + + :param endpoint: REST endpoint (e.g. "GET /jobs", "POST /result", ...) + :return: + """ + # TODO: automatically parse/normalize endpoint (to method+path) + # TODO: wrap this in some markup/directive to make this more a "small print" note. + + def decorate(f: Callable) -> Callable: + is_method = list(inspect.signature(f).parameters.keys())[:1] == ["self"] + seealso = f"This {'method' if is_method else 'function'} uses openEO endpoint ``{endpoint}``" + f.__doc__ = textwrap.dedent(f.__doc__ or "") + "\n\n" + seealso + "\n" + return f + + return decorate diff --git a/lib/openeo/internal/graph_building.py b/lib/openeo/internal/graph_building.py new file mode 100644 index 000000000..eb71615ba --- /dev/null +++ b/lib/openeo/internal/graph_building.py @@ -0,0 +1,422 @@ +""" +Internal openEO process graph building utilities +'''''''''''''''''''''''''''''''''''''''''''''''''' + +Internal functionality for abstracting, building, manipulating and processing openEO process graphs. + +""" + +from __future__ import annotations + +import abc +import collections +import json +import sys +from pathlib import Path +from typing import Any, Dict, Optional, Tuple, Union + +from openeo.api.process import Parameter +from openeo.internal.compat import nullcontext +from openeo.internal.process_graph_visitor import ( + ProcessGraphUnflattener, + ProcessGraphVisitException, + ProcessGraphVisitor, +) +from openeo.util import dict_no_none, load_json_resource + + +class FlatGraphableMixin(metaclass=abc.ABCMeta): + """ + Mixin for classes that can be exported/converted to + a "flat graph" representation of an openEO process graph. + """ + + @abc.abstractmethod + def flat_graph(self) -> Dict[str, dict]: + ... + + def to_json(self, *, indent: Union[int, None] = 2, separators: Optional[Tuple[str, str]] = None) -> str: + """ + Get interoperable JSON representation of the process graph. + + See :py:meth:`DataCube.print_json` to directly print the JSON representation + and :ref:`process_graph_export` for more usage information. + + Also see ``json.dumps`` docs for more information on the JSON formatting options. + + :param indent: JSON indentation level. + :param separators: (optional) tuple of item/key separators. + :return: JSON string + """ + pg = {"process_graph": self.flat_graph()} + return json.dumps(pg, indent=indent, separators=separators) + + def print_json( + self, + *, + file=None, + indent: Union[int, None] = 2, + separators: Optional[Tuple[str, str]] = None, + end: str = "\n", + ): + """ + Print interoperable JSON representation of the process graph. + + See :py:meth:`DataCube.to_json` to get the JSON representation as a string + and :ref:`process_graph_export` for more usage information. + + Also see ``json.dumps`` docs for more information on the JSON formatting options. + + :param file: file-like object (stream) to print to (current ``sys.stdout`` by default). + Or a path (string or pathlib.Path) to a file to write to. + :param indent: JSON indentation level. + :param separators: (optional) tuple of item/key separators. + :param end: additional string to be printed at the end (newline by default). + + .. versionadded:: 0.12.0 + + .. versionadded:: 0.23.0 + added the ``end`` argument. + """ + pg = {"process_graph": self.flat_graph()} + if isinstance(file, (str, Path)): + # Create (new) file and automatically close it + file_ctx = Path(file).open("w", encoding="utf8") + else: + # Just use file as-is, but don't close it automatically. + file_ctx = nullcontext(enter_result=file or sys.stdout) + with file_ctx as f: + json.dump(pg, f, indent=indent, separators=separators) + if end: + f.write(end) + + +class _FromNodeMixin(abc.ABC): + """Mixin for classes that want to hook into the generation of a "from_node" reference.""" + + @abc.abstractmethod + def from_node(self) -> PGNode: + # TODO: "from_node" is a bit a confusing name: + # it refers to the "from_node" node reference in openEO process graphs, + # but as a method name here it reads like "construct from PGNode", + # while it is actually meant as "export as PGNode" (that can be used in a "from_node" reference). + pass + + +class PGNode(_FromNodeMixin, FlatGraphableMixin): + """ + A process node in a process graph: has at least a process_id and arguments. + + Note that a full openEO "process graph" is essentially a directed acyclic graph of nodes + pointing to each other. A full process graph is practically equivalent with its "result" node, + as it points (directly or indirectly) to all the other nodes it depends on. + + .. warning:: + This class is an implementation detail meant for internal use. + It is not recommended for general use in normal user code. + Instead, use process graph abstraction builders like + :py:meth:`Connection.load_collection() `, + :py:meth:`Connection.datacube_from_process() `, + :py:meth:`Connection.datacube_from_flat_graph() `, + :py:meth:`Connection.datacube_from_json() `, + :py:meth:`Connection.load_ml_model() `, + :py:func:`openeo.processes.process()`, + + """ + + __slots__ = ["_process_id", "_arguments", "_namespace"] + + def __init__(self, process_id: str, arguments: dict = None, namespace: Union[str, None] = None, **kwargs): + self._process_id = process_id + # Merge arguments dict and kwargs + arguments = dict(**(arguments or {}), **kwargs) + # Make sure direct PGNode arguments are properly wrapped in a "from_node" dict + for arg, value in arguments.items(): + if isinstance(value, _FromNodeMixin): + arguments[arg] = {"from_node": value.from_node()} + elif isinstance(value, list): + for index, arrayelement in enumerate(value): + if isinstance(arrayelement, _FromNodeMixin): + value[index] = {"from_node": arrayelement.from_node()} + # TODO: use a frozendict of some sort to ensure immutability? + self._arguments = arguments + self._namespace = namespace + + def from_node(self): + return self + + def __repr__(self): + return "<{c} {p!r} at 0x{m:x}>".format(c=self.__class__.__name__, p=self.process_id, m=id(self)) + + @property + def process_id(self) -> str: + return self._process_id + + @property + def arguments(self) -> dict: + return self._arguments + + @property + def namespace(self) -> Union[str, None]: + return self._namespace + + def update_arguments(self, **kwargs): + """ + Add/Update arguments of the process node. + + .. versionadded:: 0.10.1 + """ + self._arguments = {**self._arguments, **kwargs} + + def _as_tuple(self): + return (self._process_id, self._arguments, self._namespace) + + def __eq__(self, other): + return isinstance(other, type(self)) and self._as_tuple() == other._as_tuple() + + def to_dict(self) -> dict: + """ + Convert process graph to a nested dictionary structure. + Uses deep copy style: nodes that are reused in graph will be deduplicated + """ + + def _deep_copy(x): + """PGNode aware deep copy helper""" + if isinstance(x, PGNode): + return dict_no_none(process_id=x.process_id, arguments=_deep_copy(x.arguments), namespace=x.namespace) + if isinstance(x, Parameter): + return {"from_parameter": x.name} + elif isinstance(x, dict): + return {str(k): _deep_copy(v) for k, v in x.items()} + elif isinstance(x, (list, tuple)): + return type(x)(_deep_copy(v) for v in x) + elif isinstance(x, (str, int, float)) or x is None: + return x + else: + raise ValueError(repr(x)) + + return _deep_copy(self) + + def flat_graph(self) -> Dict[str, dict]: + """Get the process graph in internal flat dict representation.""" + return GraphFlattener().flatten(node=self) + + @staticmethod + def to_process_graph_argument(value: Union['PGNode', str, dict]) -> dict: + """ + Normalize given argument properly to a "process_graph" argument + to be used as reducer/subprocess for processes like + ``reduce_dimension``, ``aggregate_spatial``, ``apply``, ``merge_cubes``, ``resample_cube_temporal`` + """ + if isinstance(value, str): + # assume string with predefined reduce/apply process ("mean", "sum", ...) + # TODO: is this case still used? It's invalid anyway for 1.0 openEO spec I think? + return value + elif isinstance(value, PGNode): + return {"process_graph": value} + elif isinstance(value, dict) and isinstance(value.get("process_graph"), PGNode): + return value + else: + raise ValueError(value) + + @staticmethod + def from_flat_graph(flat_graph: dict, parameters: Optional[dict] = None) -> PGNode: + """Unflatten a given flat dict representation of a process graph and return result node.""" + return PGNodeGraphUnflattener.unflatten(flat_graph=flat_graph, parameters=parameters) + + +def as_flat_graph(x: Union[dict, FlatGraphableMixin, Path, Any]) -> Dict[str, dict]: + """ + Convert given object to a internal flat dict graph representation. + """ + # TODO: document or verify which process graph flavor this is: + # including `{"process": {"process_graph": {nodes}}` ("process graph with metadata") + # including `{"process_graph": {nodes}}` ("process graph") + # or just the raw process graph nodes? + if isinstance(x, dict): + return x + elif isinstance(x, FlatGraphableMixin): + return x.flat_graph() + elif isinstance(x, (str, Path)): + # Assume a JSON resource (raw JSON, path to local file, JSON url, ...) + return load_json_resource(x) + raise ValueError(x) + + +class ReduceNode(PGNode): + """ + A process graph node for "reduce" processes (has a reducer sub-process-graph) + """ + + def __init__( + self, + data: _FromNodeMixin, + reducer: Union[PGNode, str, dict], + dimension: str, + context=None, + process_id="reduce_dimension", + band_math_mode: bool = False, + ): + assert process_id in ("reduce_dimension", "reduce_dimension_binary") + arguments = { + "data": data, + "reducer": self.to_process_graph_argument(reducer), + "dimension": dimension, + } + if context is not None: + arguments["context"] = context + super().__init__(process_id=process_id, arguments=arguments) + # TODO #123 is it (still) necessary to make "band" math a special case? + self.band_math_mode = band_math_mode + + @property + def dimension(self): + return self.arguments["dimension"] + + def reducer_process_graph(self) -> PGNode: + return self.arguments["reducer"]["process_graph"] + + def clone_with_new_reducer(self, reducer: PGNode) -> ReduceNode: + """Copy/clone this reduce node: keep input reference, but use new reducer""" + return ReduceNode( + data=self.arguments["data"]["from_node"], + reducer=reducer, + dimension=self.arguments["dimension"], + band_math_mode=self.band_math_mode, + context=self.arguments.get("context"), + ) + + +class FlatGraphNodeIdGenerator: + """ + Helper class to generate unique node ids (e.g. autoincrement style) + for processes in a flat process graph. + """ + + def __init__(self): + self._counters = collections.defaultdict(int) + + def generate(self, process_id: str): + """Generate new key for given process id.""" + self._counters[process_id] += 1 + return "{p}{c}".format(p=process_id.replace('_', ''), c=self._counters[process_id]) + + +class GraphFlattener(ProcessGraphVisitor): + + def __init__(self, node_id_generator: FlatGraphNodeIdGenerator = None): + super().__init__() + self._node_id_generator = node_id_generator or FlatGraphNodeIdGenerator() + self._last_node_id = None + self._flattened: Dict[str, dict] = {} + self._argument_stack = [] + self._node_cache = {} + + def flatten(self, node: PGNode) -> Dict[str, dict]: + """Consume given nested process graph and return flat dict representation""" + self.accept_node(node) + assert len(self._argument_stack) == 0 + self._flattened[self._last_node_id]["result"] = True + return self._flattened + + def accept_node(self, node: PGNode): + # Process reused nodes only first time and remember node id. + node_id = id(node) + if node_id not in self._node_cache: + super()._accept_process(process_id=node.process_id, arguments=node.arguments, namespace=node.namespace) + self._node_cache[node_id] = self._last_node_id + else: + self._last_node_id = self._node_cache[node_id] + + def enterProcess(self, process_id: str, arguments: dict, namespace: Union[str, None]): + self._argument_stack.append({}) + + def leaveProcess(self, process_id: str, arguments: dict, namespace: Union[str, None]): + node_id = self._node_id_generator.generate(process_id) + self._flattened[node_id] = dict_no_none( + process_id=process_id, + arguments=self._argument_stack.pop(), + namespace=namespace, + ) + self._last_node_id = node_id + + def _store_argument(self, argument_id: str, value): + if isinstance(value, Parameter): + value = {"from_parameter": value.name} + self._argument_stack[-1][argument_id] = value + + def _store_array_element(self, value): + if isinstance(value, Parameter): + value = {"from_parameter": value.name} + self._argument_stack[-1].append(value) + + def enterArray(self, argument_id: str): + array = [] + self._store_argument(argument_id, array) + self._argument_stack.append(array) + + def leaveArray(self, argument_id: str): + self._argument_stack.pop() + + def arrayElementDone(self, value): + self._store_array_element(self._flatten_argument(value)) + + def constantArrayElement(self, value): + self._store_array_element(self._flatten_argument(value)) + + def _flatten_argument(self, value): + if isinstance(value, dict): + if "from_node" in value: + value = {"from_node": self._last_node_id} + elif "process_graph" in value: + pg = value["process_graph"] + if isinstance(pg, PGNode): + value = {"process_graph": GraphFlattener(node_id_generator=self._node_id_generator).flatten(pg)} + elif isinstance(pg, dict): + # Assume it is already a valid flat graph representation of a subprocess + value = {"process_graph": pg} + else: + raise ValueError(pg) + else: + value = {k: self._flatten_argument(v) for k, v in value.items()} + elif isinstance(value, Parameter): + value = {"from_parameter": value.name} + return value + + def leaveArgument(self, argument_id: str, value): + self._store_argument(argument_id, self._flatten_argument(value)) + + def constantArgument(self, argument_id: str, value): + self._store_argument(argument_id, value) + + +class PGNodeGraphUnflattener(ProcessGraphUnflattener): + """ + Unflatten a flat process graph to a graph of :py:class:`PGNode` objects + + Parameter substitution can also be performed, but is optional: + if the ``parameters=None`` is given, no parameter substitution is done, + if it is a dictionary (even an empty one) is given, every parameter encountered in the process + graph must have an entry for substitution. + """ + + def __init__(self, flat_graph: dict, parameters: Optional[dict] = None): + super().__init__(flat_graph=flat_graph) + self._parameters = parameters + + def _process_node(self, node: dict) -> PGNode: + return PGNode( + process_id=node["process_id"], + arguments=self._process_value(value=node["arguments"]), + namespace=node.get("namespace") + ) + + def _process_from_node(self, key: str, node: dict) -> PGNode: + return self.get_node(key=key) + + def _process_from_parameter(self, name: str) -> Any: + if self._parameters is None: + return super()._process_from_parameter(name=name) + if name not in self._parameters: + raise ProcessGraphVisitException("No substitution value for parameter {p!r}.".format(p=name)) + return self._parameters[name] diff --git a/lib/openeo/internal/jupyter.py b/lib/openeo/internal/jupyter.py new file mode 100644 index 000000000..58a9347f6 --- /dev/null +++ b/lib/openeo/internal/jupyter.py @@ -0,0 +1,177 @@ +import json +import os + +from openeo.rest import OpenEoApiError + +SCRIPT_URL = 'https://cdn.jsdelivr.net/npm/@openeo/vue-components@2/assets/openeo.min.js' +COMPONENT_MAP = { + 'collection': 'data', + 'data-table': 'data', + 'file-format': 'format', + 'file-formats': 'formats', + 'item': 'data', + 'job-estimate': 'estimate', + 'model-builder': 'value', + 'service-type': 'service', + 'service-types': 'services', + 'udf-runtime': 'runtime', + 'udf-runtimes': 'runtimes', +} + +TABLE_COLUMNS = { + 'jobs': { + 'id': { + 'name': 'ID', + 'primaryKey': True + }, + 'title': { + 'name': 'Title' + }, + 'status': { + 'name': 'Status', +# 'stylable': True + }, + 'created': { + 'name': 'Submitted', + 'format': 'Timestamp', + 'sort': 'desc' + }, + 'updated': { + 'name': 'Last update', + 'format': 'Timestamp' + } + }, + 'services': { + 'id': { + 'name': 'ID', + 'primaryKey': True + }, + 'title': { + 'name': 'Title' + }, + 'type': { + 'name': 'Type', +# 'format': value => typeof value === 'string' ? value.toUpperCase() : value, + }, + 'enabled': { + 'name': 'Enabled' + }, + 'created': { + 'name': 'Submitted', + 'format': 'Timestamp', + 'sort': 'desc' + } + }, + 'files': { + 'path': { + 'name': 'Path', + 'primaryKey': True, +# 'sortFn': Utils.sortByPath, + 'sort': 'asc' + }, + 'size': { + 'name': 'Size', + 'format': "FileSize", + 'filterable': False + }, + 'modified': { + 'name': 'Last modified', + 'format': 'Timestamp' + } + } +} + + +def in_jupyter_context() -> bool: + """Check if we are running in an interactive Jupyter notebook context.""" + try: + from ipykernel.zmqshell import ZMQInteractiveShell + from IPython.core.getipython import get_ipython + except ImportError: + return False + return isinstance(get_ipython(), ZMQInteractiveShell) + + +def render_component(component: str, data = None, parameters: dict = None): + parameters = parameters or {} + # Special handling for batch job results, show either item or collection depending on the data + if component == "batch-job-result": + component = "item" if data["type"] == "Feature" else "collection" + + if component == "data-table": + parameters['columns'] = TABLE_COLUMNS[parameters['columns']] + elif component in ['collection', 'collections', 'item', 'items']: + url = os.environ.get("OPENEO_BASEMAP_URL") + attribution = os.environ.get("OPENEO_BASEMAP_ATTRIBUTION") + parameters['mapOptions'] = {} + if url: + parameters['mapOptions']['basemap'] = url + if attribution: + parameters['mapOptions']['attribution'] = attribution + + # Set the data as the corresponding parameter in the Vue components + key = COMPONENT_MAP.get(component, component) + if data is not None: + if isinstance(data, list): + # TODO: make this `to_dict` usage more explicit with an internal API? + data = [(x.to_dict() if hasattr(x, "to_dict") else x) for x in data] + parameters[key] = data + + # Construct HTML, load Vue Components source files only if the openEO HTML tag is not yet defined + return """ + + + + + """.format( + script=SCRIPT_URL, + component=component, + props=json.dumps(parameters) + ) + + +def render_error(error: OpenEoApiError): + # ToDo: Once we have a dedicated log/error component, use that instead of description + output = """## Error `{code}`\n\n{message}""".format( + code=error.code, + message=error.message + ) + return render_component('description', data=output) + + +# These classes are proxies to visualize openEO responses nicely in Jupyter +# To show the actual list or dict in Jupyter, use repr() or print() + +class VisualDict(dict): + + def __init__(self, component: str, data: dict, parameters: dict = None): + dict.__init__(self, data) + self.component = component + self.parameters = parameters or {} + + def _repr_html_(self): + return render_component(self.component, self, self.parameters) + + +class VisualList(list): + + def __init__(self, component: str, data: list, parameters: dict = None): + list.__init__(self, data) + self.component = component + self.parameters = parameters or {} + + def _repr_html_(self): + return render_component(self.component, self, self.parameters) diff --git a/lib/openeo/internal/process_graph_visitor.py b/lib/openeo/internal/process_graph_visitor.py new file mode 100644 index 000000000..8315eda40 --- /dev/null +++ b/lib/openeo/internal/process_graph_visitor.py @@ -0,0 +1,266 @@ +from __future__ import annotations + +import json +from abc import ABC +from typing import Any, Tuple, Union + +from openeo.internal.warnings import deprecated +from openeo.rest import OpenEoClientException + + +class ProcessGraphVisitException(OpenEoClientException): + pass + + +class ProcessGraphVisitor(ABC): + """ + Hierarchical Visitor for (nested) process graphs structures. + """ + + def __init__(self): + self.process_stack = [] + + @classmethod + def dereference_from_node_arguments(cls, process_graph: dict) -> str: + """ + Walk through the given (flat) process graph and replace (in-place) "from_node" references in + process arguments (dictionaries or lists) with the corresponding resolved subgraphs + + :param process_graph: process graph dictionary to be manipulated in-place + :return: name of the "result" node of the graph + """ + + # TODO avoid manipulating process graph in place? make it more explicit? work on a copy? + # TODO call it more something like "unflatten"?. Split this off of ProcessGraphVisitor? + # TODO implement this through `ProcessGraphUnflattener` ? + + def resolve_from_node(process_graph, node, from_node): + if from_node not in process_graph: + raise ProcessGraphVisitException('from_node {f!r} (referenced by {n!r}) not in process graph.'.format( + f=from_node, n=node)) + return process_graph[from_node] + + result_node = None + for node, node_dict in process_graph.items(): + if node_dict.get("result", False): + if result_node: + raise ProcessGraphVisitException("Multiple result nodes: {a}, {b}".format(a=result_node, b=node)) + result_node = node + arguments = node_dict.get("arguments", {}) + for arg in arguments.values(): + if isinstance(arg, dict): + if "from_node" in arg: + arg["node"] = resolve_from_node(process_graph, node, arg["from_node"]) + else: + for k, v in arg.items(): + if isinstance(v, dict) and "from_node" in v: + v["node"] = resolve_from_node(process_graph, node, v["from_node"]) + elif isinstance(arg, list): + for i, element in enumerate(arg): + if isinstance(element, dict) and "from_node" in element: + arg[i] = resolve_from_node(process_graph, node, element['from_node']) + + if result_node is None: + dump = json.dumps(process_graph, indent=2) + raise ProcessGraphVisitException("No result node in process graph: " + dump[:1000]) + return result_node + + def accept_process_graph(self, graph: dict) -> ProcessGraphVisitor: + """ + Traverse a (flat) process graph + + :param graph: + :return: + """ + # TODO: this is driver specific functionality, working on flattened graph structures. Make this more clear? + top_level_node = self.dereference_from_node_arguments(graph) + self.accept_node(graph[top_level_node]) + return self + + @deprecated(reason="Use accept_node() instead", version="0.4.6") + def accept(self, node: dict): + self.accept_node(node) + + def accept_node(self, node: dict): + pid = node['process_id'] + arguments = node.get('arguments', {}) + namespace = node.get("namespace", None) + self._accept_process(process_id=pid, arguments=arguments, namespace=namespace) + + def _accept_process(self, process_id: str, arguments: dict, namespace: Union[str, None]): + self.process_stack.append(process_id) + self.enterProcess(process_id=process_id, arguments=arguments, namespace=namespace) + for arg_id, value in sorted(arguments.items()): + if isinstance(value, list): + self.enterArray(argument_id=arg_id) + self._accept_argument_list(value) + self.leaveArray(argument_id=arg_id) + elif isinstance(value, dict): + self.enterArgument(argument_id=arg_id, value=value) + self._accept_argument_dict(value) + self.leaveArgument(argument_id=arg_id, value=value) + else: + self.constantArgument(argument_id=arg_id, value=value) + self.leaveProcess(process_id=process_id, arguments=arguments, namespace=namespace) + assert self.process_stack.pop() == process_id + + def _accept_argument_list(self, elements: list): + for element in elements: + if isinstance(element, dict): + self._accept_argument_dict(element) + self.arrayElementDone(element) + else: + self.constantArrayElement(element) + + def _accept_argument_dict(self, value: dict): + if 'node' in value and 'from_node' in value: + # TODO: this looks bit weird (or at least very specific). + self.accept_node(value['node']) + elif value.get("from_node"): + self.accept_node(value['from_node']) + elif "process_id" in value: + self.accept_node(value) + elif "from_parameter" in value: + self.from_parameter(value['from_parameter']) + else: + self._accept_dict(value) + + def _accept_dict(self, value: dict): + pass + + def from_parameter(self,parameter_id:str): + pass + + def enterProcess(self, process_id: str, arguments: dict, namespace: Union[str, None]): + pass + + def leaveProcess(self, process_id: str, arguments: dict, namespace: Union[str, None]): + pass + + def enterArgument(self, argument_id: str, value): + pass + + def leaveArgument(self, argument_id: str, value): + pass + + def constantArgument(self, argument_id: str, value): + pass + + def enterArray(self, argument_id: str): + pass + + def leaveArray(self, argument_id: str): + pass + + def constantArrayElement(self, value): + pass + + def arrayElementDone(self, value: dict): + pass + + +def find_result_node(flat_graph: dict) -> Tuple[str, dict]: + """ + Find result node in flat graph + + :return: tuple with node id (str) and node dictionary of the result node. + """ + result_nodes = [(key, node) for (key, node) in flat_graph.items() if node.get("result")] + + if len(result_nodes) == 1: + return result_nodes[0] + elif len(result_nodes) == 0: + raise ProcessGraphVisitException("Found no result node in flat process graph") + else: + keys = [k for (k, n) in result_nodes] + raise ProcessGraphVisitException( + "Found multiple result nodes in flat process graph: {keys!r}".format(keys=keys)) + + +class ProcessGraphUnflattener: + """ + Base class to process a flat graph representation of a process graph + and unflatten it by resolving the "from_node" references. + Subclassing and overriding certain methods allows to build a desired unflattened graph structure. + """ + + # Sentinel object for flagging a node "under construction" and detect graph cycles. + _UNDER_CONSTRUCTION = object() + + def __init__(self, flat_graph: dict): + self._flat_graph = flat_graph + self._nodes = {} + + @classmethod + def unflatten(cls, flat_graph: dict, **kwargs): + """Class method helper to unflatten given flat process graph""" + return cls(flat_graph=flat_graph, **kwargs).process() + + def process(self): + """Process the flat process graph: unflatten it.""" + result_key, result_node = find_result_node(flat_graph=self._flat_graph) + return self.get_node(result_key) + + def get_node(self, key: str) -> Any: + """Get processed node by node key.""" + if key not in self._nodes: + self._nodes[key] = self._UNDER_CONSTRUCTION + node = self._process_node(self._flat_graph[key]) + self._nodes[key] = node + elif self._nodes[key] is self._UNDER_CONSTRUCTION: + raise ProcessGraphVisitException("Cycle in process graph") + return self._nodes[key] + + def _process_node(self, node: dict) -> Any: + """ + Overridable: generate process graph node from flat_graph data. + """ + # Default implementation: basic validation/whitelisting, and only traverse arguments + return dict( + process_id=node["process_id"], + arguments=self._process_value(value=node["arguments"]), + **{k: node[k] for k in ["namespace", "description", "result"] if k in node} + ) + + def _process_from_node(self, key: str, node: dict) -> Any: + """ + Overridable: generate a node from a flat_graph "from_node" reference + """ + # Default/original implementation: keep "from_node" key and add resolved node under "node" key. + # TODO: just return `self.get_node(key=key)` + return { + "from_node": key, + "node": self.get_node(key=key) + } + + def _process_from_parameter(self, name: str) -> Any: + """ + Overridable: generate a node from a flat_graph "from_parameter" reference + """ + # Default implementation: + return {"from_parameter": name} + + def _resolve_from_node(self, key: str) -> dict: + if key not in self._flat_graph: + raise ProcessGraphVisitException("from_node reference {k!r} not found in process graph".format(k=key)) + return self._flat_graph[key] + + def _process_value(self, value) -> Any: + if isinstance(value, dict): + if "from_node" in value: + key = value["from_node"] + node = self._resolve_from_node(key=key) + return self._process_from_node(key=key, node=node) + elif "from_parameter" in value: + name = value["from_parameter"] + return self._process_from_parameter(name=name) + elif "process_graph" in value: + # Don't traverse child process graphs + # TODO: should/can we? Can we know available parameters for validation, or do we skip validation? + return value + else: + return {k: self._process_value(v) for (k, v) in value.items()} + elif isinstance(value, (list, tuple)): + return [self._process_value(v) for v in value] + else: + return value diff --git a/lib/openeo/internal/processes/__init__.py b/lib/openeo/internal/processes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/openeo/internal/processes/builder.py b/lib/openeo/internal/processes/builder.py new file mode 100644 index 000000000..24816e46a --- /dev/null +++ b/lib/openeo/internal/processes/builder.py @@ -0,0 +1,123 @@ +import inspect +import logging +import warnings +from typing import Any, Callable, Dict, List, Optional, Union + +from openeo.internal.graph_building import FlatGraphableMixin, PGNode, _FromNodeMixin +from openeo.rest import OpenEoClientException + +UNSET = object() +_log = logging.getLogger(__name__) + + +def _to_pgnode_data(value: Any) -> Union[PGNode, dict, Any]: + """Convert given value to valid process graph material""" + if isinstance(value, ProcessBuilderBase): + return value.pgnode + elif isinstance(value, list): + return [_to_pgnode_data(item) for item in value] + elif isinstance(value, Callable): + pg = convert_callable_to_pgnode(value) + return PGNode.to_process_graph_argument(pg) + else: + # Fallback: assume value is valid process graph material already. + return value + + +class ProcessBuilderBase(_FromNodeMixin, FlatGraphableMixin): + """ + Base implementation of a builder pattern that allows constructing process graphs + by calling functions. + """ + + # TODO: can this implementation be merged with PGNode directly? + + def __init__(self, pgnode: Union[PGNode, dict, list]): + self.pgnode = pgnode + + @classmethod + def process(cls, process_id: str, arguments: dict = None, namespace: Union[str, None] = None, **kwargs): + """ + Apply process, using given arguments + + :param process_id: process id of the process. + :param arguments: argument dictionary for the process. + :param namespace: process namespace (only necessary to specify for non-predefined or non-user-defined processes) + :return: new ProcessBuilder instance + """ + arguments = {**(arguments or {}), **kwargs} + arguments = { + k: _to_pgnode_data(v) + for k, v in arguments.items() + if v is not UNSET + } + return cls(PGNode(process_id=process_id, arguments=arguments, namespace=namespace)) + + def flat_graph(self) -> Dict[str, dict]: + """Get the process graph in internal flat dict representation.""" + return self.pgnode.flat_graph() + + def from_node(self) -> PGNode: + # _FromNodeMixin API + return self.pgnode + + +def get_parameter_names(process: Callable) -> List[str]: + """Get argument (aka parameter) names of given function/callable.""" + signature = inspect.signature(process) + return [ + p.name for p in signature.parameters.values() + if p.kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD) + ] + + +def convert_callable_to_pgnode(callback: Callable, parent_parameters: Optional[List[str]] = None) -> PGNode: + """ + Convert given process callback to a PGNode. + + >>> result = convert_callable_to_pgnode(lambda x: x + 5) + >>> assert isinstance(result, PGNode) + >>> result.flat_graph() + {"add1": {"process_id": "add", "arguments": {"x": {"from_parameter": "x"}, "y": 5}, "result": True}} + + """ + # TODO: eliminate local import (due to circular dependency)? + from openeo.processes import ProcessBuilder + + process_params = get_parameter_names(callback) + if parent_parameters is None: + # Due to lack of parent parameter information, + # we blindly use all callback's argument names as parameter names + # TODO #426: Instead of guessing: extract expected parent_parameters, e.g. based on parent process_id? + message = f"Blindly using callback parameter names from {callback!r} argument names: {process_params!r}" + if tuple(process_params) not in {(), ("x",), ("data",), ("x", "y")}: + warnings.warn(message) + else: + _log.info(message) + kwargs = {p: ProcessBuilder({"from_parameter": p}) for p in process_params} + elif parent_parameters == ["x", "y"] and (len(process_params) == 1 or process_params[:1] == ["data"]): + # Special case: wrap all parent parameters in an array + kwargs = {process_params[0]: ProcessBuilder([{"from_parameter": p} for p in parent_parameters])} + else: + # Check for direct correspondence between callback arguments and parent parameters (or subset thereof). + common = set(parent_parameters).intersection(process_params) + if common: + kwargs = {p: ProcessBuilder({"from_parameter": p}) for p in common} + elif min(len(parent_parameters), len(process_params)) == 0: + kwargs = {} + elif min(len(parent_parameters), len(process_params)) == 1: + # Fallback for common case of just one callback argument (pass the main parameter), + # or one parent parameter (just pass that one) + kwargs = {process_params[0]: ProcessBuilder({"from_parameter": parent_parameters[0]})} + else: + raise OpenEoClientException( + f"Callback argument mismatch: expected (prefix of) {parent_parameters}, but found found {process_params!r}" + ) + + # "Evaluate" the callback, which should give a ProcessBuilder again to extract pgnode from + result = callback(**kwargs) + if not isinstance(result, ProcessBuilderBase): + raise OpenEoClientException( + f"Callback {callback} did not evaluate to ProcessBuilderBase. Got {result!r} instead" + ) + return result.pgnode diff --git a/lib/openeo/internal/processes/generator.py b/lib/openeo/internal/processes/generator.py new file mode 100644 index 000000000..314b244c0 --- /dev/null +++ b/lib/openeo/internal/processes/generator.py @@ -0,0 +1,287 @@ +import argparse +import datetime +import keyword +import sys +import textwrap +from pathlib import Path +from typing import Iterator, List, Optional, Union + +from openeo.internal.processes.parse import Process, parse_all_from_dir + + +class PythonRenderer: + """Generator of Python function source code for a given openEO process""" + DEFAULT_WIDTH = 115 + + def __init__( + self, + oo_mode: bool = False, + indent: str = " ", + body_template: str = "return _process({id!r}, {args})", + optional_default="None", + return_type_hint: Optional[str] = None, + decorator: Optional[str] = None, + ): + self.oo_mode = oo_mode + self.indent = indent + self.body_template = body_template + self.optional_default = optional_default + self.return_type_hint = return_type_hint + self.decorator = decorator + + def render_process(self, process: Process, prefix: str = None, width: int = DEFAULT_WIDTH) -> str: + if prefix is None: + prefix = " " if self.oo_mode else "" + + # TODO: add type hints + # TODO: width limit? + def_line = "def {id}({args}){th}:".format( + id=self._safe_name(process.id), + args=", ".join(self._def_arguments(process)), + th=" -> {t}".format(t=self.return_type_hint) if self.return_type_hint else "" + ) + + call_args = ", ".join(self._call_args(process)) + if len(call_args) > width: + # TODO: also include `id` placeholder in `self.body_format` + call_args = ( + "\n" + ",\n".join(self.indent + self.indent + a for a in self._call_args(process)) + "\n" + self.indent + ) + body = self.indent + self.body_template.format( + id=process.id, safe_name=self._safe_name(process.id), args=call_args + ) + + lines = ([self.decorator] if self.decorator else []) + [ + def_line, + self.render_docstring(process, width=width - len(prefix), prefix=self.indent), + body + ] + return textwrap.indent("\n".join(lines), prefix=prefix) + + def _safe_name(self, name: str) -> str: + if keyword.iskeyword(name): + name += '_' + return name + + def _par_names(self, process: Process) -> List[str]: + """Names of the openEO process parameters""" + return [self._safe_name(p.name) for p in process.parameters] + + def _arg_names(self, process: Process) -> List[str]: + """Names of the arguments in the python function""" + arg_names = self._par_names(process) + if self.oo_mode and arg_names: + arg_names[0] = "self" + return arg_names + + def _call_args(self, process: Process) -> Iterator[str]: + for parameter, par_name, arg_name in zip( + process.parameters, self._par_names(process), self._arg_names(process) + ): + arg_expression = arg_name + if parameter.schema.is_process_graph(): + parent_parameters = [p["name"] for p in parameter.schema.schema["parameters"]] + arg_expression = f"build_child_callback({arg_expression}, parent_parameters={parent_parameters})" + yield f"{par_name}={arg_expression}" + + def _def_arguments(self, process: Process) -> Iterator[str]: + # TODO: add argument type hints? + for arg, param in zip(self._arg_names(process), process.parameters): + if param.optional: + yield "{a}={d}".format(a=arg, d=self.optional_default) + elif param.has_default(): + yield "{a}={d!r}".format(a=arg, d=param.default) + else: + yield arg + if self.oo_mode and len(process.parameters) == 0: + yield "self" + + def render_docstring(self, process: Process, prefix="", width: int = DEFAULT_WIDTH) -> str: + w = width - len(prefix) + # TODO: use description instead of summary? + doc = "\n\n".join(textwrap.fill(d, width=w) for d in process.summary.split("\n\n")) + params = "\n".join( + self._hanging_indent(":param {n}: {d}".format(n=arg, d=param.description), width=w) + for arg, param in zip(self._arg_names(process), process.parameters) + ) + returns = self._hanging_indent(":return: {d}".format(d=process.returns.description), width=w) + return textwrap.indent('"""\n' + doc + "\n\n" + (params + "\n\n" + returns).strip() + '\n"""', prefix=prefix) + + def _hanging_indent(self, paragraph: str, indent=" ", width: int = DEFAULT_WIDTH) -> str: + return textwrap.indent(textwrap.fill(paragraph, width=width - len(indent)), prefix=indent).lstrip() + + +def collect_processes(sources: List[Union[Path, str]]) -> List[Process]: + processes = [] + for src in [Path(s) for s in sources]: + if src.is_dir(): + processes.extend(parse_all_from_dir(src)) + else: + processes.append(Process.from_json_file(src)) + processes.sort(key=lambda p: p.id) + return processes + + +def generate_process_py(processes: List[Process], output=sys.stdout, argv=None): + oo_src = textwrap.dedent( + """ + from __future__ import annotations + + import builtins + + from openeo.internal.processes.builder import ProcessBuilderBase, UNSET + from openeo.internal.documentation import openeo_process + from openeo.rest._datacube import build_child_callback + + + class ProcessBuilder(ProcessBuilderBase): + \"\"\" + .. include:: api-processbuilder.rst + \"\"\" + + _ITERATION_LIMIT = 100 + + @openeo_process(process_id="add", mode="operator") + def __add__(self, other) -> ProcessBuilder: + return self.add(other) + + @openeo_process(process_id="add", mode="operator") + def __radd__(self, other) -> ProcessBuilder: + return add(other, self) + + @openeo_process(process_id="subtract", mode="operator") + def __sub__(self, other) -> ProcessBuilder: + return self.subtract(other) + + @openeo_process(process_id="subtract", mode="operator") + def __rsub__(self, other) -> ProcessBuilder: + return subtract(other, self) + + @openeo_process(process_id="multiply", mode="operator") + def __mul__(self, other) -> ProcessBuilder: + return self.multiply(other) + + @openeo_process(process_id="multiply", mode="operator") + def __rmul__(self, other) -> ProcessBuilder: + return multiply(other, self) + + @openeo_process(process_id="divide", mode="operator") + def __truediv__(self, other) -> ProcessBuilder: + return self.divide(other) + + @openeo_process(process_id="divide", mode="operator") + def __rtruediv__(self, other) -> ProcessBuilder: + return divide(other, self) + + @openeo_process(process_id="multiply", mode="operator") + def __neg__(self) -> ProcessBuilder: + return self.multiply(-1) + + @openeo_process(process_id="power", mode="operator") + def __pow__(self, other) -> ProcessBuilder: + return self.power(other) + + @openeo_process(process_id="array_element", mode="operator") + def __getitem__(self, key) -> ProcessBuilder: + if isinstance(key, builtins.int): + if key > self._ITERATION_LIMIT: + raise RuntimeError( + "Exceeded ProcessBuilder iteration limit. " + "Are you mistakenly using a Python builtin like `sum()` or `all()` in a callback " + "instead of the appropriate helpers from the `openeo.processes` module?" + ) + return self.array_element(index=key) + else: + return self.array_element(label=key) + + @openeo_process(process_id="eq", mode="operator") + def __eq__(self, other) -> ProcessBuilder: + return eq(self, other) + + @openeo_process(process_id="neq", mode="operator") + def __ne__(self, other) -> ProcessBuilder: + return neq(self, other) + + @openeo_process(process_id="lt", mode="operator") + def __lt__(self, other) -> ProcessBuilder: + return lt(self, other) + + @openeo_process(process_id="lte", mode="operator") + def __le__(self, other) -> ProcessBuilder: + return lte(self, other) + + @openeo_process(process_id="ge", mode="operator") + def __ge__(self, other) -> ProcessBuilder: + return gte(self, other) + + @openeo_process(process_id="gt", mode="operator") + def __gt__(self, other) -> ProcessBuilder: + return gt(self, other) + + """ + ) + fun_src = textwrap.dedent( + """ + # Public shortcut + process = ProcessBuilder.process + # Private shortcut that has lower chance to collide with a process argument named `process` + _process = ProcessBuilder.process + + + """ + ) + fun_renderer = PythonRenderer( + body_template="return _process({id!r}, {args})", + optional_default="UNSET", + return_type_hint="ProcessBuilder", + decorator="@openeo_process", + ) + oo_renderer = PythonRenderer( + oo_mode=True, + body_template="return {safe_name}({args})", + optional_default="UNSET", + return_type_hint="ProcessBuilder", + decorator="@openeo_process", + ) + for p in processes: + fun_src += fun_renderer.render_process(p) + "\n\n\n" + oo_src += oo_renderer.render_process(p) + "\n\n" + output.write(textwrap.dedent(""" + # Do not edit this file directly. + # It is automatically generated. + """)) + if argv: + output.write(textwrap.dedent("""\ + # Used command line arguments: + # {cli} + """.format(cli=" ".join(argv)))) + output.write(f"# Generated on {datetime.date.today().isoformat()}\n") + + output.write(oo_src) + output.write(fun_src.rstrip() + "\n") + + +def main(): + # Usage example (from project root): + # # Update subrepos (with process specs) + # python specs/update-subrepos.py + # python openeo/internal/processes/generator.py specs/openeo-processes specs/openeo-processes/proposals --output openeo/processes.py + + argv = sys.argv + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument( + "source", nargs="+", + help="""Source directories or files containing openEO process definitions in JSON format""") + arg_parser.add_argument("--output", help="Path to output 'processes.py' file") + + arguments = arg_parser.parse_args(argv[1:]) + sources = arguments.source + output = arguments.output + + processes = collect_processes(sources) + with (open(output, "w", encoding="utf-8") if output else sys.stdout) as f: + generate_process_py(processes, output=f, argv=argv) + + +if __name__ == '__main__': + main() diff --git a/lib/openeo/internal/processes/parse.py b/lib/openeo/internal/processes/parse.py new file mode 100644 index 000000000..c4d2ba134 --- /dev/null +++ b/lib/openeo/internal/processes/parse.py @@ -0,0 +1,114 @@ +""" +Functionality and tools to process openEO processes. +For example: parse a bunch of JSON descriptions and generate Python (stub) functions. +""" +from __future__ import annotations + +import json +from pathlib import Path +from typing import Iterator, List, Union + +import requests + + +class Schema: + """Schema description of an openEO process parameter or return value.""" + + def __init__(self, schema: Union[dict, list]): + self.schema = schema + + @classmethod + def from_dict(cls, data: dict) -> Schema: + return cls(schema=data) + + def is_process_graph(self) -> bool: + """Is this a {"type": "object", "subtype": "process-graph"} schema?""" + return ( + isinstance(self.schema, dict) + and self.schema.get("type") == "object" + and self.schema.get("subtype") == "process-graph" + ) + + +class Parameter: + """openEO process parameter""" + # TODO unify with openeo.api.process.Parameter? + + NO_DEFAULT = object() + + def __init__(self, name: str, description: str, schema: Schema, default=NO_DEFAULT, optional: bool = False): + self.name = name + self.description = description + self.schema = schema + self.default = default + self.optional = optional + + @classmethod + def from_dict(cls, data: dict) -> Parameter: + return cls( + name=data["name"], description=data["description"], schema=Schema.from_dict(data["schema"]), + default=data.get("default", cls.NO_DEFAULT), optional=data.get("optional", False) + ) + + def has_default(self): + return self.default is not self.NO_DEFAULT + + +class Returns: + """openEO process return description.""" + + def __init__(self, description: str, schema: Schema): + self.description = description + self.schema = schema + + @classmethod + def from_dict(cls, data: dict) -> Returns: + return cls(description=data["description"], schema=Schema.from_dict(data["schema"])) + + +class Process: + """An openEO process""" + + def __init__( + self, id: str, parameters: List[Parameter], returns: Returns, + description: str = "", summary: str = "" + ): + self.id = id + self.description = description + self.parameters = parameters + self.returns = returns + self.summary = summary + # TODO: more properties? + + @classmethod + def from_dict(cls, data: dict) -> Process: + """Construct openEO process from dictionary values""" + return cls( + id=data["id"], + parameters=[Parameter.from_dict(d) for d in data["parameters"]], + returns=Returns.from_dict(data["returns"]), + description=data["description"], + summary=data["summary"], + ) + + @classmethod + def from_json(cls, data: str) -> Process: + """Parse openEO process JSON description.""" + return cls.from_dict(json.loads(data)) + + @classmethod + def from_json_url(cls, url: str) -> Process: + """Parse openEO process JSON description from given URL.""" + return cls.from_dict(requests.get(url).json()) + + @classmethod + def from_json_file(cls, path: Union[str, Path]) -> Process: + """Parse openEO process JSON description file.""" + with Path(path).open("r") as f: + return cls.from_json(f.read()) + + +def parse_all_from_dir(path: Union[str, Path], pattern="*.json") -> Iterator[Process]: + """Parse all openEO process files in given directory""" + for p in sorted(Path(path).glob(pattern)): + yield Process.from_json_file(p) diff --git a/lib/openeo/internal/warnings.py b/lib/openeo/internal/warnings.py new file mode 100644 index 000000000..df083753a --- /dev/null +++ b/lib/openeo/internal/warnings.py @@ -0,0 +1,92 @@ +import functools +import inspect +import warnings +from typing import Callable, Optional + +from deprecated.sphinx import deprecated as _deprecated + + +class UserDeprecationWarning(Warning): + """ + Python has a built-in `DeprecationWarning` class to warn about deprecated features, + but as the docs state (https://docs.python.org/3/library/warnings.html): + + when those warnings are intended for other Python developers + + Consequently, the default warning filters are set up to ignore (hide) these warnings + to the software end user. The developer is expected to explicitly set up + the warning filters to show the deprecation warnings again. + + In case of the openeo Python client however, this does not work because the client user + is usually the developer, but probably won't bother setting up warning filters properly. + + This custom warning class can be used as drop in replacement for `DeprecationWarning`, + where the deprecation warning should be visible by default. + """ + pass + + +def test_warnings(stacklevel=1): + """Trigger some warnings (for test contexts).""" + for warning in [UserWarning, DeprecationWarning, UserDeprecationWarning]: + warnings.warn( + f"This is a {warning.__name__} (stacklevel {stacklevel})", + category=warning, stacklevel=stacklevel + ) + + +def legacy_alias(orig: Callable, name: str = "n/a", *, since: str, mode: str = "full"): + """ + Create legacy alias of given function/method/classmethod/staticmethod + + :param orig: function/method to create legacy alias for + :param name: name of the alias (unused) + :param since: version since when this is alias is deprecated + :param mode: + - "full": raise warnings on calling, only have deprecation note as doc + - "soft": don't raise warning on calling, just add deprecation note to doc + :return: + """ + # TODO: drop `name` argument? + post_process = None + if isinstance(orig, classmethod): + post_process = classmethod + orig = orig.__func__ + kind = "class method" + elif isinstance(orig, staticmethod): + post_process = staticmethod + orig = orig.__func__ + kind = "static method" + elif inspect.ismethod(orig) or "self" in inspect.signature(orig).parameters: + kind = "method" + elif inspect.isfunction(orig): + kind = "function" + else: + raise ValueError(orig) + + # Create a "copy" by wrapping the original + @functools.wraps(orig) + def wrapper(*args, **kwargs): + return orig(*args, **kwargs) + + ref = f":py:{'meth' if 'method' in kind else 'func'}:`.{orig.__name__}`" + message = f"Usage of this legacy {kind} is deprecated. Use {ref} instead." + + if mode == "full": + # Drop original doc block, just show deprecation note. + wrapper.__doc__ = "" + wrapper = deprecated(reason=message, version=since)(wrapper) + elif mode == "soft": + # Only keep first paragraph of original doc block + wrapper.__doc__ = "\n\n".join(orig.__doc__.split("\n\n")[:1] + [f".. deprecated:: {since}\n {message}\n"]) + else: + raise ValueError(mode) + + if post_process: + wrapper = post_process(wrapper) + return wrapper + + +def deprecated(reason: str, version: str): + """Wrapper around `deprecated.sphinx.deprecated` to explicitly set the warning category.""" + return _deprecated(reason=reason, version=version, category=UserDeprecationWarning) diff --git a/lib/openeo/local/__init__.py b/lib/openeo/local/__init__.py new file mode 100644 index 000000000..bb84360b4 --- /dev/null +++ b/lib/openeo/local/__init__.py @@ -0,0 +1,3 @@ +from openeo.local.connection import LocalConnection + +__all__ = ["LocalConnection"] diff --git a/lib/openeo/local/collections.py b/lib/openeo/local/collections.py new file mode 100644 index 000000000..7e5e1b0f1 --- /dev/null +++ b/lib/openeo/local/collections.py @@ -0,0 +1,240 @@ +import logging +from pathlib import Path +from typing import List + +import rioxarray +import xarray as xr +from pyproj import Transformer + +_log = logging.getLogger(__name__) + + +def _get_dimension(dims: dict, candidates: List[str]): + for name in candidates: + if name in dims: + return name + error = f'Dimension matching one of the candidates {candidates} not found! The available ones are {dims}. Please rename the dimension accordingly and try again. This local collection will be skipped.' + raise Exception(error) + + +def _get_netcdf_zarr_metadata(file_path): + if '.zarr' in file_path.suffixes: + data = xr.open_dataset(file_path.as_posix(),chunks={},engine='zarr') + else: + data = xr.open_dataset(file_path.as_posix(),chunks={}) # Add decode_coords='all' if the crs as a band gives some issues + file_path = file_path.as_posix() + try: + t_dim = _get_dimension(data.dims, ['t', 'time', 'temporal', 'DATE']) + except Exception: + t_dim = None + try: + x_dim = _get_dimension(data.dims, ['x', 'X', 'lon', 'longitude']) + y_dim = _get_dimension(data.dims, ['y', 'Y', 'lat', 'latitude']) + except Exception as e: + _log.warning(e) + raise Exception(f'Error creating metadata for {file_path}') from e + metadata = {} + metadata['stac_version'] = '1.0.0-rc.2' + metadata['type'] = 'Collection' + metadata['id'] = file_path + data_attrs_lowercase = [x.lower() for x in data.attrs] + data_attrs_original = [x for x in data.attrs] + data_attrs = dict(zip(data_attrs_lowercase,data_attrs_original)) + if 'title' in data_attrs_lowercase: + metadata['title'] = data.attrs[data_attrs['title']] + else: + metadata['title'] = file_path + if 'description' in data_attrs_lowercase: + metadata['description'] = data.attrs[data_attrs['description']] + else: + metadata['description'] = '' + if 'license' in data_attrs_lowercase: + metadata['license'] = data.attrs[data_attrs['license']] + else: + metadata['license'] = '' + providers = [{'name':'', + 'roles':['producer'], + 'url':''}] + if 'providers' in data_attrs_lowercase: + providers[0]['name'] = data.attrs[data_attrs['providers']] + metadata['providers'] = providers + elif 'institution' in data_attrs_lowercase: + providers[0]['name'] = data.attrs[data_attrs['institution']] + metadata['providers'] = providers + else: + metadata['providers'] = providers + if 'links' in data_attrs_lowercase: + metadata['links'] = data.attrs[data_attrs['links']] + else: + metadata['links'] = '' + x_min = data[x_dim].min().item(0) + x_max = data[x_dim].max().item(0) + y_min = data[y_dim].min().item(0) + y_max = data[y_dim].max().item(0) + + crs_present = False + bands = list(data.data_vars) + if 'crs' in bands: + bands.remove('crs') + crs_present = True + extent = {} + if crs_present: + if "crs_wkt" in data.crs.attrs: + transformer = Transformer.from_crs(data.crs.attrs["crs_wkt"], "epsg:4326") + lat_min, lon_min = transformer.transform(x_min, y_min) + lat_max, lon_max = transformer.transform(x_max, y_max) + extent["spatial"] = {"bbox": [[lon_min, lat_min, lon_max, lat_max]]} + + if t_dim is not None: + t_min = str(data[t_dim].min().values) + t_max = str(data[t_dim].max().values) + extent['temporal'] = {'interval': [[t_min,t_max]]} + + metadata['extent'] = extent + + t_dimension = {} + if t_dim is not None: + t_dimension = {t_dim: {'type': 'temporal', 'extent':[t_min,t_max]}} + + x_dimension = {x_dim: {'type': 'spatial','axis':'x','extent':[x_min,x_max]}} + y_dimension = {y_dim: {'type': 'spatial','axis':'y','extent':[y_min,y_max]}} + if crs_present: + if 'crs_wkt' in data.crs.attrs: + x_dimension[x_dim]['reference_system'] = data.crs.attrs['crs_wkt'] + y_dimension[y_dim]['reference_system'] = data.crs.attrs['crs_wkt'] + + b_dimension = {} + if len(bands)>0: + b_dimension = {'bands': {'type': 'bands', 'values':bands}} + + metadata['cube:dimensions'] = {**t_dimension,**x_dimension,**y_dimension,**b_dimension} + + return metadata + + +def _get_geotiff_metadata(file_path): + data = rioxarray.open_rasterio(file_path.as_posix(),chunks={},band_as_variable=True) + file_path = file_path.as_posix() + try: + t_dim = _get_dimension(data.dims, ['t', 'time', 'temporal', 'DATE']) + except Exception: + t_dim = None + try: + x_dim = _get_dimension(data.dims, ['x', 'X', 'lon', 'longitude']) + y_dim = _get_dimension(data.dims, ['y', 'Y', 'lat', 'latitude']) + except Exception as e: + _log.warning(e) + raise Exception(f'Error creating metadata for {file_path}') from e + + metadata = {} + metadata['stac_version'] = '1.0.0-rc.2' + metadata['type'] = 'Collection' + metadata['id'] = file_path + data_attrs_lowercase = [x.lower() for x in data.attrs] + data_attrs_original = [x for x in data.attrs] + data_attrs = dict(zip(data_attrs_lowercase,data_attrs_original)) + if 'title' in data_attrs_lowercase: + metadata['title'] = data.attrs[data_attrs['title']] + else: + metadata['title'] = file_path + if 'description' in data_attrs_lowercase: + metadata['description'] = data.attrs[data_attrs['description']] + else: + metadata['description'] = '' + if 'license' in data_attrs_lowercase: + metadata['license'] = data.attrs[data_attrs['license']] + else: + metadata['license'] = '' + providers = [{'name':'', + 'roles':['producer'], + 'url':''}] + if 'providers' in data_attrs_lowercase: + providers[0]['name'] = data.attrs[data_attrs['providers']] + metadata['providers'] = providers + elif 'institution' in data_attrs_lowercase: + providers[0]['name'] = data.attrs[data_attrs['institution']] + metadata['providers'] = providers + else: + metadata['providers'] = providers + if 'links' in data_attrs_lowercase: + metadata['links'] = data.attrs[data_attrs['links']] + else: + metadata['links'] = '' + x_min = data[x_dim].min().item(0) + x_max = data[x_dim].max().item(0) + y_min = data[y_dim].min().item(0) + y_max = data[y_dim].max().item(0) + + crs_present = False + coords = list(data.coords) + if 'spatial_ref' in coords: + # bands.remove('crs') + crs_present = True + bands = [] + for d in data.data_vars: + data_attrs_lowercase = [x.lower() for x in data[d].attrs] + data_attrs_original = [x for x in data[d].attrs] + data_attrs = dict(zip(data_attrs_lowercase,data_attrs_original)) + if 'description' in data_attrs_lowercase: + bands.append(data[d].attrs[data_attrs['description']]) + else: + bands.append(d) + extent = {} + if crs_present: + if 'crs_wkt' in data.spatial_ref.attrs: + transformer = Transformer.from_crs(data.spatial_ref.attrs['crs_wkt'], 'epsg:4326') + lat_min,lon_min = transformer.transform(x_min,y_min) + lat_max,lon_max = transformer.transform(x_max,y_max) + extent['spatial'] = {'bbox': [[lon_min, lat_min, lon_max, lat_max]]} + + if t_dim is not None: + t_min = str(data[t_dim].min().values) + t_max = str(data[t_dim].max().values) + extent['temporal'] = {'interval': [[t_min,t_max]]} + + metadata['extent'] = extent + + t_dimension = {} + if t_dim is not None: + t_dimension = {t_dim: {'type': 'temporal', 'extent':[t_min,t_max]}} + + x_dimension = {x_dim: {'type': 'spatial','axis':'x','extent':[x_min,x_max]}} + y_dimension = {y_dim: {'type': 'spatial','axis':'y','extent':[y_min,y_max]}} + if crs_present: + if 'crs_wkt' in data.spatial_ref.attrs: + x_dimension[x_dim]['reference_system'] = data.spatial_ref.attrs['crs_wkt'] + y_dimension[y_dim]['reference_system'] = data.spatial_ref.attrs['crs_wkt'] + + b_dimension = {} + if len(bands)>0: + b_dimension = {'bands': {'type': 'bands', 'values':bands}} + + metadata['cube:dimensions'] = {**t_dimension,**x_dimension,**y_dimension,**b_dimension} + + return metadata + + +def _get_local_collections(local_collections_path): + if isinstance(local_collections_path,str): + local_collections_path = [local_collections_path] + local_collections_list = [] + for flds in local_collections_path: + local_collections_netcdf_zarr = [p for p in Path(flds).rglob('*') if p.suffix in ['.nc','.zarr']] + for local_file in local_collections_netcdf_zarr: + try: + metadata = _get_netcdf_zarr_metadata(local_file) + local_collections_list.append(metadata) + except Exception as e: + _log.error(e) + continue + local_collections_geotiffs = [p for p in Path(flds).rglob('*') if p.suffix in ['.tif','.tiff']] + for local_file in local_collections_geotiffs: + try: + metadata = _get_geotiff_metadata(local_file) + local_collections_list.append(metadata) + except Exception as e: + _log.error(e) + continue + local_collections_dict = {'collections':local_collections_list} + + return local_collections_dict diff --git a/lib/openeo/local/connection.py b/lib/openeo/local/connection.py new file mode 100644 index 000000000..e9ce0c3f0 --- /dev/null +++ b/lib/openeo/local/connection.py @@ -0,0 +1,275 @@ +import datetime +import logging +from pathlib import Path +from typing import Callable, Dict, List, Optional, Union + +import numpy as np +import xarray as xr +from openeo_pg_parser_networkx.graph import OpenEOProcessGraph +from openeo_pg_parser_networkx.pg_schema import BoundingBox, TemporalInterval +from openeo_processes_dask.process_implementations.cubes import load_stac + +from openeo.internal.graph_building import PGNode, as_flat_graph +from openeo.internal.jupyter import VisualDict, VisualList +from openeo.local.collections import ( + _get_geotiff_metadata, + _get_local_collections, + _get_netcdf_zarr_metadata, +) +from openeo.local.processing import PROCESS_REGISTRY +from openeo.metadata import ( + Band, + BandDimension, + CollectionMetadata, + SpatialDimension, + TemporalDimension, +) +from openeo.rest.datacube import DataCube + +_log = logging.getLogger(__name__) + + +class LocalConnection(): + """ + Connection to no backend, for local processing. + """ + + def __init__(self,local_collections_path: Union[str,List]): + """ + Constructor of LocalConnection. + + :param local_collections_path: String or list of strings, path to the folder(s) with + the local collections in netCDF, geoTIFF or ZARR. + """ + self.local_collections_path = local_collections_path + + def list_collections(self) -> List[dict]: + """ + List basic metadata of all collections provided in the local collections folder. + + .. caution:: + :return: list of dictionaries with basic collection metadata. + """ + data = _get_local_collections(self.local_collections_path)["collections"] + return VisualList("collections", data=data) + + def describe_collection(self, collection_id: str) -> dict: + """ + Get full collection metadata for given collection id. + + .. seealso:: + + :py:meth:`~openeo.rest.connection.Connection.list_collection_ids` + to list all collection ids provided by the back-end. + + :param collection_id: collection id + :return: collection metadata. + """ + local_collection = Path(collection_id) + if '.nc' in local_collection.suffixes or '.zarr' in local_collection.suffixes: + data = _get_netcdf_zarr_metadata(local_collection) + elif '.tif' in local_collection.suffixes or '.tiff' in local_collection.suffixes: + data = _get_geotiff_metadata(local_collection) + return VisualDict("collection", data=data) + + def collection_metadata(self, name) -> CollectionMetadata: + # TODO: duplication with `Connection.describe_collection`: deprecate one or the other? + return CollectionMetadata(metadata=self.describe_collection(name)) + + def load_collection( + self, + collection_id: str, + spatial_extent: Optional[Dict[str, float]] = None, + temporal_extent: Optional[List[Union[str, datetime.datetime, datetime.date]]] = None, + bands: Optional[List[str]] = None, + properties: Optional[Dict[str, Union[str, PGNode, Callable]]] = None, + fetch_metadata=True, + ) -> DataCube: + """ + Load a DataCube by collection id. + + :param collection_id: image collection identifier + :param spatial_extent: limit data to specified bounding box or polygons + :param temporal_extent: limit data to specified temporal interval + :param bands: only add the specified bands + :param properties: limit data by metadata property predicates + :return: a datacube containing the requested data + """ + return DataCube.load_collection( + collection_id=collection_id, connection=self, + spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands, properties=properties, + fetch_metadata=fetch_metadata, + ) + + def datacube_from_process(self, process_id: str, namespace: Optional[str] = None, **kwargs) -> DataCube: + """ + Load a data cube from a (custom) process. + + :param process_id: The process id. + :param namespace: optional: process namespace + :param kwargs: The arguments of the custom process + :return: A :py:class:`DataCube`, without valid metadata, as the client is not aware of this custom process. + """ + graph = PGNode(process_id, namespace=namespace, arguments=kwargs) + return DataCube(graph=graph, connection=self) + + def load_stac( + self, + url: str, + spatial_extent: Optional[Dict[str, float]] = None, + temporal_extent: Optional[List[Union[str, datetime.datetime, datetime.date]]] = None, + bands: Optional[List[str]] = None, + properties: Optional[dict] = None, + ) -> DataCube: + """ + Loads data from a static STAC catalog or a STAC API Collection and returns the data as a processable :py:class:`DataCube`. + A batch job result can be loaded by providing a reference to it. + + If supported by the underlying metadata and file format, the data that is added to the data cube can be + restricted with the parameters ``spatial_extent``, ``temporal_extent`` and ``bands``. + If no data is available for the given extents, a ``NoDataAvailable`` error is thrown. + + Remarks: + + * 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``. + * 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 values should be processed only after the data has been limited to the required extent + and as a consequence also to a manageable size. + + + :param url: The URL to a static STAC catalog (STAC Item, STAC Collection, or STAC Catalog) + or a specific STAC API Collection that allows to filter items and to download assets. + This includes batch job results, which itself are compliant to STAC. + For external URLs, authentication details such as API keys or tokens may need to be included in the URL. + + Batch job results can be specified in two ways: + + - For Batch job results at the same back-end, a URL pointing to the corresponding batch job results + endpoint should be provided. The URL usually ends with ``/jobs/{id}/results`` and ``{id}`` + is the corresponding batch job ID. + - For external results, a signed URL must be provided. Not all back-ends support signed URLs, + which are provided as a link with the link relation `canonical` in the batch job result metadata. + :param spatial_extent: + Limits the data to load to the specified bounding box or polygons. + + For raster data, the process loads the pixel into the data cube if the point at the pixel center intersects + with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). + + For vector data, the process loads the geometry into the data cube if the geometry is fully within the + bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). + Empty geometries may only be in the data cube if no spatial extent has been provided. + + The GeoJSON can be one of the following feature types: + + * A ``Polygon`` or ``MultiPolygon`` geometry, + * a ``Feature`` with a ``Polygon`` or ``MultiPolygon`` geometry, or + * a ``FeatureCollection`` containing at least one ``Feature`` with ``Polygon`` or ``MultiPolygon`` geometries. + + Set this parameter to ``None`` 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. + + :param temporal_extent: + Limits the data to load 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: + + 1. The first element is the start of the temporal interval. + The specified instance in time is **included** in the interval. + 2. The second element is the end of the temporal interval. + The specified instance in time is **excluded** from the interval. + + The second element must always be greater/later than the first element. + Otherwise, a `TemporalExtentEmpty` exception is thrown. + + Also supports open intervals by setting one of the boundaries to ``None``, but never both. + + Set this parameter to ``None`` 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. + + :param bands: + 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`. + + Either 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. + + The 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. + + It is recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded data. + + :param properties: + Limits the data by metadata properties to include only data in the data cube which + all given conditions return ``True`` for (AND operation). + + Specify key-value-pairs with the key being the name of the metadata property, + which can be retrieved with the openEO Data Discovery for Collections. + The value must be a condition (user-defined process) to be evaluated against a STAC API. + This parameter is not supported for static STAC. + + .. versionadded:: 0.21.0 + """ + arguments = {"url": url} + # TODO: more normalization/validation of extent/band parameters and `properties` + if spatial_extent is not None: + arguments["spatial_extent"] = spatial_extent + if temporal_extent is not None: + arguments["temporal_extent"] = DataCube._get_temporal_extent(extent=temporal_extent) + if bands is not None: + arguments["bands"] = bands + if properties is not None: + arguments["properties"] = properties + cube = self.datacube_from_process(process_id="load_stac", **arguments) + # detect actual metadata from URL + # run load_stac to get the datacube metadata + if spatial_extent is not None: + arguments["spatial_extent"] = BoundingBox.parse_obj(spatial_extent) + if temporal_extent is not None: + arguments["temporal_extent"] = TemporalInterval.parse_obj(temporal_extent) + xarray_cube = load_stac(**arguments) + attrs = xarray_cube.attrs + for at in attrs: + # allowed types: str, Number, ndarray, number, list, tuple + if not isinstance(attrs[at], (int, float, str, np.ndarray, list, tuple)): + attrs[at] = str(attrs[at]) + metadata = CollectionMetadata( + attrs, + dimensions=[ + SpatialDimension(name=xarray_cube.openeo.x_dim, extent=[]), + SpatialDimension(name=xarray_cube.openeo.y_dim, extent=[]), + TemporalDimension(name=xarray_cube.openeo.temporal_dims[0], extent=[]), + BandDimension( + name=xarray_cube.openeo.band_dims[0], + bands=[Band(name=x) for x in xarray_cube[xarray_cube.openeo.band_dims[0]].values], + ), + ], + ) + cube.metadata = metadata + return cube + + def list_udf_runtimes(self) -> dict: + """ + Loads all available UDF runtimes. + + :return: All available UDF runtimes + """ + runtimes = { + "Python": {"title": "Python 3", "type": "language", "versions": {"3": {"libraries": {}}}, "default": "3"} + } + return VisualDict("udf-runtimes", data=runtimes) + + def execute(self, process_graph: Union[dict, str, Path], validate: Optional[bool] = None) -> xr.DataArray: + """ + Execute locally the process graph and return the result as an xarray.DataArray. + + :param process_graph: (flat) dict representing a process graph, or process graph as raw JSON string, + :return: a datacube containing the requested data + """ + process_graph = as_flat_graph(process_graph) + return OpenEOProcessGraph(process_graph).to_callable(PROCESS_REGISTRY)() diff --git a/lib/openeo/local/processing.py b/lib/openeo/local/processing.py new file mode 100644 index 000000000..4adce909d --- /dev/null +++ b/lib/openeo/local/processing.py @@ -0,0 +1,82 @@ +import inspect +import logging +from pathlib import Path + +import openeo_processes_dask.process_implementations +import openeo_processes_dask.specs +import rasterio +import rioxarray +import xarray as xr +from openeo_pg_parser_networkx import ProcessRegistry +from openeo_pg_parser_networkx.process_registry import Process +from openeo_processes_dask.process_implementations.core import process +from openeo_processes_dask.process_implementations.data_model import RasterCube + +_log = logging.getLogger(__name__) + + +def init_process_registry(): + process_registry = ProcessRegistry(wrap_funcs=[process]) + + # Import these pre-defined processes from openeo_processes_dask and register them into registry + processes_from_module = [ + func + for _, func in inspect.getmembers( + openeo_processes_dask.process_implementations, + inspect.isfunction, + ) + ] + + specs = {} + for func in processes_from_module: + try: + specs[func.__name__] = getattr(openeo_processes_dask.specs, func.__name__) + except Exception: + continue + + for func in processes_from_module: + try: + process_registry[func.__name__] = Process( + spec=specs[func.__name__], implementation=func + ) + except Exception: + continue + return process_registry + + +PROCESS_REGISTRY = init_process_registry() + + +def load_local_collection(*args, **kwargs): + pretty_args = {k: repr(v)[:80] for k, v in kwargs.items()} + _log.info("Running process load_collection") + _log.debug( + f"Running process load_collection with resolved parameters: {pretty_args}" + ) + collection = Path(kwargs['id']) + if '.zarr' in collection.suffixes: + data = xr.open_dataset(kwargs['id'],chunks={},engine='zarr') + elif '.nc' in collection.suffixes: + data = xr.open_dataset(kwargs['id'],chunks={},decode_coords='all') # Add decode_coords='all' if the crs as a band gives some issues + crs = None + if 'crs' in data.coords: + if 'spatial_ref' in data.crs.attrs: + crs = data.crs.attrs['spatial_ref'] + elif 'crs_wkt' in data.crs.attrs: + crs = data.crs.attrs['crs_wkt'] + data = data.to_array(dim='bands') + if crs is not None: + data.rio.write_crs(crs,inplace=True) + elif '.tiff' in collection.suffixes or '.tif' in collection.suffixes: + data = rioxarray.open_rasterio(kwargs['id'],chunks={},band_as_variable=True) + for d in data.data_vars: + descriptions = [v for k, v in data[d].attrs.items() if k.lower() == "description"] + if descriptions: + data = data.rename({d: descriptions[0]}) + data = data.to_array(dim='bands') + return data + +PROCESS_REGISTRY["load_collection"] = Process( + spec=openeo_processes_dask.specs.load_collection, + implementation=load_local_collection, +) diff --git a/lib/openeo/metadata.py b/lib/openeo/metadata.py new file mode 100644 index 000000000..84367de61 --- /dev/null +++ b/lib/openeo/metadata.py @@ -0,0 +1,488 @@ +from __future__ import annotations + +import logging +import warnings +from typing import Any, Callable, List, NamedTuple, Optional, Tuple, Union + +from openeo.internal.jupyter import render_component +from openeo.util import deep_get + +_log = logging.getLogger(__name__) + + +class MetadataException(Exception): + pass + + +class DimensionAlreadyExistsException(MetadataException): + pass + + +class Dimension: + """Base class for dimensions.""" + + def __init__(self, type: str, name: str): + self.type = type + self.name = name + + def __repr__(self): + return "{c}({f})".format( + c=self.__class__.__name__, + f=", ".join("{k!s}={v!r}".format(k=k, v=v) for (k, v) in self.__dict__.items()) + ) + + def __eq__(self, other): + return self.__class__ == other.__class__ and self.__dict__ == other.__dict__ + + def rename(self, name) -> Dimension: + """Create new dimension with new name.""" + return Dimension(type=self.type, name=name) + + def rename_labels(self, target, source) -> Dimension: + """ + Rename labels, if the type of dimension allows it. + + :param target: List of target labels + :param source: Source labels, or empty list + :return: A new dimension with modified labels, or the same if no change is applied. + """ + # In general, we don't have/manage label info here, so do nothing. + return Dimension(type=self.type, name=self.name) + + +class SpatialDimension(Dimension): + DEFAULT_CRS = 4326 + + def __init__( + self, + name: str, + extent: Union[Tuple[float, float], List[float]], + crs: Union[str, int, dict] = DEFAULT_CRS, + step=None, + ): + """ + + @param name: + @param extent: + @param crs: + @param step: The space between the values. Use null for irregularly spaced steps. + """ + super().__init__(type="spatial", name=name) + self.extent = extent + self.crs = crs + self.step = step + + def rename(self, name) -> Dimension: + return SpatialDimension(name=name, extent=self.extent, crs=self.crs, step=self.step) + + +class TemporalDimension(Dimension): + def __init__(self, name: str, extent: Union[Tuple[str, str], List[str]]): + super().__init__(type="temporal", name=name) + self.extent = extent + + def rename(self, name) -> Dimension: + return TemporalDimension(name=name, extent=self.extent) + + +class Band(NamedTuple): + """ + Simple container class for band metadata. + Based on https://github.com/stac-extensions/eo#band-object + """ + + name: str + common_name: Optional[str] = None + # wavelength in micrometer + wavelength_um: Optional[float] = None + aliases: Optional[List[str]] = None + # "openeo:gsd" field (https://github.com/Open-EO/openeo-stac-extensions#GSD-Object) + gsd: Optional[dict] = None + + +class BandDimension(Dimension): + def __init__(self, name: str, bands: List[Band]): + super().__init__(type="bands", name=name) + self.bands = bands + + @property + def band_names(self) -> List[str]: + return [b.name for b in self.bands] + + @property + def band_aliases(self) -> List[List[str]]: + return [b.aliases for b in self.bands] + + @property + def common_names(self) -> List[str]: + return [b.common_name for b in self.bands] + + def band_index(self, band: Union[int, str]) -> int: + """ + Resolve a given band (common) name/index to band index + + :param band: band name, common name or index + :return int: band index + """ + band_names = self.band_names + if isinstance(band, int) and 0 <= band < len(band_names): + return band + elif isinstance(band, str): + common_names = self.common_names + # First try common names if possible + if band in common_names: + return common_names.index(band) + if band in band_names: + return band_names.index(band) + # Check band aliases to still support old band names + aliases = [True if aliases and band in aliases else False for aliases in self.band_aliases] + if any(aliases): + return aliases.index(True) + raise ValueError("Invalid band name/index {b!r}. Valid names: {n!r}".format(b=band, n=band_names)) + + def band_name(self, band: Union[str, int], allow_common=True) -> str: + """Resolve (common) name or index to a valid (common) name""" + if isinstance(band, str): + if band in self.band_names: + return band + elif band in self.common_names: + if allow_common: + return band + else: + return self.band_names[self.common_names.index(band)] + elif any([True if aliases and band in aliases else False for aliases in self.band_aliases]): + return self.band_names[self.band_index(band)] + elif isinstance(band, int) and 0 <= band < len(self.bands): + return self.band_names[band] + raise ValueError("Invalid band name/index {b!r}. Valid names: {n!r}".format(b=band, n=self.band_names)) + + def filter_bands(self, bands: List[Union[int, str]]) -> BandDimension: + """ + Construct new BandDimension with subset of bands, + based on given band indices or (common) names + """ + return BandDimension( + name=self.name, + bands=[self.bands[self.band_index(b)] for b in bands] + ) + + def append_band(self, band: Band) -> BandDimension: + """Create new BandDimension with appended band.""" + if band.name in self.band_names: + raise ValueError("Duplicate band {b!r}".format(b=band)) + + return BandDimension( + name=self.name, + bands=self.bands + [band] + ) + + def rename_labels(self, target, source) -> Dimension: + if source: + if len(target) != len(source): + raise ValueError( + "In rename_labels, `target` and `source` should have same number of labels, " + "but got: `target` {t} and `source` {s}".format(t=target, s=source) + ) + new_bands = self.bands.copy() + for old_name, new_name in zip(source, target): + band_index = self.band_index(old_name) + the_band = new_bands[band_index] + new_bands[band_index] = Band( + name=new_name, + common_name=the_band.common_name, + wavelength_um=the_band.wavelength_um, + aliases=the_band.aliases, + gsd=the_band.gsd, + ) + else: + new_bands = [Band(name=n) for n in target] + return BandDimension(name=self.name, bands=new_bands) + + +class CollectionMetadata: + """ + Wrapper for Image Collection metadata. + + Simplifies getting values from deeply nested mappings, + allows additional parsing and normalizing compatibility issues. + + Metadata is expected to follow format defined by + https://openeo.org/documentation/1.0/developers/api/reference.html#operation/describe-collection + (with partial support for older versions) + + """ + + # TODO: "CollectionMetadata" is also used as "cube metadata" where the link to original collection + # might be lost (if any). Better separation between rich EO raster collection metadata and + # essential cube metadata? E.g.: also thing of vector cubes. + + def __init__(self, metadata: dict, dimensions: List[Dimension] = None): + # Original collection metadata (actual cube metadata might be altered through processes) + self._orig_metadata = metadata + + if dimensions == None: + self._dimensions = self._parse_dimensions(self._orig_metadata) + else: + self._dimensions = dimensions + self._band_dimension = None + self._temporal_dimension = None + for dim in self._dimensions: + # TODO: here we blindly pick last bands or temporal dimension if multiple. Let user choose? + if dim.type == "bands": + self._band_dimension = dim + if dim.type == "temporal": + self._temporal_dimension = dim + + def __eq__(self, o: Any) -> bool: + return isinstance(o, CollectionMetadata) and self._dimensions == o._dimensions + + def _clone_and_update( + self, metadata: dict = None, dimensions: List[Dimension] = None, **kwargs + ) -> CollectionMetadata: + """Create a new instance (of same class) with copied/updated fields.""" + cls = type(self) + if dimensions == None: + dimensions = self._dimensions + return cls(metadata=metadata or self._orig_metadata, dimensions=dimensions, **kwargs) + + @classmethod + def _parse_dimensions(cls, spec: dict, complain: Callable[[str], None] = warnings.warn) -> List[Dimension]: + """ + Extract data cube dimension metadata from STAC-like description of a collection. + + Dimension metadata comes from different places in spec: + - 'cube:dimensions' has dimension names (e.g. 'x', 'y', 't'), dimension extent info + and band names for band dimensions + - 'eo:bands' has more detailed band information like "common" name and wavelength info + + This helper tries to normalize/combine these sources. + + :param spec: STAC like collection metadata dict + :param complain: handler for warnings + :return list: list of `Dimension` objects + + """ + + # Dimension info is in `cube:dimensions` (or 0.4-style `properties/cube:dimensions`) + cube_dimensions = ( + deep_get(spec, "cube:dimensions", default=None) + or deep_get(spec, "properties", "cube:dimensions", default=None) + or {} + ) + if not cube_dimensions: + complain("No cube:dimensions metadata") + dimensions = [] + for name, info in cube_dimensions.items(): + dim_type = info.get("type") + if dim_type == "spatial": + dimensions.append( + SpatialDimension( + name=name, + extent=info.get("extent"), + crs=info.get("reference_system", SpatialDimension.DEFAULT_CRS), + step=info.get("step", None), + ) + ) + elif dim_type == "temporal": + dimensions.append(TemporalDimension(name=name, extent=info.get("extent"))) + elif dim_type == "bands": + bands = [Band(name=b) for b in info.get("values", [])] + if not bands: + complain("No band names in dimension {d!r}".format(d=name)) + dimensions.append(BandDimension(name=name, bands=bands)) + else: + complain("Unknown dimension type {t!r}".format(t=dim_type)) + dimensions.append(Dimension(name=name, type=dim_type)) + + # Detailed band information: `summaries/[eo|raster]:bands` (and 0.4 style `properties/eo:bands`) + eo_bands = ( + deep_get(spec, "summaries", "eo:bands", default=None) + or deep_get(spec, "summaries", "raster:bands", default=None) + or deep_get(spec, "properties", "eo:bands", default=None) + ) + if eo_bands: + # center_wavelength is in micrometer according to spec + bands_detailed = [ + Band( + name=b["name"], + common_name=b.get("common_name"), + wavelength_um=b.get("center_wavelength"), + aliases=b.get("aliases"), + gsd=b.get("openeo:gsd"), + ) + for b in eo_bands + ] + # Update band dimension with more detailed info + band_dimensions = [d for d in dimensions if d.type == "bands"] + if len(band_dimensions) == 1: + dim = band_dimensions[0] + # Update band values from 'cube:dimensions' with more detailed 'eo:bands' info + eo_band_names = [b.name for b in bands_detailed] + cube_dimension_band_names = [b.name for b in dim.bands] + if eo_band_names == cube_dimension_band_names: + dim.bands = bands_detailed + else: + complain("Band name mismatch: {a} != {b}".format(a=cube_dimension_band_names, b=eo_band_names)) + elif len(band_dimensions) == 0: + if len(dimensions) == 0: + complain("Assuming name 'bands' for anonymous band dimension.") + dimensions.append(BandDimension(name="bands", bands=bands_detailed)) + else: + complain("No 'bands' dimension in 'cube:dimensions' while having 'eo:bands' or 'raster:bands'") + else: + complain("Multiple dimensions of type 'bands'") + + return dimensions + + def get(self, *args, default=None): + return deep_get(self._orig_metadata, *args, default=default) + + @property + def extent(self) -> dict: + # TODO: is this currently used and relevant? + # TODO: check against extent metadata in dimensions + return self._orig_metadata.get("extent") + + def dimension_names(self) -> List[str]: + return list(d.name for d in self._dimensions) + + def assert_valid_dimension(self, dimension: str) -> str: + """Make sure given dimension name is valid.""" + names = self.dimension_names() + if dimension not in names: + raise ValueError(f"Invalid dimension {dimension!r}. Should be one of {names}") + return dimension + + def has_band_dimension(self) -> bool: + return isinstance(self._band_dimension, BandDimension) + + @property + def band_dimension(self) -> BandDimension: + """Dimension corresponding to spectral/logic/thematic "bands".""" + if not self.has_band_dimension(): + raise MetadataException("No band dimension") + return self._band_dimension + + def has_temporal_dimension(self) -> bool: + return isinstance(self._temporal_dimension, TemporalDimension) + + @property + def temporal_dimension(self) -> TemporalDimension: + if not self.has_temporal_dimension(): + raise MetadataException("No temporal dimension") + return self._temporal_dimension + + @property + def spatial_dimensions(self) -> List[SpatialDimension]: + return [d for d in self._dimensions if isinstance(d, SpatialDimension)] + + @property + def bands(self) -> List[Band]: + """Get band metadata as list of Band metadata tuples""" + return self.band_dimension.bands + + @property + def band_names(self) -> List[str]: + """Get band names of band dimension""" + return self.band_dimension.band_names + + @property + def band_common_names(self) -> List[str]: + return self.band_dimension.common_names + + def get_band_index(self, band: Union[int, str]) -> int: + # TODO: eliminate this shortcut for smaller API surface + return self.band_dimension.band_index(band) + + def filter_bands(self, band_names: List[Union[int, str]]) -> CollectionMetadata: + """ + Create new `CollectionMetadata` with filtered band dimension + :param band_names: list of band names/indices to keep + :return: + """ + assert self.band_dimension + return self._clone_and_update(dimensions=[ + d.filter_bands(band_names) if isinstance(d, BandDimension) else d + for d in self._dimensions + ]) + + def append_band(self, band: Band) -> CollectionMetadata: + """ + Create new `CollectionMetadata` with given band added to band dimension. + """ + assert self.band_dimension + return self._clone_and_update(dimensions=[ + d.append_band(band) if isinstance(d, BandDimension) else d + for d in self._dimensions + ]) + + def rename_labels(self, dimension: str, target: list, source: list = None) -> CollectionMetadata: + """ + Renames the labels of the specified dimension from source to target. + + :param dimension: Dimension name + :param target: The new names for the labels. + :param source: The names of the labels as they are currently in the data cube. + + :return: Updated metadata + """ + self.assert_valid_dimension(dimension) + loc = self.dimension_names().index(dimension) + new_dimensions = self._dimensions.copy() + new_dimensions[loc] = new_dimensions[loc].rename_labels(target, source) + + return self._clone_and_update(dimensions=new_dimensions) + + def rename_dimension(self, source: str, target: str) -> CollectionMetadata: + """ + Rename source dimension into target, preserving other properties + """ + self.assert_valid_dimension(source) + loc = self.dimension_names().index(source) + new_dimensions = self._dimensions.copy() + new_dimensions[loc] = new_dimensions[loc].rename(target) + + return self._clone_and_update(dimensions=new_dimensions) + + def reduce_dimension(self, dimension_name: str) -> CollectionMetadata: + """Create new metadata object by collapsing/reducing a dimension.""" + # TODO: option to keep reduced dimension (with a single value)? + # TODO: rename argument to `name` for more internal consistency + # TODO: merge with drop_dimension (which does the same). + self.assert_valid_dimension(dimension_name) + loc = self.dimension_names().index(dimension_name) + dimensions = self._dimensions[:loc] + self._dimensions[loc + 1:] + return self._clone_and_update(dimensions=dimensions) + + def reduce_spatial(self) -> CollectionMetadata: + """Create new metadata object by reducing the spatial dimensions.""" + dimensions = [d for d in self._dimensions if not isinstance(d, SpatialDimension)] + return self._clone_and_update(dimensions=dimensions) + + def add_dimension(self, name: str, label: Union[str, float], type: str = None) -> CollectionMetadata: + """Create new metadata object with added dimension""" + if any(d.name == name for d in self._dimensions): + raise DimensionAlreadyExistsException(f"Dimension with name {name!r} already exists") + if type == "bands": + dim = BandDimension(name=name, bands=[Band(name=label)]) + elif type == "spatial": + dim = SpatialDimension(name=name, extent=[label, label]) + elif type == "temporal": + dim = TemporalDimension(name=name, extent=[label, label]) + else: + dim = Dimension(type=type or "other", name=name) + return self._clone_and_update(dimensions=self._dimensions + [dim]) + + def drop_dimension(self, name: str = None) -> CollectionMetadata: + """Drop dimension with given name""" + dimension_names = self.dimension_names() + if name not in dimension_names: + raise ValueError("No dimension named {n!r} (valid names: {ns!r})".format(n=name, ns=dimension_names)) + return self._clone_and_update(dimensions=[d for d in self._dimensions if not d.name == name]) + + def _repr_html_(self): + return render_component("collection", data=self._orig_metadata) + + def __str__(self) -> str: + bands = self.band_names if self.has_band_dimension() else "no bands dimension" + return f"CollectionMetadata({self.extent} - {bands} - {self.dimension_names()})" diff --git a/lib/openeo/processes.py b/lib/openeo/processes.py new file mode 100644 index 000000000..b184fffa7 --- /dev/null +++ b/lib/openeo/processes.py @@ -0,0 +1,5325 @@ + +# Do not edit this file directly. +# It is automatically generated. +# Used command line arguments: +# openeo/internal/processes/generator.py specs/openeo-processes specs/openeo-processes/proposals --output openeo/processes.py +# Generated on 2023-09-08 + +from __future__ import annotations + +import builtins + +from openeo.internal.processes.builder import ProcessBuilderBase, UNSET +from openeo.internal.documentation import openeo_process +from openeo.rest._datacube import build_child_callback + + +class ProcessBuilder(ProcessBuilderBase): + """ + .. include:: api-processbuilder.rst + """ + + _ITERATION_LIMIT = 100 + + @openeo_process(process_id="add", mode="operator") + def __add__(self, other) -> ProcessBuilder: + return self.add(other) + + @openeo_process(process_id="add", mode="operator") + def __radd__(self, other) -> ProcessBuilder: + return add(other, self) + + @openeo_process(process_id="subtract", mode="operator") + def __sub__(self, other) -> ProcessBuilder: + return self.subtract(other) + + @openeo_process(process_id="subtract", mode="operator") + def __rsub__(self, other) -> ProcessBuilder: + return subtract(other, self) + + @openeo_process(process_id="multiply", mode="operator") + def __mul__(self, other) -> ProcessBuilder: + return self.multiply(other) + + @openeo_process(process_id="multiply", mode="operator") + def __rmul__(self, other) -> ProcessBuilder: + return multiply(other, self) + + @openeo_process(process_id="divide", mode="operator") + def __truediv__(self, other) -> ProcessBuilder: + return self.divide(other) + + @openeo_process(process_id="divide", mode="operator") + def __rtruediv__(self, other) -> ProcessBuilder: + return divide(other, self) + + @openeo_process(process_id="multiply", mode="operator") + def __neg__(self) -> ProcessBuilder: + return self.multiply(-1) + + @openeo_process(process_id="power", mode="operator") + def __pow__(self, other) -> ProcessBuilder: + return self.power(other) + + @openeo_process(process_id="array_element", mode="operator") + def __getitem__(self, key) -> ProcessBuilder: + if isinstance(key, builtins.int): + if key > self._ITERATION_LIMIT: + raise RuntimeError( + "Exceeded ProcessBuilder iteration limit. " + "Are you mistakenly using a Python builtin like `sum()` or `all()` in a callback " + "instead of the appropriate helpers from the `openeo.processes` module?" + ) + return self.array_element(index=key) + else: + return self.array_element(label=key) + + @openeo_process(process_id="eq", mode="operator") + def __eq__(self, other) -> ProcessBuilder: + return eq(self, other) + + @openeo_process(process_id="neq", mode="operator") + def __ne__(self, other) -> ProcessBuilder: + return neq(self, other) + + @openeo_process(process_id="lt", mode="operator") + def __lt__(self, other) -> ProcessBuilder: + return lt(self, other) + + @openeo_process(process_id="lte", mode="operator") + def __le__(self, other) -> ProcessBuilder: + return lte(self, other) + + @openeo_process(process_id="ge", mode="operator") + def __ge__(self, other) -> ProcessBuilder: + return gte(self, other) + + @openeo_process(process_id="gt", mode="operator") + def __gt__(self, other) -> ProcessBuilder: + return gt(self, other) + + @openeo_process + def absolute(self) -> ProcessBuilder: + """ + Absolute value + + :param self: A number. + + :return: The computed absolute value. + """ + return absolute(x=self) + + @openeo_process + def add(self, y) -> ProcessBuilder: + """ + Addition of two numbers + + :param self: The first summand. + :param y: The second summand. + + :return: The computed sum of the two numbers. + """ + return add(x=self, y=y) + + @openeo_process + def add_dimension(self, name, label, type=UNSET) -> ProcessBuilder: + """ + Add a new dimension + + :param self: A data cube to add the dimension to. + :param name: Name for the dimension. + :param label: A dimension label. + :param type: The type of dimension, defaults to `other`. + + :return: The data cube with a newly added dimension. The new dimension has exactly one dimension label. + All other dimensions remain unchanged. + """ + return add_dimension(data=self, name=name, label=label, type=type) + + @openeo_process + def aggregate_spatial(self, geometries, reducer, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for geometries + + :param self: A raster data cube. The 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. 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. + :param geometries: Geometries as GeoJSON on which the aggregation will be based. Vector properties are + preserved for vector data cubes and all GeoJSON Features. One 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. - + 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). - For + **points**, the process considers the closest pixel center. - For **lines** (line strings), the process + considers all the pixels whose centers are closest to at least one point on the line. Thus, pixels may + be part of multiple geometries and be part of multiple aggregations. To 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`). + :param reducer: A reducer to be applied on all values of each geometry. 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. + :param target_dimension: The name of a new dimensions that is used to store the results. A new + dimension will be created with the given name and type `other` (see ``add_dimension()``). Defaults to + the dimension name `result`. Fails with a `TargetDimensionExists` exception if a dimension with the + specified name exists. + :param context: Additional data to be passed to the reducer. + + :return: A vector data cube with the computed results and restricted to the bounds of the geometries. + The computed value is used for the dimension with the name that was specified in the parameter + `target_dimension`. The 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`. + """ + return aggregate_spatial( + data=self, + geometries=geometries, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + target_dimension=target_dimension, + context=context + ) + + @openeo_process + def aggregate_spatial_window(self, reducer, size, boundary=UNSET, align=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for rectangular windows + + :param self: 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. + :param reducer: 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. + :param size: Window size in pixels along the horizontal spatial dimensions. The first value + corresponds to the `x` axis, the second value corresponds to the `y` axis. + :param boundary: 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: - `pad` (default): pad the data cube + with the no-data value `null` to fit the required window size. - `trim`: trim the data cube to fit the + required window size. Set the parameter `align` to specifies to which corner the data is aligned to. + :param align: 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. + :param context: Additional data to be passed to the reducer. + + :return: A data cube with the newly computed values and the same dimensions. The 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. The + 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. + """ + return aggregate_spatial_window( + data=self, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + size=size, + boundary=boundary, + align=align, + context=context + ) + + @openeo_process + def aggregate_temporal(self, intervals, reducer, labels=UNSET, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations + + :param self: A data cube. + :param intervals: Left-closed temporal intervals, which are allowed to overlap. Each temporal interval + in the array has exactly two elements: 1. The first element is the start of the temporal interval. The + specified instance in time is **included** in the interval. 2. The second element is the end of the + temporal interval. The specified instance in time is **excluded** from the interval. The 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. + :param reducer: 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. + :param labels: Distinct labels for the intervals, which can contain dates and/or times. Is only + required to be specified if the values for the start of the temporal intervals are not distinct and + thus the default labels would not be unique. The number of labels and the number of groups need to be + equal. + :param dimension: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return aggregate_temporal( + data=self, + intervals=intervals, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + labels=labels, + dimension=dimension, + context=context + ) + + @openeo_process + def aggregate_temporal_period(self, period, reducer, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations based on calendar hierarchies + + :param self: The source data cube. + :param period: The time intervals to aggregate. The following pre-defined values are available: * + `hour`: Hour of the day * `day`: Day of the year * `week`: Week of the year * `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. * `month`: Month of the year * `season`: Three month periods of the calendar seasons (December - + February, March - May, June - August, September - November). * `tropical-season`: Six month periods of + the tropical seasons (November - April, May - October). * `year`: Proleptic years * `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. * `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. + :param reducer: 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. + :param dimension: 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 source 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. + :param context: Additional data to be passed to the reducer. + + :return: 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): * `hour`: `YYYY-MM- + DD-00` - `YYYY-MM-DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - `YYYY-52` * `dekad`: + `YYYY-00` - `YYYY-36` * `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` (December - February), + `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - November). * `tropical- + season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October). * `year`: `YYYY` * `decade`: + `YYY0` * `decade-ad`: `YYY1` The dimension labels in the new data cube are complete for the whole + extent of the source data cube. For example, if `period` is set to `day` and the source data cube has + two dimension labels at the beginning of the year (`2020-01-01`) and the end of a year (`2020-12-31`), + the process returns a data cube with 365 dimension labels (`2020-001`, `2020-002`, ..., `2020-365`). In + contrast, if `period` is set to `day` and the source data cube has just one dimension label + `2020-01-05`, the process returns a data cube with just a single dimension label (`2020-005`). + """ + return aggregate_temporal_period( + data=self, + period=period, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + ) + + @openeo_process + def all(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Are all of the values true? + + :param self: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return all(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def and_(self, y) -> ProcessBuilder: + """ + Logical AND + + :param self: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical AND. + """ + return and_(x=self, y=y) + + @openeo_process + def anomaly(self, normals, period) -> ProcessBuilder: + """ + Compute anomalies + + :param self: A data cube with exactly one temporal dimension and the following dimension labels for the + given period (`YYYY` = four-digit year, `MM` = two-digit month, `DD` two-digit day of month): * + `hour`: `YYYY-MM-DD-00` - `YYYY-MM-DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - + `YYYY-52` * `dekad`: `YYYY-00` - `YYYY-36` * `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` + (December - February), `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - + November). * `tropical-season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October). * + `year`: `YYYY` * `decade`: `YYY0` * `decade-ad`: `YYY1` * `single-period` / `climatology-period`: Any + ``aggregate_temporal_period()`` can compute such a data cube. + :param normals: A data cube with normals, e.g. daily, monthly or yearly values computed from a process + such as ``climatological_normal()``. Must contain exactly one temporal dimension with the following + dimension labels for the given period: * `hour`: `00` - `23` * `day`: `001` - `365` * `week`: `01` - + `52` * `dekad`: `00` - `36` * `month`: `01` - `12` * `season`: `djf` (December - February), `mam` + (March - May), `jja` (June - August), `son` (September - November) * `tropical-season`: `ndjfma` + (November - April), `mjjaso` (May - October) * `year`: Four-digit year numbers * `decade`: Four-digit + year numbers, the last digit being a `0` * `decade-ad`: Four-digit year numbers, the last digit being a + `1` * `single-period` / `climatology-period`: A single dimension label with any name is expected. + :param period: Specifies the time intervals available in the normals data cube. The following options + are available: * `hour`: Hour of the day * `day`: Day of the year * `week`: Week of the year * + `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. * `month`: Month of the year * `season`: Three month periods of the + calendar seasons (December - February, March - May, June - August, September - November). * `tropical- + season`: Six month periods of the tropical seasons (November - April, May - October). * `year`: + Proleptic years * `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. * `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. * `single-period` / + `climatology-period`: A single period of arbitrary length + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged. + """ + return anomaly(data=self, normals=normals, period=period) + + @openeo_process + def any(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Is at least one value true? + + :param self: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return any(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def apply(self, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each pixel + + :param self: A data cube. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return apply(data=self, process=build_child_callback(process, parent_parameters=['x', 'context']), context=context) + + @openeo_process + def apply_dimension(self, process, dimension, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels along a dimension + + :param self: A data cube. + :param process: 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. + :param dimension: The name of the source dimension to apply the process on. Fails with a + `DimensionNotAvailable` exception if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or `null` (the default) to use the source + dimension specified in the parameter `dimension`. By 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. + :param context: Additional data to be passed to the process. + + :return: 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 dimensions can change: + 1. The source dimension is the target dimension: - The (number of) dimensions remain unchanged as + the source dimension is the target dimension. - The source dimension properties name and type remain + unchanged. - 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. 2. The source + dimension is not the target dimension and the latter exists: - The number of dimensions decreases by + one as the source dimension is dropped. - The target dimension properties name and type remain + unchanged. All other dimension properties change as defined in the list below. 3. The source dimension + is not the target dimension and the latter does not exist: - The number of dimensions remain + unchanged, but the source dimension is replaced with the target dimension. - The target dimension + has the specified name and the type other. All other dimension properties are set as defined in the + list below. Unless otherwise stated above, for the given (target) dimension the following applies: - + the number of dimension labels is equal to the number of values computed by the process, - the + dimension labels are incrementing integers starting from zero, - the resolution changes, and - the + reference system is undefined. + """ + return apply_dimension( + data=self, + process=build_child_callback(process, parent_parameters=['data', 'context']), + dimension=dimension, + target_dimension=target_dimension, + context=context + ) + + @openeo_process + def apply_kernel(self, kernel, factor=UNSET, border=UNSET, replace_invalid=UNSET) -> ProcessBuilder: + """ + Apply a spatial convolution with a kernel + + :param self: A data cube. + :param kernel: 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. + :param factor: A factor that is multiplied to each value after the kernel has been applied. This is + basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often + required for some kernel-based algorithms such as the Gaussian blur. + :param border: Determines how the data is extended when the kernel overlaps with the borders. Defaults + to fill the border with zeroes. The following options are available: * *numeric value* - fill with a + user-defined constant number `n`: `nnnnnn|abcdefgh|nnnnnn` (default, with `n` = 0) * `replicate` - + repeat the value from the pixel at the border: `aaaaaa|abcdefgh|hhhhhh` * `reflect` - mirror/reflect + from the border: `fedcba|abcdefgh|hgfedc` * `reflect_pixel` - mirror/reflect from the center of the + pixel at the border: `gfedcb|abcdefgh|gfedcb` * `wrap` - repeat/wrap the image: + `cdefgh|abcdefgh|abcdef` + :param replace_invalid: This parameter specifies the value to replace non-numerical or infinite + numerical values with. By default, those values are replaced with zeroes. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return apply_kernel(data=self, kernel=kernel, factor=factor, border=border, replace_invalid=replace_invalid) + + @openeo_process + def apply_neighborhood(self, process, size, overlap=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels in a n-dimensional neighborhood + + :param self: A data cube. + :param process: Process to be applied on all neighborhoods. + :param size: Neighborhood sizes along each dimension. This 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. + :param overlap: Overlap of neighborhoods along each dimension to avoid border effects. By default no + overlap is provided. For 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. Be aware that large overlaps increase the need for computational resources and modifying + overlapping data in subsequent operations have no effect. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return apply_neighborhood( + data=self, + process=build_child_callback(process, parent_parameters=['data', 'context']), + size=size, + overlap=overlap, + context=context + ) + + @openeo_process + def arccos(self) -> ProcessBuilder: + """ + Inverse cosine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arccos(x=self) + + @openeo_process + def arcosh(self) -> ProcessBuilder: + """ + Inverse hyperbolic cosine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arcosh(x=self) + + @openeo_process + def arcsin(self) -> ProcessBuilder: + """ + Inverse sine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arcsin(x=self) + + @openeo_process + def arctan(self) -> ProcessBuilder: + """ + Inverse tangent + + :param self: A number. + + :return: The computed angle in radians. + """ + return arctan(x=self) + + @openeo_process + def arctan2(self, x) -> ProcessBuilder: + """ + Inverse tangent of two numbers + + :param self: A number to be used as the dividend. + :param x: A number to be used as the divisor. + + :return: The computed angle in radians. + """ + return arctan2(y=self, x=x) + + @openeo_process + def ard_normalized_radar_backscatter(self, elevation_model=UNSET, contributing_area=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant SAR NRB generation + + :param self: The source data cube containing SAR input. + :param elevation_model: 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. + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options + will reduce portability. + + :return: Backscatter values expressed as gamma0 in linear scale. In 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: - `mask`: A data mask that + indicates which values are valid (1), invalid (0) or contain no-data (null). - `local_incidence_angle`: + A band with DEM-based local incidence angles in degrees. The data returned is CARD4L compliant with + corresponding metadata. + """ + return ard_normalized_radar_backscatter( + data=self, + elevation_model=elevation_model, + contributing_area=contributing_area, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + ) + + @openeo_process + def ard_surface_reflectance(self, atmospheric_correction_method, cloud_detection_method, elevation_model=UNSET, atmospheric_correction_options=UNSET, cloud_detection_options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant Surface Reflectance generation + + :param self: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances. There must be a single dimension of type `bands` available. + :param atmospheric_correction_method: The atmospheric correction method to use. + :param cloud_detection_method: The cloud detection method to use. Each method supports detecting + different atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water + vapour in optical imagery. + :param elevation_model: 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. + :param atmospheric_correction_options: Proprietary options for the atmospheric correction method. + Specifying proprietary options will reduce portability. + :param cloud_detection_options: Proprietary options for the cloud detection method. Specifying + proprietary options will reduce portability. + + :return: 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: 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. Depending on the + methods used, several additional bands will be added to the data cube: - `date` (optional): Specifies + per-pixel acquisition timestamps. - `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. - `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. - `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. - `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. - `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. - `incidence-angle` (optional): Specifies per-pixel incidence angles in degrees. - `azimuth` + (optional): Specifies per-pixel azimuth angles in degrees. - `sun-azimuth:` (optional): Specifies per- + pixel sun azimuth angles in degrees. - `sun-elevation` (optional): Specifies per-pixel sun elevation + angles in degrees. - `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. - `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. - `terrain-illumination` (optional): + Contains coefficients used for terrain illumination correction are provided for each pixel. The data + returned is CARD4L compliant with corresponding metadata. + """ + return ard_surface_reflectance( + data=self, + atmospheric_correction_method=atmospheric_correction_method, + cloud_detection_method=cloud_detection_method, + elevation_model=elevation_model, + atmospheric_correction_options=atmospheric_correction_options, + cloud_detection_options=cloud_detection_options + ) + + @openeo_process + def array_append(self, value, label=UNSET) -> ProcessBuilder: + """ + Append a value to an array + + :param self: An array. + :param value: Value to append to the array. + :param label: If the given array is a labeled array, a new label for the new value should be given. If + not given or `null`, the array index as string is used as the label. If in any case the label exists, a + `LabelExists` exception is thrown. + + :return: The new array with the value being appended. + """ + return array_append(data=self, value=value, label=label) + + @openeo_process + def array_apply(self, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each array element + + :param self: An array. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: An array with the newly computed values. The number of elements are the same as for the + original array. + """ + return array_apply( + data=self, + process=build_child_callback(process, parent_parameters=['x', 'index', 'label', 'context']), + context=context + ) + + @openeo_process + def array_concat(self, array2) -> ProcessBuilder: + """ + Merge two arrays + + :param self: The first array. + :param array2: The second array. + + :return: The merged array. + """ + return array_concat(array1=self, array2=array2) + + @openeo_process + def array_contains(self, value) -> ProcessBuilder: + """ + Check whether the array contains a given value + + :param self: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `false`. + + :return: `true` if the list contains the value, false` otherwise. + """ + return array_contains(data=self, value=value) + + @openeo_process + def array_create(self=UNSET, repeat=UNSET) -> ProcessBuilder: + """ + Create an array + + :param self: A (native) array to fill the newly created array with. Defaults to an empty array. + :param repeat: 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`. + + :return: The newly created array. + """ + return array_create(data=self, repeat=repeat) + + @openeo_process + def array_create_labeled(self, labels) -> ProcessBuilder: + """ + Create a labeled array + + :param self: An array of values to be used. + :param labels: An array of labels to be used. + + :return: The newly created labeled array. + """ + return array_create_labeled(data=self, labels=labels) + + @openeo_process + def array_element(self, index=UNSET, label=UNSET, return_nodata=UNSET) -> ProcessBuilder: + """ + Get an element from an array + + :param self: An array. + :param index: The zero-based index of the element to retrieve. + :param label: 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. + :param return_nodata: By default this process throws an `ArrayElementNotAvailable` exception if the + index or label is invalid. If you want to return `null` instead, set this flag to `true`. + + :return: The value of the requested element. + """ + return array_element(data=self, index=index, label=label, return_nodata=return_nodata) + + @openeo_process + def array_filter(self, condition, context=UNSET) -> ProcessBuilder: + """ + Filter an array based on a condition + + :param self: An array. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: An array filtered by the specified condition. The number of elements are less than or equal + compared to the original array. + """ + return array_filter( + data=self, + condition=build_child_callback(condition, parent_parameters=['x', 'index', 'label', 'context']), + context=context + ) + + @openeo_process + def array_find(self, value, reverse=UNSET) -> ProcessBuilder: + """ + Get the index for a value in an array + + :param self: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `null`. + :param reverse: By default, this process finds the index of the first match. To return the index of the + last match instead, set this flag to `true`. + + :return: The index of the first element with the specified value. If no element was found, `null` is + returned. + """ + return array_find(data=self, value=value, reverse=reverse) + + @openeo_process + def array_find_label(self, label) -> ProcessBuilder: + """ + Get the index for a label in a labeled array + + :param self: List to find the label in. + :param label: Label to find in `data`. + + :return: The index of the element with the specified label assigned. If no such label was found, `null` + is returned. + """ + return array_find_label(data=self, label=label) + + @openeo_process + def array_interpolate_linear(self) -> ProcessBuilder: + """ + One-dimensional linear interpolation for arrays + + :param self: An array of numbers and no-data values. If 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. + + :return: 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. + """ + return array_interpolate_linear(data=self) + + @openeo_process + def array_labels(self) -> ProcessBuilder: + """ + Get the labels for an array + + :param self: An array. + + :return: The labels or indices as array. + """ + return array_labels(data=self) + + @openeo_process + def array_modify(self, values, index, length=UNSET) -> ProcessBuilder: + """ + Change the content of an array (remove, insert, update) + + :param self: The array to modify. + :param values: The values to insert into the `data` array. + :param index: The index in the `data` array of the element to insert the value(s) before. If the index + is greater than the number of elements in the `data` array, the process throws an + `ArrayElementNotAvailable` exception. To insert after the last element, there are two options: 1. Use + the simpler processes ``array_append()`` to append a single value or ``array_concat()`` to append + multiple values. 2. 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`. + :param length: The number of elements in the `data` array to remove (or replace) starting from the + given index. If the array contains fewer elements, the process simply removes all elements up to the + end. + + :return: An array with values added, updated or removed. + """ + return array_modify(data=self, values=values, index=index, length=length) + + @openeo_process + def arsinh(self) -> ProcessBuilder: + """ + Inverse hyperbolic sine + + :param self: A number. + + :return: The computed angle in radians. + """ + return arsinh(x=self) + + @openeo_process + def artanh(self) -> ProcessBuilder: + """ + Inverse hyperbolic tangent + + :param self: A number. + + :return: The computed angle in radians. + """ + return artanh(x=self) + + @openeo_process + def atmospheric_correction(self, method, elevation_model=UNSET, options=UNSET) -> ProcessBuilder: + """ + Apply atmospheric correction + + :param self: Data cube containing multi-spectral optical top of atmosphere reflectances to be + corrected. + :param method: The atmospheric correction method to use. To get reproducible results, you have to set a + specific method. Set 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. + :param elevation_model: 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. + :param options: Proprietary options for the atmospheric correction method. Specifying proprietary + options will reduce portability. + + :return: Data cube containing bottom of atmosphere reflectances. + """ + return atmospheric_correction(data=self, method=method, elevation_model=elevation_model, options=options) + + @openeo_process + def between(self, min, max, exclude_max=UNSET) -> ProcessBuilder: + """ + Between comparison + + :param self: The value to check. + :param min: Lower boundary (inclusive) to check against. + :param max: Upper boundary (inclusive) to check against. + :param exclude_max: Exclude the upper boundary `max` if set to `true`. Defaults to `false`. + + :return: `true` if `x` is between the specified bounds, otherwise `false`. + """ + return between(x=self, min=min, max=max, exclude_max=exclude_max) + + @openeo_process + def ceil(self) -> ProcessBuilder: + """ + Round fractions up + + :param self: A number to round up. + + :return: The number rounded up. + """ + return ceil(x=self) + + @openeo_process + def climatological_normal(self, period, climatology_period=UNSET) -> ProcessBuilder: + """ + Compute climatology normals + + :param self: A data cube with exactly one temporal dimension. The data cube must span at least the + temporal interval specified in the parameter `climatology-period`. Seasonal periods may span two + consecutive years, e.g. temporal winter that includes months December, January and February. If the + required months before the actual climate period are available, the season is taken into account. If + not available, the first season is not taken into account and the seasonal mean is based on one year + less than the other seasonal normals. The incomplete season at the end of the last year is never taken + into account. + :param period: The time intervals to aggregate the average value for. The following pre-defined + frequencies are supported: * `day`: Day of the year * `month`: Month of the year * `climatology- + period`: The period specified in the `climatology-period`. * `season`: Three month periods of the + calendar seasons (December - February, March - May, June - August, September - November). * `tropical- + season`: Six month periods of the tropical seasons (November - April, May - October). + :param climatology_period: 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). + + :return: 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 temporal + dimension. The temporal dimension has the following dimension labels: * `day`: `001` - `365` * + `month`: `01` - `12` * `climatology-period`: `climatology-period` * `season`: `djf` (December - + February), `mam` (March - May), `jja` (June - August), `son` (September - November) * `tropical- + season`: `ndjfma` (November - April), `mjjaso` (May - October) + """ + return climatological_normal(data=self, period=period, climatology_period=climatology_period) + + @openeo_process + def clip(self, min, max) -> ProcessBuilder: + """ + Clip a value between a minimum and a maximum + + :param self: A number. + :param min: Minimum value. If the value is lower than this value, the process will return the value of + this parameter. + :param max: Maximum value. If the value is greater than this value, the process will return the value + of this parameter. + + :return: The value clipped to the specified range. + """ + return clip(x=self, min=min, max=max) + + @openeo_process + def cloud_detection(self, method, options=UNSET) -> ProcessBuilder: + """ + Create cloud masks + + :param self: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances on which to perform cloud detection. + :param method: The cloud detection method to use. To get reproducible results, you have to set a + specific method. Set 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. + :param options: Proprietary options for the cloud detection method. Specifying proprietary options will + reduce portability. + + :return: 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. + """ + return cloud_detection(data=self, method=method, options=options) + + @openeo_process + def constant(self) -> ProcessBuilder: + """ + Define a constant value + + :param self: The value of the constant. + + :return: The value of the constant. + """ + return constant(x=self) + + @openeo_process + def cos(self) -> ProcessBuilder: + """ + Cosine + + :param self: An angle in radians. + + :return: The computed cosine of `x`. + """ + return cos(x=self) + + @openeo_process + def cosh(self) -> ProcessBuilder: + """ + Hyperbolic cosine + + :param self: An angle in radians. + + :return: The computed hyperbolic cosine of `x`. + """ + return cosh(x=self) + + @openeo_process + def count(self, condition=UNSET, context=UNSET) -> ProcessBuilder: + """ + Count the number of elements + + :param self: An array with elements of any data type. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: The counted number of elements. + """ + return count(data=self, condition=condition, context=context) + + @openeo_process + def create_raster_cube(self) -> ProcessBuilder: + """ + Create an empty raster data cube + + :return: An empty raster data cube with zero dimensions. + """ + return create_raster_cube() + + @openeo_process + def cummax(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative maxima + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative maxima. + """ + return cummax(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def cummin(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative minima + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative minima. + """ + return cummin(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def cumproduct(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative products + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative products. + """ + return cumproduct(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def cumsum(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative sums + + :param self: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative sums. + """ + return cumsum(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def date_shift(self, value, unit) -> ProcessBuilder: + """ + Manipulates dates and times by addition or subtraction + + :param self: The date (and optionally time) to manipulate. If 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. + :param value: 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. + :param unit: The unit for the value given. The following pre-defined units are available: - + millisecond: Milliseconds - second: Seconds - leap seconds are ignored in computations. - minute: + Minutes - hour: Hours - day: Days - changes only the the day part of a date - week: Weeks (equivalent + to 7 days) - month: Months - year: Years Manipulations 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`. + + :return: The manipulated date. If a time component was given in the parameter `date`, the time + component is returned with the date. + """ + return date_shift(date=self, value=value, unit=unit) + + @openeo_process + def dimension_labels(self, dimension) -> ProcessBuilder: + """ + Get the dimension labels + + :param self: The data cube. + :param dimension: The name of the dimension to get the labels for. + + :return: The labels as an array. + """ + return dimension_labels(data=self, dimension=dimension) + + @openeo_process + def divide(self, y) -> ProcessBuilder: + """ + Division of two numbers + + :param self: The dividend. + :param y: The divisor. + + :return: The computed result. + """ + return divide(x=self, y=y) + + @openeo_process + def drop_dimension(self, name) -> ProcessBuilder: + """ + Remove a dimension + + :param self: The data cube to drop a dimension from. + :param name: Name of the dimension to drop. + + :return: A data cube without the specified dimension. The number of dimensions decreases by one, but + the dimension properties (name, type, labels, reference system and resolution) for all other dimensions + remain unchanged. + """ + return drop_dimension(data=self, name=name) + + @openeo_process + def e(self) -> ProcessBuilder: + """ + Euler's number (e) + + :return: The numerical value of Euler's number. + """ + return e() + + @openeo_process + def eq(self, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Equal to comparison + + :param self: First operand. + :param y: Second operand. + :param delta: 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. + This option is basically an alias for the following computation: `lte(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be + disabled by setting this parameter to `false`. + + :return: `true` if `x` is equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return eq(x=self, y=y, delta=delta, case_sensitive=case_sensitive) + + @openeo_process + def exp(self) -> ProcessBuilder: + """ + Exponentiation to the base e + + :param self: The numerical exponent. + + :return: The computed value for *e* raised to the power of `p`. + """ + return exp(p=self) + + @openeo_process + def extrema(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum and maximum values + + :param self: An array of numbers. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. + Setting this flag to `false` considers no-data values so that an array with two `null` values is + returned if any value is such a value. + + :return: An array containing the minimum and maximum values for the specified numbers. The first + element is the minimum, the second element is the maximum. If the input array is empty both elements + are set to `null`. + """ + return extrema(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def filter_bands(self, bands=UNSET, wavelengths=UNSET) -> ProcessBuilder: + """ + Filter the bands by names + + :param self: A data cube with bands. + :param bands: 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. The 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. + :param wavelengths: 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). The 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. + + :return: A data cube limited to a subset of its original bands. The dimensions and dimension properties + (name, type, labels, reference system and resolution) remain unchanged, except that the dimension of + type `bands` has less (or the same) dimension labels. + """ + return filter_bands(data=self, bands=bands, wavelengths=wavelengths) + + @openeo_process + def filter_bbox(self, extent) -> ProcessBuilder: + """ + Spatial filter using a bounding box + + :param self: A data cube. + :param extent: A bounding box, which may include a vertical axis (see `base` and `height`). + + :return: A data cube restricted to the bounding box. The dimensions and dimension properties (name, + type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions + have less (or the same) dimension labels. + """ + return filter_bbox(data=self, extent=extent) + + @openeo_process + def filter_labels(self, condition, dimension, context=UNSET) -> ProcessBuilder: + """ + Filter dimension labels based on a condition + + :param self: A data cube. + :param condition: A condition that is evaluated against each dimension label in the specified + dimension. A dimension label and the corresponding data is preserved for the given dimension, if the + condition returns `true`. + :param dimension: The name of the dimension to filter on. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param context: Additional data to be passed to the condition. + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged, except that the given dimension has less (or the same) + dimension labels. + """ + return filter_labels( + data=self, + condition=build_child_callback(condition, parent_parameters=['value', 'context']), + dimension=dimension, + context=context + ) + + @openeo_process + def filter_spatial(self, geometries) -> ProcessBuilder: + """ + Spatial filter using geometries + + :param self: A data cube. + :param geometries: One or more geometries used for filtering, specified as GeoJSON. + + :return: A data cube restricted to the specified geometries. The dimensions and dimension properties + (name, type, labels, reference system and resolution) remain unchanged, except that the spatial + dimensions have less (or the same) dimension labels. + """ + return filter_spatial(data=self, geometries=geometries) + + @openeo_process + def filter_temporal(self, extent, dimension=UNSET) -> ProcessBuilder: + """ + Temporal filter based on temporal intervals + + :param self: A data cube. + :param extent: Left-closed temporal interval, i.e. an array with exactly two elements: 1. The first + element is the start of the temporal interval. The specified instance in time is **included** in the + interval. 2. The second element is the end of the temporal interval. The specified instance in time is + **excluded** from the interval. The 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. + :param dimension: 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. + + :return: 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. + """ + return filter_temporal(data=self, extent=extent, dimension=dimension) + + @openeo_process + def first(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + First element + + :param self: An array with elements of any data type. + :param ignore_nodata: 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 returned if the first value is + such a value. + + :return: The first element of the input array. + """ + return first(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def fit_class_random_forest(self, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest classification model + + :param self: The predictors for the classification model as a vector data cube. Aggregated to the + features (vectors) of the target input variable. + :param target: The training sites for the classification model as a vector data cube. This is + associated with the target variable for the Random Forest model. The geometry has to associated with a + value to predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options + are available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables + are considered for each split. - `onethird`: A third of the number of variables are considered for each + split. - `sqrt`: The square root of the number of variables are considered for each split. This is + often the default for classification. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, + no seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with + ``load_ml_model()``. + """ + return fit_class_random_forest(predictors=self, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed) + + @openeo_process + def fit_curve(self, parameters, function, dimension) -> ProcessBuilder: + """ + Curve fitting + + :param self: A data cube. + :param parameters: Defined the number of parameters for the model function and provides an initial + guess for them. At least one parameter is required. + :param function: The model function. It must take the parameters to fit as array through the first + argument and the independent variable `x` as the second argument. It is recommended to store the model + function as a user-defined process on the back-end to be able to re-use the model function with the + computed optimal values for the parameters afterwards. + :param dimension: The name of the dimension for curve fitting. Must be a dimension with labels that + have a order (i.e. numerical labels or a temporal dimension). Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + + :return: A data cube with the optimal values for the parameters. + """ + return fit_curve( + data=self, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension + ) + + @openeo_process + def fit_regr_random_forest(self, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest regression model + + :param self: The predictors for the regression model as a vector data cube. Aggregated to the features + (vectors) of the target input variable. + :param target: The training sites for the regression model as a vector data cube. This is associated + with the target variable for the Random Forest model. The geometry has to associated with a value to + predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options + are available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables + are considered for each split. - `onethird`: A third of the number of variables are considered for each + split. This is often the default for regression. - `sqrt`: The square root of the number of variables + are considered for each split. + :param num_trees: The number of trees build within the Random Forest regression. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, + no seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with + ``load_ml_model()``. + """ + return fit_regr_random_forest(predictors=self, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed) + + @openeo_process + def flatten_dimensions(self, dimensions, target_dimension, label_separator=UNSET) -> ProcessBuilder: + """ + Combine multiple dimensions into a single dimension + + :param self: A data cube. + :param dimensions: The names of the dimension to combine. The order of the array defines the order in + which the dimension labels and values are combined (see the example in the process description). Fails + with a `DimensionNotAvailable` exception if at least one of the specified dimensions does not exist. + :param target_dimension: The name of the new target dimension. A new dimensions will be created with + the given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` + exception if a dimension with the specified name exists. + :param label_separator: The string that will be used as a separator for the concatenated dimension + labels. To unambiguously revert the dimension labels with the process ``unflatten_dimension()``, the + given string must not be contained in any of the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system + and resolution) for all other dimensions remain unchanged. + """ + return flatten_dimensions(data=self, dimensions=dimensions, target_dimension=target_dimension, label_separator=label_separator) + + @openeo_process + def floor(self) -> ProcessBuilder: + """ + Round fractions down + + :param self: A number to round down. + + :return: The number rounded down. + """ + return floor(x=self) + + @openeo_process + def gt(self, y) -> ProcessBuilder: + """ + Greater than comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly greater than `y` or `null` if any operand is `null`, otherwise + `false`. + """ + return gt(x=self, y=y) + + @openeo_process + def gte(self, y) -> ProcessBuilder: + """ + Greater than or equal to comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is greater than or equal to `y`, `null` if any operand is `null`, otherwise + `false`. + """ + return gte(x=self, y=y) + + @openeo_process + def if_(self, accept, reject=UNSET) -> ProcessBuilder: + """ + If-Then-Else conditional + + :param self: A boolean value. + :param accept: A value that is returned if the boolean value is `true`. + :param reject: A value that is returned if the boolean value is **not** `true`. Defaults to `null`. + + :return: Either the `accept` or `reject` argument depending on the given boolean value. + """ + return if_(value=self, accept=accept, reject=reject) + + @openeo_process + def inspect(self, code=UNSET, level=UNSET, message=UNSET) -> ProcessBuilder: + """ + Add information to the logs + + :param self: Data to log. + :param code: A label to help identify one or more log entries originating from this process in the list + of all log entries. It can help to group or filter log entries and is usually not unique. + :param level: The severity level of this message, defaults to `info`. + :param message: A message to send in addition to the data. + + :return: The data as passed to the `data` parameter without any modification. + """ + return inspect(data=self, code=code, level=level, message=message) + + @openeo_process + def int(self) -> ProcessBuilder: + """ + Integer part of a number + + :param self: A number. + + :return: Integer part of the number. + """ + return int(x=self) + + @openeo_process + def is_infinite(self) -> ProcessBuilder: + """ + Value is an infinite number + + :param self: The data to check. + + :return: `true` if the data is an infinite number, otherwise `false`. + """ + return is_infinite(x=self) + + @openeo_process + def is_nan(self) -> ProcessBuilder: + """ + Value is not a number + + :param self: The data to check. + + :return: `true` if the data is not a number, otherwise `false`. + """ + return is_nan(x=self) + + @openeo_process + def is_nodata(self) -> ProcessBuilder: + """ + Value is a no-data value + + :param self: The data to check. + + :return: `true` if the data is a no-data value, otherwise `false`. + """ + return is_nodata(x=self) + + @openeo_process + def is_valid(self) -> ProcessBuilder: + """ + Value is valid data + + :param self: The data to check. + + :return: `true` if the data is valid, otherwise `false`. + """ + return is_valid(x=self) + + @openeo_process + def last(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Last element + + :param self: An array with elements of any data type. + :param ignore_nodata: 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 returned if the last value is + such a value. + + :return: The last element of the input array. + """ + return last(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def linear_scale_range(self, inputMin, inputMax, outputMin=UNSET, outputMax=UNSET) -> ProcessBuilder: + """ + Linear transformation between two ranges + + :param self: A number to transform. The number gets clipped to the bounds specified in `inputMin` and + `inputMax`. + :param inputMin: Minimum value the input can obtain. + :param inputMax: Maximum value the input can obtain. + :param outputMin: Minimum value of the desired output range. + :param outputMax: Maximum value of the desired output range. + + :return: The transformed number. + """ + return linear_scale_range(x=self, inputMin=inputMin, inputMax=inputMax, outputMin=outputMin, outputMax=outputMax) + + @openeo_process + def ln(self) -> ProcessBuilder: + """ + Natural logarithm + + :param self: A number to compute the natural logarithm for. + + :return: The computed natural logarithm. + """ + return ln(x=self) + + @openeo_process + def load_collection(self, spatial_extent, temporal_extent, bands=UNSET, properties=UNSET) -> ProcessBuilder: + """ + Load a collection + + :param self: The collection id. + :param spatial_extent: Limits the data to load from the collection to the specified bounding box or + polygons. The 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). The + GeoJSON can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a + `Feature` with a `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one + `Feature` with `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` + or `MultiPolygon` geometries. To maximize interoperability, `GeometryCollection` should be avoided in + favour of one of the alternatives above. Set 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. + :param temporal_extent: 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: 1. The first element is the start of the temporal interval. The specified + instance in time is **included** in the interval. 2. The second element is the end of the temporal + interval. The specified instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is + recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded + data. + :param properties: Limits the data by metadata properties to include only data in the data cube which + all given conditions return `true` for (AND operation). Specify key-value-pairs with the key being the + name of the metadata property, which can be retrieved with the openEO Data Discovery for Collections. + The value must be a condition (user-defined process) to be evaluated against the collection metadata, + see the example. + + :return: A data cube for further processing. The dimensions and dimension properties (name, type, + labels, reference system and resolution) correspond to the collection's metadata, but the dimension + labels are restricted as specified in the parameters. + """ + return load_collection(id=self, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands, properties=properties) + + @openeo_process + def load_ml_model(self) -> ProcessBuilder: + """ + Load a ML model + + :param self: The STAC Item to load the machine learning model from. The STAC Item must implement the + `ml-model` extension. + + :return: A machine learning model to be used with machine learning processes such as + ``predict_random_forest()``. + """ + return load_ml_model(id=self) + + @openeo_process + def load_result(self, spatial_extent=UNSET, temporal_extent=UNSET, bands=UNSET) -> ProcessBuilder: + """ + Load batch job results + + :param self: The id of a batch job with results. + :param spatial_extent: Limits the data to load from the batch job result to the specified bounding box + or polygons. The 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). + The GeoJSON can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a + `Feature` with a `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one + `Feature` with `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` + or `MultiPolygon` geometries. To maximize interoperability, `GeometryCollection` should be avoided in + favour of one of the alternatives above. Set 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. + :param temporal_extent: Limits the data to load from the batch job result 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: 1. The first element is the start of the temporal interval. The specified + instance in time is **included** in the interval. 2. The second element is the end of the temporal + interval. The specified instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is + recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded + data. + + :return: A data cube for further processing. + """ + return load_result(id=self, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands) + + @openeo_process + def load_uploaded_files(self, format, options=UNSET) -> ProcessBuilder: + """ + Load files from the user workspace + + :param self: The files to read. Folders can't be specified, specify all files instead. An exception is + thrown if a file can't be read. + :param format: The file format to read from. It must be one of the values that the server reports as + supported input file formats, which usually correspond to the short GDAL/OGR codes. If the format is + not suitable for loading the data, a `FormatUnsuitable` exception will be thrown. This parameter is + *case insensitive*. + :param options: The file format parameters to be used to read the files. Must correspond to the + parameters that the server reports as supported parameters for the chosen `format`. The parameter names + and valid values usually correspond to the GDAL/OGR format options. + + :return: A data cube for further processing. + """ + return load_uploaded_files(paths=self, format=format, options=options) + + @openeo_process + def log(self, base) -> ProcessBuilder: + """ + Logarithm to a base + + :param self: A number to compute the logarithm for. + :param base: The numerical base. + + :return: The computed logarithm. + """ + return log(x=self, base=base) + + @openeo_process + def lt(self, y) -> ProcessBuilder: + """ + Less than comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly less than `y`, `null` if any operand is `null`, otherwise `false`. + """ + return lt(x=self, y=y) + + @openeo_process + def lte(self, y) -> ProcessBuilder: + """ + Less than or equal to comparison + + :param self: First operand. + :param y: Second operand. + + :return: `true` if `x` is less than or equal to `y`, `null` if any operand is `null`, otherwise + `false`. + """ + return lte(x=self, y=y) + + @openeo_process + def mask(self, mask, replacement=UNSET) -> ProcessBuilder: + """ + Apply a raster mask + + :param self: A raster data cube. + :param mask: A mask as a raster data cube. Every pixel in `data` must have a corresponding element in + `mask`. + :param replacement: The value used to replace masked values with. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, + labels, reference system and resolution) remain unchanged. + """ + return mask(data=self, mask=mask, replacement=replacement) + + @openeo_process + def mask_polygon(self, mask, replacement=UNSET, inside=UNSET) -> ProcessBuilder: + """ + Apply a polygon mask + + :param self: A raster data cube. + :param mask: A GeoJSON object containing at least one polygon. The provided feature types can be one of + the following: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a `Polygon` or + `MultiPolygon` geometry, * a `FeatureCollection` containing at least one `Feature` with `Polygon` or + `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` + geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of + the alternatives above. + :param replacement: The value used to replace masked values with. + :param inside: If set to `true` all pixels for which the point at the pixel center **does** intersect + with any polygon are replaced. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, + labels, reference system and resolution) remain unchanged. + """ + return mask_polygon(data=self, mask=mask, replacement=replacement, inside=inside) + + @openeo_process + def max(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Maximum value + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The maximum value. + """ + return max(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def mean(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Arithmetic mean (average) + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed arithmetic mean. + """ + return mean(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def median(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Statistical median + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed statistical median. + """ + return median(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def merge_cubes(self, cube2, overlap_resolver=UNSET, context=UNSET) -> ProcessBuilder: + """ + Merge two data cubes + + :param self: The first data cube. + :param cube2: The second data cube. + :param overlap_resolver: A reduction operator that resolves the conflict if the data overlaps. The + reducer must return a value of the same data type as the input values are. The reduction operator may + be a single process such as ``multiply()`` or consist of multiple sub-processes. `null` (the default) + can be specified if no overlap resolver is required. + :param context: Additional data to be passed to the overlap resolver. + + :return: The merged data cube. See the process description for details regarding the dimensions and + dimension properties (name, type, labels, reference system and resolution). + """ + return merge_cubes( + cube1=self, + cube2=cube2, + overlap_resolver=build_child_callback(overlap_resolver, parent_parameters=['x', 'y', 'context']), + context=context + ) + + @openeo_process + def min(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum value + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The minimum value. + """ + return min(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def mod(self, y) -> ProcessBuilder: + """ + Modulo + + :param self: A number to be used as the dividend. + :param y: A number to be used as the divisor. + + :return: The remainder after division. + """ + return mod(x=self, y=y) + + @openeo_process + def multiply(self, y) -> ProcessBuilder: + """ + Multiplication of two numbers + + :param self: The multiplier. + :param y: The multiplicand. + + :return: The computed product of the two numbers. + """ + return multiply(x=self, y=y) + + @openeo_process + def nan(self) -> ProcessBuilder: + """ + Not a Number (NaN) + + :return: Returns `NaN`. + """ + return nan() + + @openeo_process + def ndvi(self, nir=UNSET, red=UNSET, target_band=UNSET) -> ProcessBuilder: + """ + Normalized Difference Vegetation Index + + :param self: A raster data cube with two bands that have the common names `red` and `nir` assigned. + :param nir: The name of the NIR band. Defaults to the band that has the common name `nir` assigned. + Either 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. + :param red: The name of the red band. Defaults to the band that has the common name `red` assigned. + Either 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. + :param target_band: By default, the dimension of type `bands` is dropped. To keep the dimension specify + a new band name in this parameter so that a new dimension label with the specified name will be added + for the computed values. + + :return: A raster data cube containing the computed NDVI values. The structure of the data cube differs + depending on the value passed to `target_band`: * `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. * `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`. + """ + return ndvi(data=self, nir=nir, red=red, target_band=target_band) + + @openeo_process + def neq(self, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Not equal to comparison + + :param self: First operand. + :param y: Second operand. + :param delta: 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. + This option is basically an alias for the following computation: `gt(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be + disabled by setting this parameter to `false`. + + :return: `true` if `x` is *not* equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return neq(x=self, y=y, delta=delta, case_sensitive=case_sensitive) + + @openeo_process + def normalized_difference(self, y) -> ProcessBuilder: + """ + Normalized difference + + :param self: The value for the first band. + :param y: The value for the second band. + + :return: The computed normalized difference. + """ + return normalized_difference(x=self, y=y) + + @openeo_process + def not_(self) -> ProcessBuilder: + """ + Inverting a boolean + + :param self: Boolean value to invert. + + :return: Inverted boolean value. + """ + return not_(x=self) + + @openeo_process + def or_(self, y) -> ProcessBuilder: + """ + Logical OR + + :param self: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical OR. + """ + return or_(x=self, y=y) + + @openeo_process + def order(self, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Create a permutation + + :param self: An array to compute the order for. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The computed permutation. + """ + return order(data=self, asc=asc, nodata=nodata) + + @openeo_process + def pi(self) -> ProcessBuilder: + """ + Pi (π) + + :return: The numerical value of Pi. + """ + return pi() + + @openeo_process + def power(self, p) -> ProcessBuilder: + """ + Exponentiation + + :param self: The numerical base. + :param p: The numerical exponent. + + :return: The computed value for `base` raised to the power of `p`. + """ + return power(base=self, p=p) + + @openeo_process + def predict_curve(self, parameters, function, dimension, labels=UNSET) -> ProcessBuilder: + """ + Predict values + + :param self: A data cube to predict values for. + :param parameters: A data cube with optimal values from a result of e.g. ``fit_curve()``. + :param function: The model function. It must take the parameters to fit as array through the first + argument and the independent variable `x` as the second argument. It is recommended to store the model + function as a user-defined process on the back-end. + :param dimension: The name of the dimension for predictions. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param labels: The labels to predict values for. If no labels are given, predicts values only for no- + data (`null`) values in the data cube. + + :return: A data cube with the predicted values. + """ + return predict_curve( + data=self, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension, + labels=labels + ) + + @openeo_process + def predict_random_forest(self, model) -> ProcessBuilder: + """ + Predict values from a Random Forest model + + :param self: An array of numbers. + :param model: A model object that can be trained with the processes ``fit_regr_random_forest()`` + (regression) and ``fit_class_random_forest()`` (classification). + + :return: The predicted value. Returns `null` if any of the given values in the array is a no-data + value. + """ + return predict_random_forest(data=self, model=model) + + @openeo_process + def product(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the product by multiplying numbers + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed product of the sequence of numbers. + """ + return product(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def quantiles(self, probabilities=UNSET, q=UNSET, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Quantiles + + :param self: An array of numbers. + :param probabilities: A list of probabilities to calculate quantiles for. The probabilities must be + between 0 and 1 (inclusive). + :param q: Number of intervals to calculate quantiles for. Calculates q-quantiles with equal-sized + intervals. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. + Setting this flag to `false` considers no-data values so that an array with `null` values is returned + if any element is such a value. + + :return: An array with the computed quantiles. The list has either * as many elements as the given + list of `probabilities` had or * *`q`-1* elements. If 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. + """ + return quantiles(data=self, probabilities=probabilities, q=q, ignore_nodata=ignore_nodata) + + @openeo_process + def rearrange(self, order) -> ProcessBuilder: + """ + Rearrange an array based on a permutation + + :param self: The array to rearrange. + :param order: The permutation used for rearranging. + + :return: The rearranged array. + """ + return rearrange(data=self, order=order) + + @openeo_process + def reduce_dimension(self, reducer, dimension, context=UNSET) -> ProcessBuilder: + """ + Reduce dimensions + + :param self: A data cube. + :param reducer: A reducer to apply on 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. + :param dimension: The name of the dimension over which to reduce. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return reduce_dimension( + data=self, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + ) + + @openeo_process + def reduce_spatial(self, reducer, context=UNSET) -> ProcessBuilder: + """ + Reduce spatial dimensions 'x' and 'y' + + :param self: A data cube. + :param reducer: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return reduce_spatial(data=self, reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), context=context) + + @openeo_process + def rename_dimension(self, source, target) -> ProcessBuilder: + """ + Rename a dimension + + :param self: The data cube. + :param source: The current name of the dimension. Fails with a `DimensionNotAvailable` exception if the + specified dimension does not exist. + :param target: A new Name for the dimension. Fails with a `DimensionExists` exception if a dimension + with the specified name exists. + + :return: A data cube with the same dimensions, but the name of one of the dimensions changes. The old + name can not be referred to any longer. The dimension properties (name, type, labels, reference system + and resolution) remain unchanged. + """ + return rename_dimension(data=self, source=source, target=target) + + @openeo_process + def rename_labels(self, dimension, target, source=UNSET) -> ProcessBuilder: + """ + Rename dimension labels + + :param self: The data cube. + :param dimension: The name of the dimension to rename the labels for. + :param target: The new names for the labels. If a target dimension label already exists in the data + cube, a `LabelExists` exception is thrown. + :param source: The original names of the labels to be renamed to corresponding array elements in the + parameter `target`. It is allowed to only specify a subset of labels to rename, as long as the `target` + and `source` parameter have the same length. The order of the labels doesn't need to match the order of + the dimension labels in the data cube. By default, the array is empty so that the dimension labels in + the data cube are expected to be enumerated. If the dimension labels are not enumerated and the given + array is empty, the `LabelsNotEnumerated` exception is thrown. If one of the source dimension labels + doesn't exist, the `LabelNotAvailable` exception is thrown. + + :return: The data cube with the same dimensions. The dimension properties (name, type, labels, + reference system and resolution) remain unchanged, except that for the given dimension the labels + change. The old labels can not be referred to any longer. The number of labels remains the same. + """ + return rename_labels(data=self, dimension=dimension, target=target, source=source) + + @openeo_process + def resample_cube_spatial(self, target, method=UNSET) -> ProcessBuilder: + """ + Resample the spatial dimensions to match a target data cube + + :param self: A data cube. + :param target: A data cube that describes the spatial target resolution. + :param method: 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): * `average`: average + (mean) resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling + * `cubic`: cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc + resampling * `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median + resampling, selects the median value of all valid pixels * `min`: minimum resampling, selects the + minimum value from all valid pixels * `mode`: mode resampling, selects the value which appears most + often of all the sampled points * `near`: nearest neighbour resampling (default) * `q1`: first quartile + resampling, selects the first quartile value of all valid pixels * `q3`: third quartile resampling, + selects the third quartile value of all valid pixels * `rms` root mean square (quadratic mean) of all + valid pixels * `sum`: compute the weighted sum of all valid pixels Valid pixels are determined based + on the function ``is_valid()``. + + :return: 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 spatial + dimensions. + """ + return resample_cube_spatial(data=self, target=target, method=method) + + @openeo_process + def resample_cube_temporal(self, target, dimension=UNSET, valid_within=UNSET) -> ProcessBuilder: + """ + Resample temporal dimensions to match a target data cube + + :param self: A data cube with one or more temporal dimensions. + :param target: A data cube that describes the temporal target resolution. + :param dimension: 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. The following exceptions may occur: * A + dimension is given, but it does not exist in any of the data cubes: `DimensionNotAvailable` * A + dimension is given, but one of them is not temporal: `DimensionMismatch` * No specific dimension name + is given and there are no temporal dimensions with the same name in the data: `DimensionMismatch` + :param valid_within: 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`). + + :return: 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. + """ + return resample_cube_temporal(data=self, target=target, dimension=dimension, valid_within=valid_within) + + @openeo_process + def resample_spatial(self, resolution=UNSET, projection=UNSET, method=UNSET, align=UNSET) -> ProcessBuilder: + """ + Resample and warp the spatial dimensions + + :param self: A raster data cube. + :param resolution: 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`). + :param projection: Warps the data cube to the target projection, specified as as [EPSG + code](http://www.epsg-registry.org/), [WKT2 (ISO 19162) + string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html), [PROJ definition + (deprecated)](https://proj.org/usage/quickstart.html). By default (`null`), the projection is not + changed. + :param method: 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): * `average`: average + (mean) resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling + * `cubic`: cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc + resampling * `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median + resampling, selects the median value of all valid pixels * `min`: minimum resampling, selects the + minimum value from all valid pixels * `mode`: mode resampling, selects the value which appears most + often of all the sampled points * `near`: nearest neighbour resampling (default) * `q1`: first quartile + resampling, selects the first quartile value of all valid pixels * `q3`: third quartile resampling, + selects the third quartile value of all valid pixels * `rms` root mean square (quadratic mean) of all + valid pixels * `sum`: compute the weighted sum of all valid pixels Valid pixels are determined based + on the function ``is_valid()``. + :param align: Specifies to which corner of the spatial extent the new resampled data is aligned to. + + :return: A raster data cube with values warped onto the new projection. It has the same dimensions and + the same dimension properties (name, type, labels, reference system and resolution) for all non-spatial + or vertical spatial dimensions. For the horizontal spatial dimensions the name and type remain + unchanged, but reference system, labels and resolution may change depending on the given parameters. + """ + return resample_spatial(data=self, resolution=resolution, projection=projection, method=method, align=align) + + @openeo_process + def round(self, p=UNSET) -> ProcessBuilder: + """ + Round to a specified precision + + :param self: A number to round. + :param p: A positive number specifies the number of digits after the decimal point to round to. A + negative number means rounding to a power of ten, so for example *-2* rounds to the nearest hundred. + Defaults to *0*. + + :return: The rounded number. + """ + return round(x=self, p=p) + + @openeo_process + def run_udf(self, udf, runtime, version=UNSET, context=UNSET) -> ProcessBuilder: + """ + Run a UDF + + :param self: The data to be passed to the UDF. + :param udf: Either source code, an absolute URL or a path to a UDF script. + :param runtime: A UDF runtime identifier available at the back-end. + :param version: An UDF runtime version. If set to `null`, the default runtime version specified for + each runtime is used. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can be of any data type and is exactly what + the UDF code returns. + """ + return run_udf(data=self, udf=udf, runtime=runtime, version=version, context=context) + + @openeo_process + def run_udf_externally(self, url, context=UNSET) -> ProcessBuilder: + """ + Run an externally hosted UDF container + + :param self: The data to be passed to the UDF. + :param url: Absolute URL to a remote UDF service. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can in principle be of any data type, but it + depends on what is returned by the UDF code. Please see the implemented UDF interface for details. + """ + return run_udf_externally(data=self, url=url, context=context) + + @openeo_process + def sar_backscatter(self, coefficient=UNSET, elevation_model=UNSET, mask=UNSET, contributing_area=UNSET, local_incidence_angle=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + Computes backscatter from SAR input + + :param self: The source data cube containing SAR input. + :param coefficient: Select the radiometric correction coefficient. The following options are available: + * `beta0`: radar brightness * `sigma0-ellipsoid`: ground area computed with ellipsoid earth model * + `sigma0-terrain`: ground area computed with terrain earth model * `gamma0-ellipsoid`: ground area + computed with ellipsoid earth model in sensor line of sight * `gamma0-terrain`: ground area computed + with terrain earth model in sensor line of sight (default) * `null`: non-normalized backscatter + :param elevation_model: 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. + :param mask: 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). + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param local_incidence_angle: If set to `true`, a DEM-based local incidence angle band named + `local_incidence_angle` is added. The values are given in degrees. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options + will reduce portability. + + :return: Backscatter values corresponding to the chosen parametrization. The values are given in linear + scale. + """ + return sar_backscatter( + data=self, + coefficient=coefficient, + elevation_model=elevation_model, + mask=mask, + contributing_area=contributing_area, + local_incidence_angle=local_incidence_angle, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + ) + + @openeo_process + def save_ml_model(self, options=UNSET) -> ProcessBuilder: + """ + Save a ML model + + :param self: The data to store as a machine learning model. + :param options: Additional parameters to create the file(s). + + :return: Returns `false` if the process failed to store the model, `true` otherwise. + """ + return save_ml_model(data=self, options=options) + + @openeo_process + def save_result(self, format, options=UNSET) -> ProcessBuilder: + """ + Save processed data + + :param self: The data to deliver in the given file format. + :param format: The file format to use. It must be one of the values that the server reports as + supported output file formats, which usually correspond to the short GDAL/OGR codes. If the format is + not suitable for storing the underlying data structure, a `FormatUnsuitable` exception will be thrown. + This parameter is *case insensitive*. + :param options: The file format parameters to be used to create the file(s). Must correspond to the + parameters that the server reports as supported parameters for the chosen `format`. The parameter names + and valid values usually correspond to the GDAL/OGR format options. + + :return: Returns `false` if the process failed to make the data available, `true` otherwise. + """ + return save_result(data=self, format=format, options=options) + + @openeo_process + def sd(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Standard deviation + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed sample standard deviation. + """ + return sd(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def sgn(self) -> ProcessBuilder: + """ + Signum + + :param self: A number. + + :return: The computed signum value of `x`. + """ + return sgn(x=self) + + @openeo_process + def sin(self) -> ProcessBuilder: + """ + Sine + + :param self: An angle in radians. + + :return: The computed sine of `x`. + """ + return sin(x=self) + + @openeo_process + def sinh(self) -> ProcessBuilder: + """ + Hyperbolic sine + + :param self: An angle in radians. + + :return: The computed hyperbolic sine of `x`. + """ + return sinh(x=self) + + @openeo_process + def sort(self, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Sort data + + :param self: An array with data to sort. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The sorted array. + """ + return sort(data=self, asc=asc, nodata=nodata) + + @openeo_process + def sqrt(self) -> ProcessBuilder: + """ + Square root + + :param self: A number. + + :return: The computed square root. + """ + return sqrt(x=self) + + @openeo_process + def subtract(self, y) -> ProcessBuilder: + """ + Subtraction of two numbers + + :param self: The minuend. + :param y: The subtrahend. + + :return: The computed result. + """ + return subtract(x=self, y=y) + + @openeo_process + def sum(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the sum by adding up numbers + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed sum of the sequence of numbers. + """ + return sum(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def tan(self) -> ProcessBuilder: + """ + Tangent + + :param self: An angle in radians. + + :return: The computed tangent of `x`. + """ + return tan(x=self) + + @openeo_process + def tanh(self) -> ProcessBuilder: + """ + Hyperbolic tangent + + :param self: An angle in radians. + + :return: The computed hyperbolic tangent of `x`. + """ + return tanh(x=self) + + @openeo_process + def text_begins(self, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text begins with another text + + :param self: Text in which to find something at the beginning. + :param pattern: Text to find at the beginning of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` begins with `pattern`, false` otherwise. + """ + return text_begins(data=self, pattern=pattern, case_sensitive=case_sensitive) + + @openeo_process + def text_concat(self, separator=UNSET) -> ProcessBuilder: + """ + Concatenate elements to a single text + + :param self: A set of elements. Numbers, boolean values and null values get converted to their (lower + case) string representation. For example: `1` (integer), `-1.5` (number), `true` / `false` (boolean + values) + :param separator: A separator to put between each of the individual texts. Defaults to an empty string. + + :return: A string containing a string representation of all the array elements in the same order, with + the separator between each element. + """ + return text_concat(data=self, separator=separator) + + @openeo_process + def text_contains(self, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text contains another text + + :param self: Text in which to find something in. + :param pattern: Text to find in `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` contains the `pattern`, false` otherwise. + """ + return text_contains(data=self, pattern=pattern, case_sensitive=case_sensitive) + + @openeo_process + def text_ends(self, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text ends with another text + + :param self: Text in which to find something at the end. + :param pattern: Text to find at the end of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` ends with `pattern`, false` otherwise. + """ + return text_ends(data=self, pattern=pattern, case_sensitive=case_sensitive) + + @openeo_process + def trim_cube(self) -> ProcessBuilder: + """ + Remove dimension labels with no-data values + + :param self: A raster data cube to trim. + + :return: A trimmed raster data cube with the same dimensions. The dimension properties name, type, + reference system and resolution remain unchanged. The number of dimension labels may decrease. + """ + return trim_cube(data=self) + + @openeo_process + def unflatten_dimension(self, dimension, target_dimensions, label_separator=UNSET) -> ProcessBuilder: + """ + Split a single dimensions into multiple dimensions + + :param self: A data cube that is consistently structured so that operation can execute flawlessly (e.g. + the dimension labels need to contain the `label_separator` exactly 1 time for two target dimensions, 2 + times for three target dimensions etc.). + :param dimension: The name of the dimension to split. + :param target_dimensions: The names of the new target dimensions. New dimensions will be created with + the given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` + exception if any of the dimensions exists. The order of the array defines the order in which the + dimensions and dimension labels are added to the data cube (see the example in the process + description). + :param label_separator: The string that will be used as a separator to split the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system + and resolution) for all other dimensions remain unchanged. + """ + return unflatten_dimension(data=self, dimension=dimension, target_dimensions=target_dimensions, label_separator=label_separator) + + @openeo_process + def variance(self, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Variance + + :param self: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a + value. + + :return: The computed sample variance. + """ + return variance(data=self, ignore_nodata=ignore_nodata) + + @openeo_process + def vector_buffer(self, distance) -> ProcessBuilder: + """ + Buffer geometries by distance + + :param self: Geometries to apply the buffer on. Vector properties are preserved for vector data cubes + and all GeoJSON Features. To 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`). + :param distance: The distance of the buffer in the unit of the spatial reference system. A positive + distance expands the geometries and results in outward buffering (dilation) while a negative distance + shrinks the geometries and results in inward buffering (erosion). + + :return: Returns a vector data cube with the computed new geometries. + """ + return vector_buffer(geometries=self, distance=distance) + + @openeo_process + def vector_to_random_points(self, geometry_count=UNSET, total_count=UNSET, group=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Sample random points from geometries + + :param self: Input geometries for sample extraction. To 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`). + :param geometry_count: The maximum number of points to compute per geometry. Points in the input + geometries can be selected only once by the sampling. + :param total_count: The maximum number of points to compute overall. Throws a `CountMismatch` + exception if the specified value is less than the provided number of geometries. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a + `MultiPoint` per geometry given which keeps the original identifier if present. * Otherwise, each + sampled point is generated as a distinct `Point` geometry without identifier. + :param seed: A randomization seed to use for random sampling. If not given or `null`, no seed is used + and results may differ on subsequent use. + + :return: Returns a vector data cube with the sampled points. + """ + return vector_to_random_points(data=self, geometry_count=geometry_count, total_count=total_count, group=group, seed=seed) + + @openeo_process + def vector_to_regular_points(self, distance, group=UNSET) -> ProcessBuilder: + """ + Sample regular points from geometries + + :param self: Input geometries for sample extraction. To 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`). + :param distance: Defines the minimum distance in the unit of the reference system that is required + between two samples generated *inside* a single geometry. - For **polygons**, the distance defines the + cell sizes of a regular grid that starts at the upper-left bound of each polygon. The centroid of each + cell is then a sample point. If the centroid is not enclosed in the polygon, no point is sampled. If no + point can be sampled for the geometry at all, the first coordinate of the geometry is returned as + point. - For **lines** (line strings), the sampling starts with a point at the first coordinate of the + line and then walks along the line and samples a new point each time the distance to the previous point + has been reached again. - For **points**, the point is returned as given. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a + `MultiPoint` per geometry given which keeps the original identifier if present. * Otherwise, each + sampled point is generated as a distinct `Point` geometry without identifier. + + :return: Returns a vector data cube with the sampled points. + """ + return vector_to_regular_points(data=self, distance=distance, group=group) + + @openeo_process + def xor(self, y) -> ProcessBuilder: + """ + Logical XOR (exclusive or) + + :param self: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical XOR. + """ + return xor(x=self, y=y) + + +# Public shortcut +process = ProcessBuilder.process +# Private shortcut that has lower chance to collide with a process argument named `process` +_process = ProcessBuilder.process + + +@openeo_process +def absolute(x) -> ProcessBuilder: + """ + Absolute value + + :param x: A number. + + :return: The computed absolute value. + """ + return _process('absolute', x=x) + + +@openeo_process +def add(x, y) -> ProcessBuilder: + """ + Addition of two numbers + + :param x: The first summand. + :param y: The second summand. + + :return: The computed sum of the two numbers. + """ + return _process('add', x=x, y=y) + + +@openeo_process +def add_dimension(data, name, label, type=UNSET) -> ProcessBuilder: + """ + Add a new dimension + + :param data: A data cube to add the dimension to. + :param name: Name for the dimension. + :param label: A dimension label. + :param type: The type of dimension, defaults to `other`. + + :return: The data cube with a newly added dimension. The new dimension has exactly one dimension label. All + other dimensions remain unchanged. + """ + return _process('add_dimension', data=data, name=name, label=label, type=type) + + +@openeo_process +def aggregate_spatial(data, geometries, reducer, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for geometries + + :param data: A raster data cube. The 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. 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. + :param geometries: Geometries as GeoJSON on which the aggregation will be based. Vector properties are + preserved for vector data cubes and all GeoJSON Features. One 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. - 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). - For **points**, the process considers + the closest pixel center. - For **lines** (line strings), the process considers all the pixels whose + centers are closest to at least one point on the line. Thus, pixels may be part of multiple geometries and + be part of multiple aggregations. To 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`). + :param reducer: A reducer to be applied on all values of each geometry. 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. + :param target_dimension: The name of a new dimensions that is used to store the results. A new dimension + will be created with the given name and type `other` (see ``add_dimension()``). Defaults to the dimension + name `result`. Fails with a `TargetDimensionExists` exception if a dimension with the specified name + exists. + :param context: Additional data to be passed to the reducer. + + :return: A vector data cube with the computed results and restricted to the bounds of the geometries. The + computed value is used for the dimension with the name that was specified in the parameter + `target_dimension`. The 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`. + """ + return _process('aggregate_spatial', + data=data, + geometries=geometries, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + target_dimension=target_dimension, + context=context + ) + + +@openeo_process +def aggregate_spatial_window(data, reducer, size, boundary=UNSET, align=UNSET, context=UNSET) -> ProcessBuilder: + """ + Zonal statistics for rectangular windows + + :param data: 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. + :param reducer: 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. + :param size: Window size in pixels along the horizontal spatial dimensions. The first value corresponds to + the `x` axis, the second value corresponds to the `y` axis. + :param boundary: 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: - `pad` (default): pad the data cube with + the no-data value `null` to fit the required window size. - `trim`: trim the data cube to fit the required + window size. Set the parameter `align` to specifies to which corner the data is aligned to. + :param align: 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. + :param context: Additional data to be passed to the reducer. + + :return: A data cube with the newly computed values and the same dimensions. The 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. The 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. + """ + return _process('aggregate_spatial_window', + data=data, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + size=size, + boundary=boundary, + align=align, + context=context + ) + + +@openeo_process +def aggregate_temporal(data, intervals, reducer, labels=UNSET, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations + + :param data: A data cube. + :param intervals: Left-closed temporal intervals, which are allowed to overlap. Each temporal interval in + the array has exactly two elements: 1. The first element is the start of the temporal interval. The + specified instance in time is **included** in the interval. 2. The second element is the end of the + temporal interval. The specified instance in time is **excluded** from the interval. The 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. + :param reducer: 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. + :param labels: Distinct labels for the intervals, which can contain dates and/or times. Is only required to + be specified if the values for the start of the temporal intervals are not distinct and thus the default + labels would not be unique. The number of labels and the number of groups need to be equal. + :param dimension: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return _process('aggregate_temporal', + data=data, + intervals=intervals, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + labels=labels, + dimension=dimension, + context=context + ) + + +@openeo_process +def aggregate_temporal_period(data, period, reducer, dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Temporal aggregations based on calendar hierarchies + + :param data: The source data cube. + :param period: The time intervals to aggregate. The following pre-defined values are available: * `hour`: + Hour of the day * `day`: Day of the year * `week`: Week of the year * `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. * `month`: Month + of the year * `season`: Three month periods of the calendar seasons (December - February, March - May, June + - August, September - November). * `tropical-season`: Six month periods of the tropical seasons (November - + April, May - October). * `year`: Proleptic years * `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. * `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. + :param reducer: 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. + :param dimension: 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 source 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. + :param context: Additional data to be passed to the reducer. + + :return: 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): * `hour`: `YYYY-MM-DD-00` - `YYYY-MM- + DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - `YYYY-52` * `dekad`: `YYYY-00` - `YYYY-36` * + `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` (December - February), `YYYY-mam` (March - May), + `YYYY-jja` (June - August), `YYYY-son` (September - November). * `tropical-season`: `YYYY-ndjfma` (November + - April), `YYYY-mjjaso` (May - October). * `year`: `YYYY` * `decade`: `YYY0` * `decade-ad`: `YYY1` The + dimension labels in the new data cube are complete for the whole extent of the source data cube. For + example, if `period` is set to `day` and the source data cube has two dimension labels at the beginning of + the year (`2020-01-01`) and the end of a year (`2020-12-31`), the process returns a data cube with 365 + dimension labels (`2020-001`, `2020-002`, ..., `2020-365`). In contrast, if `period` is set to `day` and + the source data cube has just one dimension label `2020-01-05`, the process returns a data cube with just a + single dimension label (`2020-005`). + """ + return _process('aggregate_temporal_period', + data=data, + period=period, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + ) + + +@openeo_process +def all(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Are all of the values true? + + :param data: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return _process('all', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def and_(x, y) -> ProcessBuilder: + """ + Logical AND + + :param x: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical AND. + """ + return _process('and', x=x, y=y) + + +@openeo_process +def anomaly(data, normals, period) -> ProcessBuilder: + """ + Compute anomalies + + :param data: A data cube with exactly one temporal dimension and the following dimension labels for the + given period (`YYYY` = four-digit year, `MM` = two-digit month, `DD` two-digit day of month): * `hour`: + `YYYY-MM-DD-00` - `YYYY-MM-DD-23` * `day`: `YYYY-001` - `YYYY-365` * `week`: `YYYY-01` - `YYYY-52` * + `dekad`: `YYYY-00` - `YYYY-36` * `month`: `YYYY-01` - `YYYY-12` * `season`: `YYYY-djf` (December - + February), `YYYY-mam` (March - May), `YYYY-jja` (June - August), `YYYY-son` (September - November). * + `tropical-season`: `YYYY-ndjfma` (November - April), `YYYY-mjjaso` (May - October). * `year`: `YYYY` * + `decade`: `YYY0` * `decade-ad`: `YYY1` * `single-period` / `climatology-period`: Any + ``aggregate_temporal_period()`` can compute such a data cube. + :param normals: A data cube with normals, e.g. daily, monthly or yearly values computed from a process such + as ``climatological_normal()``. Must contain exactly one temporal dimension with the following dimension + labels for the given period: * `hour`: `00` - `23` * `day`: `001` - `365` * `week`: `01` - `52` * `dekad`: + `00` - `36` * `month`: `01` - `12` * `season`: `djf` (December - February), `mam` (March - May), `jja` + (June - August), `son` (September - November) * `tropical-season`: `ndjfma` (November - April), `mjjaso` + (May - October) * `year`: Four-digit year numbers * `decade`: Four-digit year numbers, the last digit being + a `0` * `decade-ad`: Four-digit year numbers, the last digit being a `1` * `single-period` / `climatology- + period`: A single dimension label with any name is expected. + :param period: Specifies the time intervals available in the normals data cube. The following options are + available: * `hour`: Hour of the day * `day`: Day of the year * `week`: Week of the year * `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. * `month`: Month of the year * `season`: Three month periods of the calendar seasons (December - + February, March - May, June - August, September - November). * `tropical-season`: Six month periods of the + tropical seasons (November - April, May - October). * `year`: Proleptic years * `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. * `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. * `single-period` / `climatology- + period`: A single period of arbitrary length + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged. + """ + return _process('anomaly', data=data, normals=normals, period=period) + + +@openeo_process +def any(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Is at least one value true? + + :param data: A set of boolean values. + :param ignore_nodata: Indicates whether no-data values are ignored or not and ignores them by default. + + :return: Boolean result of the logical operation. + """ + return _process('any', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def apply(data, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each pixel + + :param data: A data cube. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return _process('apply', data=data, process=build_child_callback(process, parent_parameters=['x', 'context']), context=context) + + +@openeo_process +def apply_dimension(data, process, dimension, target_dimension=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels along a dimension + + :param data: A data cube. + :param process: 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. + :param dimension: The name of the source dimension to apply the process on. Fails with a + `DimensionNotAvailable` exception if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or `null` (the default) to use the source + dimension specified in the parameter `dimension`. By 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. + :param context: Additional data to be passed to the process. + + :return: 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 dimensions can change: 1. + The source dimension is the target dimension: - The (number of) dimensions remain unchanged as the + source dimension is the target dimension. - The source dimension properties name and type remain + unchanged. - 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. 2. The source dimension is + not the target dimension and the latter exists: - The number of dimensions decreases by one as the + source dimension is dropped. - The target dimension properties name and type remain unchanged. All other + dimension properties change as defined in the list below. 3. The source dimension is not the target + dimension and the latter does not exist: - The number of dimensions remain unchanged, but the source + dimension is replaced with the target dimension. - The target dimension has the specified name and the + type other. All other dimension properties are set as defined in the list below. Unless otherwise stated + above, for the given (target) dimension the following applies: - the number of dimension labels is equal + to the number of values computed by the process, - the dimension labels are incrementing integers starting + from zero, - the resolution changes, and - the reference system is undefined. + """ + return _process('apply_dimension', + data=data, + process=build_child_callback(process, parent_parameters=['data', 'context']), + dimension=dimension, + target_dimension=target_dimension, + context=context + ) + + +@openeo_process +def apply_kernel(data, kernel, factor=UNSET, border=UNSET, replace_invalid=UNSET) -> ProcessBuilder: + """ + Apply a spatial convolution with a kernel + + :param data: A data cube. + :param kernel: 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. + :param factor: A factor that is multiplied to each value after the kernel has been applied. This is + basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often required + for some kernel-based algorithms such as the Gaussian blur. + :param border: Determines how the data is extended when the kernel overlaps with the borders. Defaults to + fill the border with zeroes. The following options are available: * *numeric value* - fill with a user- + defined constant number `n`: `nnnnnn|abcdefgh|nnnnnn` (default, with `n` = 0) * `replicate` - repeat the + value from the pixel at the border: `aaaaaa|abcdefgh|hhhhhh` * `reflect` - mirror/reflect from the border: + `fedcba|abcdefgh|hgfedc` * `reflect_pixel` - mirror/reflect from the center of the pixel at the border: + `gfedcb|abcdefgh|gfedcb` * `wrap` - repeat/wrap the image: `cdefgh|abcdefgh|abcdef` + :param replace_invalid: This parameter specifies the value to replace non-numerical or infinite numerical + values with. By default, those values are replaced with zeroes. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return _process('apply_kernel', data=data, kernel=kernel, factor=factor, border=border, replace_invalid=replace_invalid) + + +@openeo_process +def apply_neighborhood(data, process, size, overlap=UNSET, context=UNSET) -> ProcessBuilder: + """ + Apply a process to pixels in a n-dimensional neighborhood + + :param data: A data cube. + :param process: Process to be applied on all neighborhoods. + :param size: Neighborhood sizes along each dimension. This 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. + :param overlap: Overlap of neighborhoods along each dimension to avoid border effects. By default no + overlap is provided. For 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. Be aware that + large overlaps increase the need for computational resources and modifying overlapping data in subsequent + operations have no effect. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. The dimension properties + (name, type, labels, reference system and resolution) remain unchanged. + """ + return _process('apply_neighborhood', + data=data, + process=build_child_callback(process, parent_parameters=['data', 'context']), + size=size, + overlap=overlap, + context=context + ) + + +@openeo_process +def arccos(x) -> ProcessBuilder: + """ + Inverse cosine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arccos', x=x) + + +@openeo_process +def arcosh(x) -> ProcessBuilder: + """ + Inverse hyperbolic cosine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arcosh', x=x) + + +@openeo_process +def arcsin(x) -> ProcessBuilder: + """ + Inverse sine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arcsin', x=x) + + +@openeo_process +def arctan(x) -> ProcessBuilder: + """ + Inverse tangent + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arctan', x=x) + + +@openeo_process +def arctan2(y, x) -> ProcessBuilder: + """ + Inverse tangent of two numbers + + :param y: A number to be used as the dividend. + :param x: A number to be used as the divisor. + + :return: The computed angle in radians. + """ + return _process('arctan2', y=y, x=x) + + +@openeo_process +def ard_normalized_radar_backscatter(data, elevation_model=UNSET, contributing_area=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant SAR NRB generation + + :param data: The source data cube containing SAR input. + :param elevation_model: 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. + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options will + reduce portability. + + :return: Backscatter values expressed as gamma0 in linear scale. In 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: - `mask`: A data mask that indicates + which values are valid (1), invalid (0) or contain no-data (null). - `local_incidence_angle`: A band with + DEM-based local incidence angles in degrees. The data returned is CARD4L compliant with corresponding + metadata. + """ + return _process('ard_normalized_radar_backscatter', + data=data, + elevation_model=elevation_model, + contributing_area=contributing_area, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + ) + + +@openeo_process +def ard_surface_reflectance(data, atmospheric_correction_method, cloud_detection_method, elevation_model=UNSET, atmospheric_correction_options=UNSET, cloud_detection_options=UNSET) -> ProcessBuilder: + """ + CARD4L compliant Surface Reflectance generation + + :param data: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances. There must be a single dimension of type `bands` available. + :param atmospheric_correction_method: The atmospheric correction method to use. + :param cloud_detection_method: The cloud detection method to use. Each method supports detecting different + atmospheric disturbances such as clouds, cloud shadows, aerosols, haze, ozone and/or water vapour in + optical imagery. + :param elevation_model: 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. + :param atmospheric_correction_options: Proprietary options for the atmospheric correction method. + Specifying proprietary options will reduce portability. + :param cloud_detection_options: Proprietary options for the cloud detection method. Specifying proprietary + options will reduce portability. + + :return: 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: 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. Depending on the methods + used, several additional bands will be added to the data cube: - `date` (optional): Specifies per-pixel + acquisition timestamps. - `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. - `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. - `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. - `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. + - `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. - `incidence-angle` (optional): Specifies per-pixel + incidence angles in degrees. - `azimuth` (optional): Specifies per-pixel azimuth angles in degrees. - `sun- + azimuth:` (optional): Specifies per-pixel sun azimuth angles in degrees. - `sun-elevation` (optional): + Specifies per-pixel sun elevation angles in degrees. - `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. - + `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. - `terrain-illumination` + (optional): Contains coefficients used for terrain illumination correction are provided for each pixel. + The data returned is CARD4L compliant with corresponding metadata. + """ + return _process('ard_surface_reflectance', + data=data, + atmospheric_correction_method=atmospheric_correction_method, + cloud_detection_method=cloud_detection_method, + elevation_model=elevation_model, + atmospheric_correction_options=atmospheric_correction_options, + cloud_detection_options=cloud_detection_options + ) + + +@openeo_process +def array_append(data, value, label=UNSET) -> ProcessBuilder: + """ + Append a value to an array + + :param data: An array. + :param value: Value to append to the array. + :param label: If the given array is a labeled array, a new label for the new value should be given. If not + given or `null`, the array index as string is used as the label. If in any case the label exists, a + `LabelExists` exception is thrown. + + :return: The new array with the value being appended. + """ + return _process('array_append', data=data, value=value, label=label) + + +@openeo_process +def array_apply(data, process, context=UNSET) -> ProcessBuilder: + """ + Apply a process to each array element + + :param data: An array. + :param process: 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 ``absolute()`` or ``linear_scale_range()``. + :param context: Additional data to be passed to the process. + + :return: An array with the newly computed values. The number of elements are the same as for the original + array. + """ + return _process('array_apply', + data=data, + process=build_child_callback(process, parent_parameters=['x', 'index', 'label', 'context']), + context=context + ) + + +@openeo_process +def array_concat(array1, array2) -> ProcessBuilder: + """ + Merge two arrays + + :param array1: The first array. + :param array2: The second array. + + :return: The merged array. + """ + return _process('array_concat', array1=array1, array2=array2) + + +@openeo_process +def array_contains(data, value) -> ProcessBuilder: + """ + Check whether the array contains a given value + + :param data: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `false`. + + :return: `true` if the list contains the value, false` otherwise. + """ + return _process('array_contains', data=data, value=value) + + +@openeo_process +def array_create(data=UNSET, repeat=UNSET) -> ProcessBuilder: + """ + Create an array + + :param data: A (native) array to fill the newly created array with. Defaults to an empty array. + :param repeat: 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`. + + :return: The newly created array. + """ + return _process('array_create', data=data, repeat=repeat) + + +@openeo_process +def array_create_labeled(data, labels) -> ProcessBuilder: + """ + Create a labeled array + + :param data: An array of values to be used. + :param labels: An array of labels to be used. + + :return: The newly created labeled array. + """ + return _process('array_create_labeled', data=data, labels=labels) + + +@openeo_process +def array_element(data, index=UNSET, label=UNSET, return_nodata=UNSET) -> ProcessBuilder: + """ + Get an element from an array + + :param data: An array. + :param index: The zero-based index of the element to retrieve. + :param label: 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. + :param return_nodata: By default this process throws an `ArrayElementNotAvailable` exception if the index + or label is invalid. If you want to return `null` instead, set this flag to `true`. + + :return: The value of the requested element. + """ + return _process('array_element', data=data, index=index, label=label, return_nodata=return_nodata) + + +@openeo_process +def array_filter(data, condition, context=UNSET) -> ProcessBuilder: + """ + Filter an array based on a condition + + :param data: An array. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: An array filtered by the specified condition. The number of elements are less than or equal + compared to the original array. + """ + return _process('array_filter', + data=data, + condition=build_child_callback(condition, parent_parameters=['x', 'index', 'label', 'context']), + context=context + ) + + +@openeo_process +def array_find(data, value, reverse=UNSET) -> ProcessBuilder: + """ + Get the index for a value in an array + + :param data: List to find the value in. + :param value: Value to find in `data`. If the value is `null`, this process returns always `null`. + :param reverse: By default, this process finds the index of the first match. To return the index of the + last match instead, set this flag to `true`. + + :return: The index of the first element with the specified value. If no element was found, `null` is + returned. + """ + return _process('array_find', data=data, value=value, reverse=reverse) + + +@openeo_process +def array_find_label(data, label) -> ProcessBuilder: + """ + Get the index for a label in a labeled array + + :param data: List to find the label in. + :param label: Label to find in `data`. + + :return: The index of the element with the specified label assigned. If no such label was found, `null` is + returned. + """ + return _process('array_find_label', data=data, label=label) + + +@openeo_process +def array_interpolate_linear(data) -> ProcessBuilder: + """ + One-dimensional linear interpolation for arrays + + :param data: An array of numbers and no-data values. If 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. + + :return: 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. + """ + return _process('array_interpolate_linear', data=data) + + +@openeo_process +def array_labels(data) -> ProcessBuilder: + """ + Get the labels for an array + + :param data: An array. + + :return: The labels or indices as array. + """ + return _process('array_labels', data=data) + + +@openeo_process +def array_modify(data, values, index, length=UNSET) -> ProcessBuilder: + """ + Change the content of an array (remove, insert, update) + + :param data: The array to modify. + :param values: The values to insert into the `data` array. + :param index: The index in the `data` array of the element to insert the value(s) before. If the index is + greater than the number of elements in the `data` array, the process throws an `ArrayElementNotAvailable` + exception. To insert after the last element, there are two options: 1. Use the simpler processes + ``array_append()`` to append a single value or ``array_concat()`` to append multiple values. 2. 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`. + :param length: The number of elements in the `data` array to remove (or replace) starting from the given + index. If the array contains fewer elements, the process simply removes all elements up to the end. + + :return: An array with values added, updated or removed. + """ + return _process('array_modify', data=data, values=values, index=index, length=length) + + +@openeo_process +def arsinh(x) -> ProcessBuilder: + """ + Inverse hyperbolic sine + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('arsinh', x=x) + + +@openeo_process +def artanh(x) -> ProcessBuilder: + """ + Inverse hyperbolic tangent + + :param x: A number. + + :return: The computed angle in radians. + """ + return _process('artanh', x=x) + + +@openeo_process +def atmospheric_correction(data, method, elevation_model=UNSET, options=UNSET) -> ProcessBuilder: + """ + Apply atmospheric correction + + :param data: Data cube containing multi-spectral optical top of atmosphere reflectances to be corrected. + :param method: The atmospheric correction method to use. To get reproducible results, you have to set a + specific method. Set 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. + :param elevation_model: 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. + :param options: Proprietary options for the atmospheric correction method. Specifying proprietary options + will reduce portability. + + :return: Data cube containing bottom of atmosphere reflectances. + """ + return _process('atmospheric_correction', data=data, method=method, elevation_model=elevation_model, options=options) + + +@openeo_process +def between(x, min, max, exclude_max=UNSET) -> ProcessBuilder: + """ + Between comparison + + :param x: The value to check. + :param min: Lower boundary (inclusive) to check against. + :param max: Upper boundary (inclusive) to check against. + :param exclude_max: Exclude the upper boundary `max` if set to `true`. Defaults to `false`. + + :return: `true` if `x` is between the specified bounds, otherwise `false`. + """ + return _process('between', x=x, min=min, max=max, exclude_max=exclude_max) + + +@openeo_process +def ceil(x) -> ProcessBuilder: + """ + Round fractions up + + :param x: A number to round up. + + :return: The number rounded up. + """ + return _process('ceil', x=x) + + +@openeo_process +def climatological_normal(data, period, climatology_period=UNSET) -> ProcessBuilder: + """ + Compute climatology normals + + :param data: A data cube with exactly one temporal dimension. The data cube must span at least the temporal + interval specified in the parameter `climatology-period`. Seasonal periods may span two consecutive years, + e.g. temporal winter that includes months December, January and February. If the required months before the + actual climate period are available, the season is taken into account. If not available, the first season + is not taken into account and the seasonal mean is based on one year less than the other seasonal normals. + The incomplete season at the end of the last year is never taken into account. + :param period: The time intervals to aggregate the average value for. The following pre-defined frequencies + are supported: * `day`: Day of the year * `month`: Month of the year * `climatology-period`: The period + specified in the `climatology-period`. * `season`: Three month periods of the calendar seasons (December - + February, March - May, June - August, September - November). * `tropical-season`: Six month periods of the + tropical seasons (November - April, May - October). + :param climatology_period: 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). + + :return: 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 temporal + dimension. The temporal dimension has the following dimension labels: * `day`: `001` - `365` * `month`: + `01` - `12` * `climatology-period`: `climatology-period` * `season`: `djf` (December - February), `mam` + (March - May), `jja` (June - August), `son` (September - November) * `tropical-season`: `ndjfma` (November + - April), `mjjaso` (May - October) + """ + return _process('climatological_normal', data=data, period=period, climatology_period=climatology_period) + + +@openeo_process +def clip(x, min, max) -> ProcessBuilder: + """ + Clip a value between a minimum and a maximum + + :param x: A number. + :param min: Minimum value. If the value is lower than this value, the process will return the value of this + parameter. + :param max: Maximum value. If the value is greater than this value, the process will return the value of + this parameter. + + :return: The value clipped to the specified range. + """ + return _process('clip', x=x, min=min, max=max) + + +@openeo_process +def cloud_detection(data, method, options=UNSET) -> ProcessBuilder: + """ + Create cloud masks + + :param data: The source data cube containing multi-spectral optical top of the atmosphere (TOA) + reflectances on which to perform cloud detection. + :param method: The cloud detection method to use. To get reproducible results, you have to set a specific + method. Set 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. + :param options: Proprietary options for the cloud detection method. Specifying proprietary options will + reduce portability. + + :return: 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. + """ + return _process('cloud_detection', data=data, method=method, options=options) + + +@openeo_process +def constant(x) -> ProcessBuilder: + """ + Define a constant value + + :param x: The value of the constant. + + :return: The value of the constant. + """ + return _process('constant', x=x) + + +@openeo_process +def cos(x) -> ProcessBuilder: + """ + Cosine + + :param x: An angle in radians. + + :return: The computed cosine of `x`. + """ + return _process('cos', x=x) + + +@openeo_process +def cosh(x) -> ProcessBuilder: + """ + Hyperbolic cosine + + :param x: An angle in radians. + + :return: The computed hyperbolic cosine of `x`. + """ + return _process('cosh', x=x) + + +@openeo_process +def count(data, condition=UNSET, context=UNSET) -> ProcessBuilder: + """ + Count the number of elements + + :param data: An array with elements of any data type. + :param condition: 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. + :param context: Additional data to be passed to the condition. + + :return: The counted number of elements. + """ + return _process('count', data=data, condition=condition, context=context) + + +@openeo_process +def create_raster_cube() -> ProcessBuilder: + """ + Create an empty raster data cube + + :return: An empty raster data cube with zero dimensions. + """ + return _process('create_raster_cube', ) + + +@openeo_process +def cummax(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative maxima + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative maxima. + """ + return _process('cummax', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def cummin(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative minima + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative minima. + """ + return _process('cummin', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def cumproduct(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative products + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative products. + """ + return _process('cumproduct', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def cumsum(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Cumulative sums + + :param data: An array of numbers. + :param ignore_nodata: 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. + + :return: An array with the computed cumulative sums. + """ + return _process('cumsum', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def date_shift(date, value, unit) -> ProcessBuilder: + """ + Manipulates dates and times by addition or subtraction + + :param date: The date (and optionally time) to manipulate. If 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. + :param value: 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. + :param unit: The unit for the value given. The following pre-defined units are available: - millisecond: + Milliseconds - second: Seconds - leap seconds are ignored in computations. - minute: Minutes - hour: Hours + - day: Days - changes only the the day part of a date - week: Weeks (equivalent to 7 days) - month: Months + - year: Years Manipulations 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`. + + :return: The manipulated date. If a time component was given in the parameter `date`, the time component is + returned with the date. + """ + return _process('date_shift', date=date, value=value, unit=unit) + + +@openeo_process +def dimension_labels(data, dimension) -> ProcessBuilder: + """ + Get the dimension labels + + :param data: The data cube. + :param dimension: The name of the dimension to get the labels for. + + :return: The labels as an array. + """ + return _process('dimension_labels', data=data, dimension=dimension) + + +@openeo_process +def divide(x, y) -> ProcessBuilder: + """ + Division of two numbers + + :param x: The dividend. + :param y: The divisor. + + :return: The computed result. + """ + return _process('divide', x=x, y=y) + + +@openeo_process +def drop_dimension(data, name) -> ProcessBuilder: + """ + Remove a dimension + + :param data: The data cube to drop a dimension from. + :param name: Name of the dimension to drop. + + :return: A data cube without the specified dimension. The number of dimensions decreases by one, but the + dimension properties (name, type, labels, reference system and resolution) for all other dimensions remain + unchanged. + """ + return _process('drop_dimension', data=data, name=name) + + +@openeo_process +def e() -> ProcessBuilder: + """ + Euler's number (e) + + :return: The numerical value of Euler's number. + """ + return _process('e', ) + + +@openeo_process +def eq(x, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Equal to comparison + + :param x: First operand. + :param y: Second operand. + :param delta: 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. This option is basically + an alias for the following computation: `lte(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be disabled + by setting this parameter to `false`. + + :return: `true` if `x` is equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('eq', x=x, y=y, delta=delta, case_sensitive=case_sensitive) + + +@openeo_process +def exp(p) -> ProcessBuilder: + """ + Exponentiation to the base e + + :param p: The numerical exponent. + + :return: The computed value for *e* raised to the power of `p`. + """ + return _process('exp', p=p) + + +@openeo_process +def extrema(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum and maximum values + + :param data: An array of numbers. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. Setting + this flag to `false` considers no-data values so that an array with two `null` values is returned if any + value is such a value. + + :return: An array containing the minimum and maximum values for the specified numbers. The first element is + the minimum, the second element is the maximum. If the input array is empty both elements are set to + `null`. + """ + return _process('extrema', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def filter_bands(data, bands=UNSET, wavelengths=UNSET) -> ProcessBuilder: + """ + Filter the bands by names + + :param data: A data cube with bands. + :param bands: 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. The 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. + :param wavelengths: 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). The 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. + + :return: A data cube limited to a subset of its original bands. The dimensions and dimension properties + (name, type, labels, reference system and resolution) remain unchanged, except that the dimension of type + `bands` has less (or the same) dimension labels. + """ + return _process('filter_bands', data=data, bands=bands, wavelengths=wavelengths) + + +@openeo_process +def filter_bbox(data, extent) -> ProcessBuilder: + """ + Spatial filter using a bounding box + + :param data: A data cube. + :param extent: A bounding box, which may include a vertical axis (see `base` and `height`). + + :return: A data cube restricted to the bounding box. The dimensions and dimension properties (name, type, + labels, reference system and resolution) remain unchanged, except that the spatial dimensions have less (or + the same) dimension labels. + """ + return _process('filter_bbox', data=data, extent=extent) + + +@openeo_process +def filter_labels(data, condition, dimension, context=UNSET) -> ProcessBuilder: + """ + Filter dimension labels based on a condition + + :param data: A data cube. + :param condition: A condition that is evaluated against each dimension label in the specified dimension. A + dimension label and the corresponding data is preserved for the given dimension, if the condition returns + `true`. + :param dimension: The name of the dimension to filter on. Fails with a `DimensionNotAvailable` exception if + the specified dimension does not exist. + :param context: Additional data to be passed to the condition. + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged, except that the given dimension has less (or the same) dimension + labels. + """ + return _process('filter_labels', + data=data, + condition=build_child_callback(condition, parent_parameters=['value', 'context']), + dimension=dimension, + context=context + ) + + +@openeo_process +def filter_spatial(data, geometries) -> ProcessBuilder: + """ + Spatial filter using geometries + + :param data: A data cube. + :param geometries: One or more geometries used for filtering, specified as GeoJSON. + + :return: A data cube restricted to the specified geometries. The dimensions and dimension properties (name, + type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions have + less (or the same) dimension labels. + """ + return _process('filter_spatial', data=data, geometries=geometries) + + +@openeo_process +def filter_temporal(data, extent, dimension=UNSET) -> ProcessBuilder: + """ + Temporal filter based on temporal intervals + + :param data: A data cube. + :param extent: Left-closed temporal interval, i.e. an array with exactly two elements: 1. The first + element is the start of the temporal interval. The specified instance in time is **included** in the + interval. 2. The second element is the end of the temporal interval. The specified instance in time is + **excluded** from the interval. The 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. + :param dimension: 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. + + :return: 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. + """ + return _process('filter_temporal', data=data, extent=extent, dimension=dimension) + + +@openeo_process +def first(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + First element + + :param data: An array with elements of any data type. + :param ignore_nodata: 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 returned if the first value is such a + value. + + :return: The first element of the input array. + """ + return _process('first', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def fit_class_random_forest(predictors, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest classification model + + :param predictors: The predictors for the classification model as a vector data cube. Aggregated to the + features (vectors) of the target input variable. + :param target: The training sites for the classification model as a vector data cube. This is associated + with the target variable for the Random Forest model. The geometry has to associated with a value to + predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options are + available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables are + considered for each split. - `onethird`: A third of the number of variables are considered for each split. + - `sqrt`: The square root of the number of variables are considered for each split. This is often the + default for classification. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, no + seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with ``load_ml_model()``. + """ + return _process('fit_class_random_forest', predictors=predictors, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed) + + +@openeo_process +def fit_curve(data, parameters, function, dimension) -> ProcessBuilder: + """ + Curve fitting + + :param data: A data cube. + :param parameters: Defined the number of parameters for the model function and provides an initial guess + for them. At least one parameter is required. + :param function: The model function. It must take the parameters to fit as array through the first argument + and the independent variable `x` as the second argument. It is recommended to store the model function as + a user-defined process on the back-end to be able to re-use the model function with the computed optimal + values for the parameters afterwards. + :param dimension: The name of the dimension for curve fitting. Must be a dimension with labels that have a + order (i.e. numerical labels or a temporal dimension). Fails with a `DimensionNotAvailable` exception if + the specified dimension does not exist. + + :return: A data cube with the optimal values for the parameters. + """ + return _process('fit_curve', + data=data, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension + ) + + +@openeo_process +def fit_regr_random_forest(predictors, target, max_variables, num_trees=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Train a random forest regression model + + :param predictors: The predictors for the regression model as a vector data cube. Aggregated to the + features (vectors) of the target input variable. + :param target: The training sites for the regression model as a vector data cube. This is associated with + the target variable for the Random Forest model. The geometry has to associated with a value to predict + (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. The following options are + available: - *integer*: The given number of variables are considered for each split. - `all`: All + variables are considered for each split. - `log2`: The logarithm with base 2 of the number of variables are + considered for each split. - `onethird`: A third of the number of variables are considered for each split. + This is often the default for regression. - `sqrt`: The square root of the number of variables are + considered for each split. + :param num_trees: The number of trees build within the Random Forest regression. + :param seed: A randomization seed to use for the random sampling in training. If not given or `null`, no + seed is used and results may differ on subsequent use. + + :return: A model object that can be saved with ``save_ml_model()`` and restored with ``load_ml_model()``. + """ + return _process('fit_regr_random_forest', predictors=predictors, target=target, max_variables=max_variables, num_trees=num_trees, seed=seed) + + +@openeo_process +def flatten_dimensions(data, dimensions, target_dimension, label_separator=UNSET) -> ProcessBuilder: + """ + Combine multiple dimensions into a single dimension + + :param data: A data cube. + :param dimensions: The names of the dimension to combine. The order of the array defines the order in which + the dimension labels and values are combined (see the example in the process description). Fails with a + `DimensionNotAvailable` exception if at least one of the specified dimensions does not exist. + :param target_dimension: The name of the new target dimension. A new dimensions will be created with the + given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` exception if a + dimension with the specified name exists. + :param label_separator: The string that will be used as a separator for the concatenated dimension labels. + To unambiguously revert the dimension labels with the process ``unflatten_dimension()``, the given string + must not be contained in any of the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system and + resolution) for all other dimensions remain unchanged. + """ + return _process('flatten_dimensions', data=data, dimensions=dimensions, target_dimension=target_dimension, label_separator=label_separator) + + +@openeo_process +def floor(x) -> ProcessBuilder: + """ + Round fractions down + + :param x: A number to round down. + + :return: The number rounded down. + """ + return _process('floor', x=x) + + +@openeo_process +def gt(x, y) -> ProcessBuilder: + """ + Greater than comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly greater than `y` or `null` if any operand is `null`, otherwise `false`. + """ + return _process('gt', x=x, y=y) + + +@openeo_process +def gte(x, y) -> ProcessBuilder: + """ + Greater than or equal to comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is greater than or equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('gte', x=x, y=y) + + +@openeo_process +def if_(value, accept, reject=UNSET) -> ProcessBuilder: + """ + If-Then-Else conditional + + :param value: A boolean value. + :param accept: A value that is returned if the boolean value is `true`. + :param reject: A value that is returned if the boolean value is **not** `true`. Defaults to `null`. + + :return: Either the `accept` or `reject` argument depending on the given boolean value. + """ + return _process('if', value=value, accept=accept, reject=reject) + + +@openeo_process +def inspect(data, code=UNSET, level=UNSET, message=UNSET) -> ProcessBuilder: + """ + Add information to the logs + + :param data: Data to log. + :param code: A label to help identify one or more log entries originating from this process in the list of + all log entries. It can help to group or filter log entries and is usually not unique. + :param level: The severity level of this message, defaults to `info`. + :param message: A message to send in addition to the data. + + :return: The data as passed to the `data` parameter without any modification. + """ + return _process('inspect', data=data, code=code, level=level, message=message) + + +@openeo_process +def int(x) -> ProcessBuilder: + """ + Integer part of a number + + :param x: A number. + + :return: Integer part of the number. + """ + return _process('int', x=x) + + +@openeo_process +def is_infinite(x) -> ProcessBuilder: + """ + Value is an infinite number + + :param x: The data to check. + + :return: `true` if the data is an infinite number, otherwise `false`. + """ + return _process('is_infinite', x=x) + + +@openeo_process +def is_nan(x) -> ProcessBuilder: + """ + Value is not a number + + :param x: The data to check. + + :return: `true` if the data is not a number, otherwise `false`. + """ + return _process('is_nan', x=x) + + +@openeo_process +def is_nodata(x) -> ProcessBuilder: + """ + Value is a no-data value + + :param x: The data to check. + + :return: `true` if the data is a no-data value, otherwise `false`. + """ + return _process('is_nodata', x=x) + + +@openeo_process +def is_valid(x) -> ProcessBuilder: + """ + Value is valid data + + :param x: The data to check. + + :return: `true` if the data is valid, otherwise `false`. + """ + return _process('is_valid', x=x) + + +@openeo_process +def last(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Last element + + :param data: An array with elements of any data type. + :param ignore_nodata: 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 returned if the last value is such a value. + + :return: The last element of the input array. + """ + return _process('last', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def linear_scale_range(x, inputMin, inputMax, outputMin=UNSET, outputMax=UNSET) -> ProcessBuilder: + """ + Linear transformation between two ranges + + :param x: A number to transform. The number gets clipped to the bounds specified in `inputMin` and + `inputMax`. + :param inputMin: Minimum value the input can obtain. + :param inputMax: Maximum value the input can obtain. + :param outputMin: Minimum value of the desired output range. + :param outputMax: Maximum value of the desired output range. + + :return: The transformed number. + """ + return _process('linear_scale_range', x=x, inputMin=inputMin, inputMax=inputMax, outputMin=outputMin, outputMax=outputMax) + + +@openeo_process +def ln(x) -> ProcessBuilder: + """ + Natural logarithm + + :param x: A number to compute the natural logarithm for. + + :return: The computed natural logarithm. + """ + return _process('ln', x=x) + + +@openeo_process +def load_collection(id, spatial_extent, temporal_extent, bands=UNSET, properties=UNSET) -> ProcessBuilder: + """ + Load a collection + + :param id: The collection id. + :param spatial_extent: Limits the data to load from the collection to the specified bounding box or + polygons. The 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). The GeoJSON + can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a + `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one `Feature` with + `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` + geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of the + alternatives above. Set 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. + :param temporal_extent: 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: 1. The first element is the start of the temporal interval. The specified instance in time is + **included** in the interval. 2. The second element is the end of the temporal interval. The specified + instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is recommended to use + this parameter instead of using ``filter_bands()`` directly after loading unbounded data. + :param properties: Limits the data by metadata properties to include only data in the data cube which all + given conditions return `true` for (AND operation). Specify key-value-pairs with the key being the name of + the metadata property, which can be retrieved with the openEO Data Discovery for Collections. The value + must be a condition (user-defined process) to be evaluated against the collection metadata, see the + example. + + :return: A data cube for further processing. The dimensions and dimension properties (name, type, labels, + reference system and resolution) correspond to the collection's metadata, but the dimension labels are + restricted as specified in the parameters. + """ + return _process('load_collection', id=id, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands, properties=properties) + + +@openeo_process +def load_ml_model(id) -> ProcessBuilder: + """ + Load a ML model + + :param id: The STAC Item to load the machine learning model from. The STAC Item must implement the `ml- + model` extension. + + :return: A machine learning model to be used with machine learning processes such as + ``predict_random_forest()``. + """ + return _process('load_ml_model', id=id) + + +@openeo_process +def load_result(id, spatial_extent=UNSET, temporal_extent=UNSET, bands=UNSET) -> ProcessBuilder: + """ + Load batch job results + + :param id: The id of a batch job with results. + :param spatial_extent: Limits the data to load from the batch job result to the specified bounding box or + polygons. The 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). The GeoJSON + can be one of the following feature types: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a + `Polygon` or `MultiPolygon` geometry, * a `FeatureCollection` containing at least one `Feature` with + `Polygon` or `MultiPolygon` geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` + geometries. To maximize interoperability, `GeometryCollection` should be avoided in favour of one of the + alternatives above. Set 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. + :param temporal_extent: Limits the data to load from the batch job result 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: 1. The first element is the start of the temporal interval. The specified instance + in time is **included** in the interval. 2. The second element is the end of the temporal interval. The + specified instance in time is **excluded** from the interval. The 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. Set 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. + :param bands: 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`. Either 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. The 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. It is recommended to use + this parameter instead of using ``filter_bands()`` directly after loading unbounded data. + + :return: A data cube for further processing. + """ + return _process('load_result', id=id, spatial_extent=spatial_extent, temporal_extent=temporal_extent, bands=bands) + + +@openeo_process +def load_uploaded_files(paths, format, options=UNSET) -> ProcessBuilder: + """ + Load files from the user workspace + + :param paths: The files to read. Folders can't be specified, specify all files instead. An exception is + thrown if a file can't be read. + :param format: The file format to read from. It must be one of the values that the server reports as + supported input file formats, which usually correspond to the short GDAL/OGR codes. If the format is not + suitable for loading the data, a `FormatUnsuitable` exception will be thrown. This parameter is *case + insensitive*. + :param options: The file format parameters to be used to read the files. Must correspond to the parameters + that the server reports as supported parameters for the chosen `format`. The parameter names and valid + values usually correspond to the GDAL/OGR format options. + + :return: A data cube for further processing. + """ + return _process('load_uploaded_files', paths=paths, format=format, options=options) + + +@openeo_process +def log(x, base) -> ProcessBuilder: + """ + Logarithm to a base + + :param x: A number to compute the logarithm for. + :param base: The numerical base. + + :return: The computed logarithm. + """ + return _process('log', x=x, base=base) + + +@openeo_process +def lt(x, y) -> ProcessBuilder: + """ + Less than comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is strictly less than `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('lt', x=x, y=y) + + +@openeo_process +def lte(x, y) -> ProcessBuilder: + """ + Less than or equal to comparison + + :param x: First operand. + :param y: Second operand. + + :return: `true` if `x` is less than or equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('lte', x=x, y=y) + + +@openeo_process +def mask(data, mask, replacement=UNSET) -> ProcessBuilder: + """ + Apply a raster mask + + :param data: A raster data cube. + :param mask: A mask as a raster data cube. Every pixel in `data` must have a corresponding element in + `mask`. + :param replacement: The value used to replace masked values with. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, labels, + reference system and resolution) remain unchanged. + """ + return _process('mask', data=data, mask=mask, replacement=replacement) + + +@openeo_process +def mask_polygon(data, mask, replacement=UNSET, inside=UNSET) -> ProcessBuilder: + """ + Apply a polygon mask + + :param data: A raster data cube. + :param mask: A GeoJSON object containing at least one polygon. The provided feature types can be one of the + following: * A `Polygon` or `MultiPolygon` geometry, * a `Feature` with a `Polygon` or `MultiPolygon` + geometry, * a `FeatureCollection` containing at least one `Feature` with `Polygon` or `MultiPolygon` + geometries, or * a `GeometryCollection` containing `Polygon` or `MultiPolygon` geometries. To maximize + interoperability, `GeometryCollection` should be avoided in favour of one of the alternatives above. + :param replacement: The value used to replace masked values with. + :param inside: If set to `true` all pixels for which the point at the pixel center **does** intersect with + any polygon are replaced. + + :return: A masked raster data cube with the same dimensions. The dimension properties (name, type, labels, + reference system and resolution) remain unchanged. + """ + return _process('mask_polygon', data=data, mask=mask, replacement=replacement, inside=inside) + + +@openeo_process +def max(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Maximum value + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The maximum value. + """ + return _process('max', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def mean(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Arithmetic mean (average) + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed arithmetic mean. + """ + return _process('mean', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def median(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Statistical median + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed statistical median. + """ + return _process('median', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def merge_cubes(cube1, cube2, overlap_resolver=UNSET, context=UNSET) -> ProcessBuilder: + """ + Merge two data cubes + + :param cube1: The first data cube. + :param cube2: The second data cube. + :param overlap_resolver: A reduction operator that resolves the conflict if the data overlaps. The reducer + must return a value of the same data type as the input values are. The reduction operator may be a single + process such as ``multiply()`` or consist of multiple sub-processes. `null` (the default) can be specified + if no overlap resolver is required. + :param context: Additional data to be passed to the overlap resolver. + + :return: The merged data cube. See the process description for details regarding the dimensions and + dimension properties (name, type, labels, reference system and resolution). + """ + return _process('merge_cubes', + cube1=cube1, + cube2=cube2, + overlap_resolver=build_child_callback(overlap_resolver, parent_parameters=['x', 'y', 'context']), + context=context + ) + + +@openeo_process +def min(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Minimum value + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The minimum value. + """ + return _process('min', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def mod(x, y) -> ProcessBuilder: + """ + Modulo + + :param x: A number to be used as the dividend. + :param y: A number to be used as the divisor. + + :return: The remainder after division. + """ + return _process('mod', x=x, y=y) + + +@openeo_process +def multiply(x, y) -> ProcessBuilder: + """ + Multiplication of two numbers + + :param x: The multiplier. + :param y: The multiplicand. + + :return: The computed product of the two numbers. + """ + return _process('multiply', x=x, y=y) + + +@openeo_process +def nan() -> ProcessBuilder: + """ + Not a Number (NaN) + + :return: Returns `NaN`. + """ + return _process('nan', ) + + +@openeo_process +def ndvi(data, nir=UNSET, red=UNSET, target_band=UNSET) -> ProcessBuilder: + """ + Normalized Difference Vegetation Index + + :param data: A raster data cube with two bands that have the common names `red` and `nir` assigned. + :param nir: The name of the NIR band. Defaults to the band that has the common name `nir` assigned. Either + 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. + :param red: The name of the red band. Defaults to the band that has the common name `red` assigned. Either + 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. + :param target_band: By default, the dimension of type `bands` is dropped. To keep the dimension specify a + new band name in this parameter so that a new dimension label with the specified name will be added for the + computed values. + + :return: A raster data cube containing the computed NDVI values. The structure of the data cube differs + depending on the value passed to `target_band`: * `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. * `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`. + """ + return _process('ndvi', data=data, nir=nir, red=red, target_band=target_band) + + +@openeo_process +def neq(x, y, delta=UNSET, case_sensitive=UNSET) -> ProcessBuilder: + """ + Not equal to comparison + + :param x: First operand. + :param y: Second operand. + :param delta: 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. This option is + basically an alias for the following computation: `gt(abs(minus([x, y]), delta)` + :param case_sensitive: Only applicable for comparing two strings. Case sensitive comparison can be disabled + by setting this parameter to `false`. + + :return: `true` if `x` is *not* equal to `y`, `null` if any operand is `null`, otherwise `false`. + """ + return _process('neq', x=x, y=y, delta=delta, case_sensitive=case_sensitive) + + +@openeo_process +def normalized_difference(x, y) -> ProcessBuilder: + """ + Normalized difference + + :param x: The value for the first band. + :param y: The value for the second band. + + :return: The computed normalized difference. + """ + return _process('normalized_difference', x=x, y=y) + + +@openeo_process +def not_(x) -> ProcessBuilder: + """ + Inverting a boolean + + :param x: Boolean value to invert. + + :return: Inverted boolean value. + """ + return _process('not', x=x) + + +@openeo_process +def or_(x, y) -> ProcessBuilder: + """ + Logical OR + + :param x: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical OR. + """ + return _process('or', x=x, y=y) + + +@openeo_process +def order(data, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Create a permutation + + :param data: An array to compute the order for. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The computed permutation. + """ + return _process('order', data=data, asc=asc, nodata=nodata) + + +@openeo_process +def pi() -> ProcessBuilder: + """ + Pi (π) + + :return: The numerical value of Pi. + """ + return _process('pi', ) + + +@openeo_process +def power(base, p) -> ProcessBuilder: + """ + Exponentiation + + :param base: The numerical base. + :param p: The numerical exponent. + + :return: The computed value for `base` raised to the power of `p`. + """ + return _process('power', base=base, p=p) + + +@openeo_process +def predict_curve(data, parameters, function, dimension, labels=UNSET) -> ProcessBuilder: + """ + Predict values + + :param data: A data cube to predict values for. + :param parameters: A data cube with optimal values from a result of e.g. ``fit_curve()``. + :param function: The model function. It must take the parameters to fit as array through the first argument + and the independent variable `x` as the second argument. It is recommended to store the model function as + a user-defined process on the back-end. + :param dimension: The name of the dimension for predictions. Fails with a `DimensionNotAvailable` exception + if the specified dimension does not exist. + :param labels: The labels to predict values for. If no labels are given, predicts values only for no-data + (`null`) values in the data cube. + + :return: A data cube with the predicted values. + """ + return _process('predict_curve', + data=data, + parameters=parameters, + function=build_child_callback(function, parent_parameters=['x', 'parameters']), + dimension=dimension, + labels=labels + ) + + +@openeo_process +def predict_random_forest(data, model) -> ProcessBuilder: + """ + Predict values from a Random Forest model + + :param data: An array of numbers. + :param model: A model object that can be trained with the processes ``fit_regr_random_forest()`` + (regression) and ``fit_class_random_forest()`` (classification). + + :return: The predicted value. Returns `null` if any of the given values in the array is a no-data value. + """ + return _process('predict_random_forest', data=data, model=model) + + +@openeo_process +def product(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the product by multiplying numbers + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed product of the sequence of numbers. + """ + return _process('product', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def quantiles(data, probabilities=UNSET, q=UNSET, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Quantiles + + :param data: An array of numbers. + :param probabilities: A list of probabilities to calculate quantiles for. The probabilities must be between + 0 and 1 (inclusive). + :param q: Number of intervals to calculate quantiles for. Calculates q-quantiles with equal-sized + intervals. + :param ignore_nodata: Indicates whether no-data values are ignored or not. Ignores them by default. Setting + this flag to `false` considers no-data values so that an array with `null` values is returned if any + element is such a value. + + :return: An array with the computed quantiles. The list has either * as many elements as the given list of + `probabilities` had or * *`q`-1* elements. If 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. + """ + return _process('quantiles', data=data, probabilities=probabilities, q=q, ignore_nodata=ignore_nodata) + + +@openeo_process +def rearrange(data, order) -> ProcessBuilder: + """ + Rearrange an array based on a permutation + + :param data: The array to rearrange. + :param order: The permutation used for rearranging. + + :return: The rearranged array. + """ + return _process('rearrange', data=data, order=order) + + +@openeo_process +def reduce_dimension(data, reducer, dimension, context=UNSET) -> ProcessBuilder: + """ + Reduce dimensions + + :param data: A data cube. + :param reducer: A reducer to apply on 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. + :param dimension: The name of the dimension over which to reduce. Fails with a `DimensionNotAvailable` + exception if the specified dimension does not exist. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return _process('reduce_dimension', + data=data, + reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), + dimension=dimension, + context=context + ) + + +@openeo_process +def reduce_spatial(data, reducer, context=UNSET) -> ProcessBuilder: + """ + Reduce spatial dimensions 'x' and 'y' + + :param data: A data cube. + :param reducer: 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. + :param context: Additional data to be passed to the reducer. + + :return: 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. + """ + return _process('reduce_spatial', data=data, reducer=build_child_callback(reducer, parent_parameters=['data', 'context']), context=context) + + +@openeo_process +def rename_dimension(data, source, target) -> ProcessBuilder: + """ + Rename a dimension + + :param data: The data cube. + :param source: The current name of the dimension. Fails with a `DimensionNotAvailable` exception if the + specified dimension does not exist. + :param target: A new Name for the dimension. Fails with a `DimensionExists` exception if a dimension with + the specified name exists. + + :return: A data cube with the same dimensions, but the name of one of the dimensions changes. The old name + can not be referred to any longer. The dimension properties (name, type, labels, reference system and + resolution) remain unchanged. + """ + return _process('rename_dimension', data=data, source=source, target=target) + + +@openeo_process +def rename_labels(data, dimension, target, source=UNSET) -> ProcessBuilder: + """ + Rename dimension labels + + :param data: The data cube. + :param dimension: The name of the dimension to rename the labels for. + :param target: The new names for the labels. If a target dimension label already exists in the data cube, + a `LabelExists` exception is thrown. + :param source: The original names of the labels to be renamed to corresponding array elements in the + parameter `target`. It is allowed to only specify a subset of labels to rename, as long as the `target` and + `source` parameter have the same length. The order of the labels doesn't need to match the order of the + dimension labels in the data cube. By default, the array is empty so that the dimension labels in the data + cube are expected to be enumerated. If the dimension labels are not enumerated and the given array is + empty, the `LabelsNotEnumerated` exception is thrown. If one of the source dimension labels doesn't exist, + the `LabelNotAvailable` exception is thrown. + + :return: The data cube with the same dimensions. The dimension properties (name, type, labels, reference + system and resolution) remain unchanged, except that for the given dimension the labels change. The old + labels can not be referred to any longer. The number of labels remains the same. + """ + return _process('rename_labels', data=data, dimension=dimension, target=target, source=source) + + +@openeo_process +def resample_cube_spatial(data, target, method=UNSET) -> ProcessBuilder: + """ + Resample the spatial dimensions to match a target data cube + + :param data: A data cube. + :param target: A data cube that describes the spatial target resolution. + :param method: 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): * `average`: average (mean) + resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling * `cubic`: + cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc resampling * + `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median resampling, + selects the median value of all valid pixels * `min`: minimum resampling, selects the minimum value from + all valid pixels * `mode`: mode resampling, selects the value which appears most often of all the sampled + points * `near`: nearest neighbour resampling (default) * `q1`: first quartile resampling, selects the + first quartile value of all valid pixels * `q3`: third quartile resampling, selects the third quartile + value of all valid pixels * `rms` root mean square (quadratic mean) of all valid pixels * `sum`: compute + the weighted sum of all valid pixels Valid pixels are determined based on the function ``is_valid()``. + + :return: 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 spatial + dimensions. + """ + return _process('resample_cube_spatial', data=data, target=target, method=method) + + +@openeo_process +def resample_cube_temporal(data, target, dimension=UNSET, valid_within=UNSET) -> ProcessBuilder: + """ + Resample temporal dimensions to match a target data cube + + :param data: A data cube with one or more temporal dimensions. + :param target: A data cube that describes the temporal target resolution. + :param dimension: 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. The following exceptions may occur: * A dimension is + given, but it does not exist in any of the data cubes: `DimensionNotAvailable` * A dimension is given, but + one of them is not temporal: `DimensionMismatch` * No specific dimension name is given and there are no + temporal dimensions with the same name in the data: `DimensionMismatch` + :param valid_within: 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`). + + :return: 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. + """ + return _process('resample_cube_temporal', data=data, target=target, dimension=dimension, valid_within=valid_within) + + +@openeo_process +def resample_spatial(data, resolution=UNSET, projection=UNSET, method=UNSET, align=UNSET) -> ProcessBuilder: + """ + Resample and warp the spatial dimensions + + :param data: A raster data cube. + :param resolution: 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`). + :param projection: Warps the data cube to the target projection, specified as as [EPSG + code](http://www.epsg-registry.org/), [WKT2 (ISO 19162) + string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html), [PROJ definition + (deprecated)](https://proj.org/usage/quickstart.html). By default (`null`), the projection is not changed. + :param method: 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): * `average`: average (mean) + resampling, computes the weighted average of all valid pixels * `bilinear`: bilinear resampling * `cubic`: + cubic resampling * `cubicspline`: cubic spline resampling * `lanczos`: Lanczos windowed sinc resampling * + `max`: maximum resampling, selects the maximum value from all valid pixels * `med`: median resampling, + selects the median value of all valid pixels * `min`: minimum resampling, selects the minimum value from + all valid pixels * `mode`: mode resampling, selects the value which appears most often of all the sampled + points * `near`: nearest neighbour resampling (default) * `q1`: first quartile resampling, selects the + first quartile value of all valid pixels * `q3`: third quartile resampling, selects the third quartile + value of all valid pixels * `rms` root mean square (quadratic mean) of all valid pixels * `sum`: compute + the weighted sum of all valid pixels Valid pixels are determined based on the function ``is_valid()``. + :param align: Specifies to which corner of the spatial extent the new resampled data is aligned to. + + :return: A raster data cube with values warped onto the new projection. It has the same dimensions and the + same dimension properties (name, type, labels, reference system and resolution) for all non-spatial or + vertical spatial dimensions. For the horizontal spatial dimensions the name and type remain unchanged, but + reference system, labels and resolution may change depending on the given parameters. + """ + return _process('resample_spatial', data=data, resolution=resolution, projection=projection, method=method, align=align) + + +@openeo_process +def round(x, p=UNSET) -> ProcessBuilder: + """ + Round to a specified precision + + :param x: A number to round. + :param p: A positive number specifies the number of digits after the decimal point to round to. A negative + number means rounding to a power of ten, so for example *-2* rounds to the nearest hundred. Defaults to + *0*. + + :return: The rounded number. + """ + return _process('round', x=x, p=p) + + +@openeo_process +def run_udf(data, udf, runtime, version=UNSET, context=UNSET) -> ProcessBuilder: + """ + Run a UDF + + :param data: The data to be passed to the UDF. + :param udf: Either source code, an absolute URL or a path to a UDF script. + :param runtime: A UDF runtime identifier available at the back-end. + :param version: An UDF runtime version. If set to `null`, the default runtime version specified for each + runtime is used. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can be of any data type and is exactly what the + UDF code returns. + """ + return _process('run_udf', data=data, udf=udf, runtime=runtime, version=version, context=context) + + +@openeo_process +def run_udf_externally(data, url, context=UNSET) -> ProcessBuilder: + """ + Run an externally hosted UDF container + + :param data: The data to be passed to the UDF. + :param url: Absolute URL to a remote UDF service. + :param context: Additional data such as configuration options to be passed to the UDF. + + :return: The data processed by the UDF. The returned value can in principle be of any data type, but it + depends on what is returned by the UDF code. Please see the implemented UDF interface for details. + """ + return _process('run_udf_externally', data=data, url=url, context=context) + + +@openeo_process +def sar_backscatter(data, coefficient=UNSET, elevation_model=UNSET, mask=UNSET, contributing_area=UNSET, local_incidence_angle=UNSET, ellipsoid_incidence_angle=UNSET, noise_removal=UNSET, options=UNSET) -> ProcessBuilder: + """ + Computes backscatter from SAR input + + :param data: The source data cube containing SAR input. + :param coefficient: Select the radiometric correction coefficient. The following options are available: * + `beta0`: radar brightness * `sigma0-ellipsoid`: ground area computed with ellipsoid earth model * + `sigma0-terrain`: ground area computed with terrain earth model * `gamma0-ellipsoid`: ground area computed + with ellipsoid earth model in sensor line of sight * `gamma0-terrain`: ground area computed with terrain + earth model in sensor line of sight (default) * `null`: non-normalized backscatter + :param elevation_model: 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. + :param mask: 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). + :param contributing_area: If set to `true`, a DEM-based local contributing area band named + `contributing_area` is added. The values are given in square meters. + :param local_incidence_angle: If set to `true`, a DEM-based local incidence angle band named + `local_incidence_angle` is added. The values are given in degrees. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes + noise. + :param options: Proprietary options for the backscatter computations. Specifying proprietary options will + reduce portability. + + :return: Backscatter values corresponding to the chosen parametrization. The values are given in linear + scale. + """ + return _process('sar_backscatter', + data=data, + coefficient=coefficient, + elevation_model=elevation_model, + mask=mask, + contributing_area=contributing_area, + local_incidence_angle=local_incidence_angle, + ellipsoid_incidence_angle=ellipsoid_incidence_angle, + noise_removal=noise_removal, + options=options + ) + + +@openeo_process +def save_ml_model(data, options=UNSET) -> ProcessBuilder: + """ + Save a ML model + + :param data: The data to store as a machine learning model. + :param options: Additional parameters to create the file(s). + + :return: Returns `false` if the process failed to store the model, `true` otherwise. + """ + return _process('save_ml_model', data=data, options=options) + + +@openeo_process +def save_result(data, format, options=UNSET) -> ProcessBuilder: + """ + Save processed data + + :param data: The data to deliver in the given file format. + :param format: The file format to use. It must be one of the values that the server reports as supported + output file formats, which usually correspond to the short GDAL/OGR codes. If the format is not suitable + for storing the underlying data structure, a `FormatUnsuitable` exception will be thrown. This parameter is + *case insensitive*. + :param options: The file format parameters to be used to create the file(s). Must correspond to the + parameters that the server reports as supported parameters for the chosen `format`. The parameter names and + valid values usually correspond to the GDAL/OGR format options. + + :return: Returns `false` if the process failed to make the data available, `true` otherwise. + """ + return _process('save_result', data=data, format=format, options=options) + + +@openeo_process +def sd(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Standard deviation + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed sample standard deviation. + """ + return _process('sd', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def sgn(x) -> ProcessBuilder: + """ + Signum + + :param x: A number. + + :return: The computed signum value of `x`. + """ + return _process('sgn', x=x) + + +@openeo_process +def sin(x) -> ProcessBuilder: + """ + Sine + + :param x: An angle in radians. + + :return: The computed sine of `x`. + """ + return _process('sin', x=x) + + +@openeo_process +def sinh(x) -> ProcessBuilder: + """ + Hyperbolic sine + + :param x: An angle in radians. + + :return: The computed hyperbolic sine of `x`. + """ + return _process('sinh', x=x) + + +@openeo_process +def sort(data, asc=UNSET, nodata=UNSET) -> ProcessBuilder: + """ + Sort data + + :param data: An array with data to sort. + :param asc: The default sort order is ascending, with smallest values first. To sort in reverse + (descending) order, set this parameter to `false`. + :param nodata: 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. + + :return: The sorted array. + """ + return _process('sort', data=data, asc=asc, nodata=nodata) + + +@openeo_process +def sqrt(x) -> ProcessBuilder: + """ + Square root + + :param x: A number. + + :return: The computed square root. + """ + return _process('sqrt', x=x) + + +@openeo_process +def subtract(x, y) -> ProcessBuilder: + """ + Subtraction of two numbers + + :param x: The minuend. + :param y: The subtrahend. + + :return: The computed result. + """ + return _process('subtract', x=x, y=y) + + +@openeo_process +def sum(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Compute the sum by adding up numbers + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed sum of the sequence of numbers. + """ + return _process('sum', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def tan(x) -> ProcessBuilder: + """ + Tangent + + :param x: An angle in radians. + + :return: The computed tangent of `x`. + """ + return _process('tan', x=x) + + +@openeo_process +def tanh(x) -> ProcessBuilder: + """ + Hyperbolic tangent + + :param x: An angle in radians. + + :return: The computed hyperbolic tangent of `x`. + """ + return _process('tanh', x=x) + + +@openeo_process +def text_begins(data, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text begins with another text + + :param data: Text in which to find something at the beginning. + :param pattern: Text to find at the beginning of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` begins with `pattern`, false` otherwise. + """ + return _process('text_begins', data=data, pattern=pattern, case_sensitive=case_sensitive) + + +@openeo_process +def text_concat(data, separator=UNSET) -> ProcessBuilder: + """ + Concatenate elements to a single text + + :param data: A set of elements. Numbers, boolean values and null values get converted to their (lower case) + string representation. For example: `1` (integer), `-1.5` (number), `true` / `false` (boolean values) + :param separator: A separator to put between each of the individual texts. Defaults to an empty string. + + :return: A string containing a string representation of all the array elements in the same order, with the + separator between each element. + """ + return _process('text_concat', data=data, separator=separator) + + +@openeo_process +def text_contains(data, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text contains another text + + :param data: Text in which to find something in. + :param pattern: Text to find in `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` contains the `pattern`, false` otherwise. + """ + return _process('text_contains', data=data, pattern=pattern, case_sensitive=case_sensitive) + + +@openeo_process +def text_ends(data, pattern, case_sensitive=UNSET) -> ProcessBuilder: + """ + Text ends with another text + + :param data: Text in which to find something at the end. + :param pattern: Text to find at the end of `data`. Regular expressions are not supported. + :param case_sensitive: Case sensitive comparison can be disabled by setting this parameter to `false`. + + :return: `true` if `data` ends with `pattern`, false` otherwise. + """ + return _process('text_ends', data=data, pattern=pattern, case_sensitive=case_sensitive) + + +@openeo_process +def trim_cube(data) -> ProcessBuilder: + """ + Remove dimension labels with no-data values + + :param data: A raster data cube to trim. + + :return: A trimmed raster data cube with the same dimensions. The dimension properties name, type, + reference system and resolution remain unchanged. The number of dimension labels may decrease. + """ + return _process('trim_cube', data=data) + + +@openeo_process +def unflatten_dimension(data, dimension, target_dimensions, label_separator=UNSET) -> ProcessBuilder: + """ + Split a single dimensions into multiple dimensions + + :param data: A data cube that is consistently structured so that operation can execute flawlessly (e.g. the + dimension labels need to contain the `label_separator` exactly 1 time for two target dimensions, 2 times + for three target dimensions etc.). + :param dimension: The name of the dimension to split. + :param target_dimensions: The names of the new target dimensions. New dimensions will be created with the + given names and type `other` (see ``add_dimension()``). Fails with a `TargetDimensionExists` exception if + any of the dimensions exists. The order of the array defines the order in which the dimensions and + dimension labels are added to the data cube (see the example in the process description). + :param label_separator: The string that will be used as a separator to split the dimension labels. + + :return: A data cube with the new shape. The dimension properties (name, type, labels, reference system and + resolution) for all other dimensions remain unchanged. + """ + return _process('unflatten_dimension', data=data, dimension=dimension, target_dimensions=target_dimensions, label_separator=label_separator) + + +@openeo_process +def variance(data, ignore_nodata=UNSET) -> ProcessBuilder: + """ + Variance + + :param data: An array of numbers. + :param ignore_nodata: 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 returned if any value is such a value. + + :return: The computed sample variance. + """ + return _process('variance', data=data, ignore_nodata=ignore_nodata) + + +@openeo_process +def vector_buffer(geometries, distance) -> ProcessBuilder: + """ + Buffer geometries by distance + + :param geometries: Geometries to apply the buffer on. Vector properties are preserved for vector data cubes + and all GeoJSON Features. To 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`). + :param distance: The distance of the buffer in the unit of the spatial reference system. A positive + distance expands the geometries and results in outward buffering (dilation) while a negative distance + shrinks the geometries and results in inward buffering (erosion). + + :return: Returns a vector data cube with the computed new geometries. + """ + return _process('vector_buffer', geometries=geometries, distance=distance) + + +@openeo_process +def vector_to_random_points(data, geometry_count=UNSET, total_count=UNSET, group=UNSET, seed=UNSET) -> ProcessBuilder: + """ + Sample random points from geometries + + :param data: Input geometries for sample extraction. To 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`). + :param geometry_count: The maximum number of points to compute per geometry. Points in the input + geometries can be selected only once by the sampling. + :param total_count: The maximum number of points to compute overall. Throws a `CountMismatch` exception if + the specified value is less than the provided number of geometries. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a `MultiPoint` + per geometry given which keeps the original identifier if present. * Otherwise, each sampled point is + generated as a distinct `Point` geometry without identifier. + :param seed: A randomization seed to use for random sampling. If not given or `null`, no seed is used and + results may differ on subsequent use. + + :return: Returns a vector data cube with the sampled points. + """ + return _process('vector_to_random_points', data=data, geometry_count=geometry_count, total_count=total_count, group=group, seed=seed) + + +@openeo_process +def vector_to_regular_points(data, distance, group=UNSET) -> ProcessBuilder: + """ + Sample regular points from geometries + + :param data: Input geometries for sample extraction. To 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`). + :param distance: Defines the minimum distance in the unit of the reference system that is required between + two samples generated *inside* a single geometry. - For **polygons**, the distance defines the cell sizes + of a regular grid that starts at the upper-left bound of each polygon. The centroid of each cell is then a + sample point. If the centroid is not enclosed in the polygon, no point is sampled. If no point can be + sampled for the geometry at all, the first coordinate of the geometry is returned as point. - For **lines** + (line strings), the sampling starts with a point at the first coordinate of the line and then walks along + the line and samples a new point each time the distance to the previous point has been reached again. - For + **points**, the point is returned as given. + :param group: Specifies whether the sampled points should be grouped by input geometry (default) or be + generated as independent points. * If the sampled points are grouped, the process generates a `MultiPoint` + per geometry given which keeps the original identifier if present. * Otherwise, each sampled point is + generated as a distinct `Point` geometry without identifier. + + :return: Returns a vector data cube with the sampled points. + """ + return _process('vector_to_regular_points', data=data, distance=distance, group=group) + + +@openeo_process +def xor(x, y) -> ProcessBuilder: + """ + Logical XOR (exclusive or) + + :param x: A boolean value. + :param y: A boolean value. + + :return: Boolean result of the logical XOR. + """ + return _process('xor', x=x, y=y) diff --git a/lib/openeo/rest/__init__.py b/lib/openeo/rest/__init__.py new file mode 100644 index 000000000..f04cf03e6 --- /dev/null +++ b/lib/openeo/rest/__init__.py @@ -0,0 +1,92 @@ +from typing import Optional + +from openeo import BaseOpenEoException + + +class OpenEoClientException(BaseOpenEoException): + """Base class for OpenEO client exceptions""" + pass + + +class CapabilitiesException(OpenEoClientException): + """Back-end does not support certain openEO feature or endpoint.""" + + +class JobFailedException(OpenEoClientException): + """A synchronous batch job failed. This exception references its corresponding job so the client can e.g. + retrieve its logs. + """ + + def __init__(self, message, job): + super().__init__(message) + self.job = job + + +class OperatorException(OpenEoClientException): + """Invalid (mathematical) operator usage.""" + pass + + +class BandMathException(OperatorException): + """Invalid "band math" usage.""" + pass + + +class OpenEoRestError(OpenEoClientException): + pass + + +class OpenEoApiPlainError(OpenEoRestError): + """ + Base class for openEO API error responses, not necessarily following the openEO API specification + (e.g. not properly JSON encoded, missing required fields, ...) + + :param message: the direct error message from the response + :param http_status_code: the HTTP status code of the response + :param error_message: the error message to show when the exception is rendered + (by default a combination of the HTTP status code and the message) + + .. versionadded:: 0.25.0 + """ + + __slots__ = ("http_status_code", "message") + + def __init__( + self, + message: str, + *, + http_status_code: Optional[int] = None, + error_message: Optional[str] = None, + ): + super().__init__(error_message or f"[{http_status_code}] {message}") + self.http_status_code = http_status_code + self.message = message + + +class OpenEoApiError(OpenEoApiPlainError): + """ + Exception for API error responses following the openEO API specification + (https://api.openeo.org/#section/API-Principles/Error-Handling): + JSON-encoded body, some expected fields like "code" and "message", ... + """ + + __slots__ = ("http_status_code", "code", "message", "id", "url") + + def __init__( + self, + http_status_code: Optional[int] = None, + code: str = "unknown", + message: str = "unknown error", + id: Optional[str] = None, + url: Optional[str] = None, + ): + super().__init__( + message=message, + http_status_code=http_status_code, + error_message=f"[{http_status_code}] {code}: {message}" + (f" (ref: {id})" if id else ""), + ) + self.http_status_code = http_status_code + self.code = code + self.message = message + self.id = id + self.url = url diff --git a/lib/openeo/rest/_datacube.py b/lib/openeo/rest/_datacube.py new file mode 100644 index 000000000..f0afeca47 --- /dev/null +++ b/lib/openeo/rest/_datacube.py @@ -0,0 +1,321 @@ +from __future__ import annotations + +import logging +import pathlib +import re +import typing +import uuid +import warnings +from typing import Dict, List, Optional, Tuple, Union + +import requests + +from openeo.internal.graph_building import FlatGraphableMixin, PGNode, _FromNodeMixin +from openeo.internal.jupyter import render_component +from openeo.internal.processes.builder import ( + convert_callable_to_pgnode, + get_parameter_names, +) +from openeo.internal.warnings import UserDeprecationWarning +from openeo.rest import OpenEoClientException +from openeo.util import dict_no_none, str_truncate + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + from openeo.rest.connection import Connection + +log = logging.getLogger(__name__) + +# Sentinel object to refer to "current" cube in chained cube processing expressions. +THIS = object() + + +class _ProcessGraphAbstraction(_FromNodeMixin, FlatGraphableMixin): + """ + Base class for client-side abstractions/wrappers + for structures that are represented by a openEO process graph: + raster data cubes, vector cubes, ML models, ... + """ + + def __init__(self, pgnode: PGNode, connection: Connection): + self._pg = pgnode + self._connection = connection + + def __str__(self): + return "{t}({pg})".format(t=self.__class__.__name__, pg=self._pg) + + def flat_graph(self) -> Dict[str, dict]: + """ + Get the process graph in internal flat dict representation. + + .. warning:: This method is mainly intended for internal use. + It is not recommended for general use and is *subject to change*. + + Instead, it is recommended to use + :py:meth:`to_json()` or :py:meth:`print_json()` + to obtain a standardized, interoperable JSON representation of the process graph. + See :ref:`process_graph_export` for more information. + """ + # TODO: wrap in {"process_graph":...} by default/optionally? + return self._pg.flat_graph() + + @property + def _api_version(self): + return self._connection.capabilities().api_version_check + + @property + def connection(self) -> Connection: + return self._connection + + def result_node(self) -> PGNode: + """ + Get the current result node (:py:class:`PGNode`) of the process graph. + + .. versionadded:: 0.10.1 + """ + return self._pg + + def from_node(self): + # _FromNodeMixin API + return self._pg + + def _build_pgnode( + self, + process_id: str, + arguments: Optional[dict] = None, + namespace: Optional[str] = None, + **kwargs + ) -> PGNode: + """ + Helper to build a PGNode from given argument dict and/or kwargs, + and possibly resolving the `THIS` reference. + """ + arguments = {**(arguments or {}), **kwargs} + for k, v in arguments.items(): + if v is THIS: + arguments[k] = self + # TODO: also necessary to traverse lists/dictionaries? + return PGNode(process_id=process_id, arguments=arguments, namespace=namespace) + + # TODO #278 also move process graph "execution" methods here: `download`, `execute`, `execute_batch`, `create_job`, `save_udf`, ... + + def _repr_html_(self): + process = {"process_graph": self.flat_graph()} + parameters = { + "id": uuid.uuid4().hex, + "explicit-zoom": True, + "height": "400px", + } + return render_component("model-builder", data=process, parameters=parameters) + + +class UDF: + """ + Helper class to load UDF code (e.g. from file) and embed them as "callback" or child process in a process graph. + + Usage example: + + .. code-block:: python + + udf = UDF.from_file("my-udf-code.py") + cube = cube.apply(process=udf) + + + .. versionchanged:: 0.13.0 + Added auto-detection of ``runtime``. + Specifying the ``data`` argument is not necessary anymore, and actually deprecated. + Added :py:meth:`from_file` to simplify loading UDF code from a file. + See :ref:`old_udf_api` for more background about the changes. + """ + + # TODO: eliminate dependency on `openeo.rest.connection` and move to somewhere under `openeo.internal`? + + __slots__ = ["code", "_runtime", "version", "context", "_source"] + + def __init__( + self, + code: str, + runtime: Optional[str] = None, + data=None, # TODO #181 remove `data` argument + version: Optional[str] = None, + context: Optional[dict] = None, + _source=None, + ): + """ + Construct a UDF object from given code string and other argument related to the ``run_udf`` process. + + :param code: UDF source code string (Python, R, ...) + :param runtime: optional UDF runtime identifier, will be autodetected from source code if omitted. + :param data: unused leftover from old API. Don't use this argument, it will be removed in a future release. + :param version: optional UDF runtime version string + :param context: optional additional UDF context data + :param _source: (for internal use) source identifier + """ + # TODO: automatically dedent code (when literal string) ? + self.code = code + self._runtime = runtime + self.version = version + self.context = context + self._source = _source + if data is not None: + # TODO #181 remove `data` argument + warnings.warn( + f"The `data` argument of `{self.__class__.__name__}` is deprecated, unused and will be removed in a future release.", + category=UserDeprecationWarning, + stacklevel=2, + ) + + def __repr__(self): + return f"<{type(self).__name__} runtime={self._runtime!r} code={str_truncate(self.code, width=200)!r}>" + + def get_runtime(self, connection: Optional[Connection] = None) -> str: + return self._runtime or self._guess_runtime(connection=connection) + + @classmethod + def from_file( + cls, + path: Union[str, pathlib.Path], + runtime: Optional[str] = None, + version: Optional[str] = None, + context: Optional[dict] = None, + ) -> UDF: + """ + Load a UDF from a local file. + + .. seealso:: + :py:meth:`from_url` for loading from a URL. + + :param path: path to the local file with UDF source code + :param runtime: optional UDF runtime identifier, will be auto-detected from source code if omitted. + :param version: optional UDF runtime version string + :param context: optional additional UDF context data + """ + path = pathlib.Path(path) + code = path.read_text(encoding="utf-8") + return cls( + code=code, runtime=runtime, version=version, context=context, _source=path + ) + + @classmethod + def from_url( + cls, + url: str, + runtime: Optional[str] = None, + version: Optional[str] = None, + context: Optional[dict] = None, + ) -> UDF: + """ + Load a UDF from a URL. + + .. seealso:: + :py:meth:`from_file` for loading from a local file. + + :param url: URL path to load the UDF source code from + :param runtime: optional UDF runtime identifier, will be auto-detected from source code if omitted. + :param version: optional UDF runtime version string + :param context: optional additional UDF context data + """ + resp = requests.get(url) + resp.raise_for_status() + code = resp.text + return cls( + code=code, runtime=runtime, version=version, context=context, _source=url + ) + + def _guess_runtime(self, connection: Optional[Connection] = None) -> str: + """Guess UDF runtime from UDF source (path) or source code.""" + # First, guess UDF language + language = None + if isinstance(self._source, pathlib.Path): + language = self._guess_runtime_from_suffix(self._source.suffix) + elif isinstance(self._source, str): + url_match = re.match( + r"https?://.*?(?P\.\w+)([&#].*)?$", self._source + ) + if url_match: + language = self._guess_runtime_from_suffix(url_match.group("suffix")) + if not language: + # Guess language from UDF code + if re.search(r"^def [\w0-9_]+\(", self.code, flags=re.MULTILINE): + language = "Python" + # TODO: detection heuristics for R and other languages? + if not language: + raise OpenEoClientException("Failed to detect language of UDF code.") + runtime = language + if connection: + # Some additional best-effort validation/normalization of the runtime + # TODO: this just does some case-normalization, just drop that all together to eliminate + # the dependency on a connection object. See https://github.com/Open-EO/openeo-api/issues/510 + runtimes = {k.lower(): k for k in connection.list_udf_runtimes().keys()} + runtime = runtimes.get(runtime.lower(), runtime) + return runtime + + def _guess_runtime_from_suffix(self, suffix: str) -> Union[str]: + return { + ".py": "Python", + ".r": "R", + }.get(suffix.lower()) + + def get_run_udf_callback(self, connection: Optional[Connection] = None, data_parameter: str = "data") -> PGNode: + """ + For internal use: construct `run_udf` node to be used as callback in `apply`, `reduce_dimension`, ... + """ + arguments = dict_no_none( + data={"from_parameter": data_parameter}, + udf=self.code, + runtime=self.get_runtime(connection=connection), + version=self.version, + context=self.context, + ) + return PGNode(process_id="run_udf", arguments=arguments) + + +def build_child_callback( + process: Union[str, PGNode, typing.Callable, UDF], + parent_parameters: List[str], + connection: Optional[Connection] = None, +) -> dict: + """ + Build a "callback" process: a user defined process that is used by another process (such + as `apply`, `apply_dimension`, `reduce`, ....) + + :param process: process id string, PGNode or callable that uses the ProcessBuilder mechanism to build a process + :param parent_parameters: list of parameter names defined for child process + :param connection: optional connection object to improve runtime validation for UDFs + :return: + """ + # TODO: move this to more generic process graph building utility module + # TODO: autodetect the parameters defined by parent process? + # TODO: eliminate need for connection object (also see `UDF._guess_runtime`) + # TODO: when `openeo.rest` deps are gone: move this helper to somewhere under `openeo.internal` + if isinstance(process, PGNode): + # Assume this is already a valid callback process + pg = process + elif isinstance(process, str): + # Assume given reducer is a simple predefined reduce process_id + # TODO: avoid local import (workaround for circular import issue) + import openeo.processes + if process in openeo.processes.__dict__: + process_params = get_parameter_names(openeo.processes.__dict__[process]) + # TODO: switch to "Callable" handling here + else: + # Best effort guess + process_params = parent_parameters + if parent_parameters == ["x", "y"] and (len(process_params) == 1 or process_params[:1] == ["data"]): + # Special case: wrap all parent parameters in an array + arguments = {process_params[0]: [{"from_parameter": p} for p in parent_parameters]} + else: + # Only pass parameters that correspond with an arg name + common = set(process_params).intersection(parent_parameters) + arguments = {p: {"from_parameter": p} for p in common} + pg = PGNode(process_id=process, arguments=arguments) + elif isinstance(process, typing.Callable): + pg = convert_callable_to_pgnode(process, parent_parameters=parent_parameters) + elif isinstance(process, UDF): + pg = process.get_run_udf_callback(connection=connection, data_parameter=parent_parameters[0]) + elif isinstance(process, dict) and isinstance(process.get("process_graph"), PGNode): + pg = process["process_graph"] + else: + raise ValueError(process) + + return PGNode.to_process_graph_argument(pg) diff --git a/lib/openeo/rest/_testing.py b/lib/openeo/rest/_testing.py new file mode 100644 index 000000000..6ad33ada6 --- /dev/null +++ b/lib/openeo/rest/_testing.py @@ -0,0 +1,217 @@ +import json +import re +from typing import Optional, Union + +from openeo import Connection, DataCube +from openeo.rest.vectorcube import VectorCube + + +class DummyBackend: + """ + Dummy backend that handles sync/batch execution requests + and allows inspection of posted process graphs + """ + + __slots__ = ( + "connection", + "sync_requests", + "batch_jobs", + "validation_requests", + "next_result", + "next_validation_errors", + ) + + # Default result (can serve both as JSON or binary data) + DEFAULT_RESULT = b'{"what?": "Result data"}' + + def __init__(self, requests_mock, connection: Connection): + self.connection = connection + self.sync_requests = [] + self.batch_jobs = {} + self.validation_requests = [] + self.next_result = self.DEFAULT_RESULT + self.next_validation_errors = [] + requests_mock.post( + connection.build_url("/result"), + content=self._handle_post_result, + ) + requests_mock.post( + connection.build_url("/jobs"), + content=self._handle_post_jobs, + ) + requests_mock.post( + re.compile(connection.build_url(r"/jobs/(job-\d+)/results$")), content=self._handle_post_job_results + ) + requests_mock.get(re.compile(connection.build_url(r"/jobs/(job-\d+)$")), json=self._handle_get_job) + requests_mock.get( + re.compile(connection.build_url(r"/jobs/(job-\d+)/results$")), json=self._handle_get_job_results + ) + requests_mock.get( + re.compile(connection.build_url("/jobs/(.*?)/results/result.data$")), + content=self._handle_get_job_result_asset, + ) + requests_mock.post(connection.build_url("/validation"), json=self._handle_post_validation) + + def _handle_post_result(self, request, context): + """handler of `POST /result` (synchronous execute)""" + pg = request.json()["process"]["process_graph"] + self.sync_requests.append(pg) + result = self.next_result + if isinstance(result, (dict, list)): + result = json.dumps(result).encode("utf-8") + elif isinstance(result, str): + result = result.encode("utf-8") + assert isinstance(result, bytes) + return result + + def _handle_post_jobs(self, request, context): + """handler of `POST /jobs` (create batch job)""" + pg = request.json()["process"]["process_graph"] + job_id = f"job-{len(self.batch_jobs):03d}" + self.batch_jobs[job_id] = {"job_id": job_id, "pg": pg, "status": "created"} + context.status_code = 201 + context.headers["openeo-identifier"] = job_id + + def _get_job_id(self, request) -> str: + match = re.match(r"^/jobs/(job-\d+)(/|$)", request.path) + if not match: + raise ValueError(f"Failed to extract job_id from {request.path}") + job_id = match.group(1) + assert job_id in self.batch_jobs + return job_id + + def _handle_post_job_results(self, request, context): + """Handler of `POST /job/{job_id}/results` (start batch job).""" + job_id = self._get_job_id(request) + assert self.batch_jobs[job_id]["status"] == "created" + # TODO: support custom status sequence (instead of directly going to status "finished")? + self.batch_jobs[job_id]["status"] = "finished" + context.status_code = 202 + + def _handle_get_job(self, request, context): + """Handler of `GET /job/{job_id}` (get batch job status and metadata).""" + job_id = self._get_job_id(request) + return {"id": job_id, "status": self.batch_jobs[job_id]["status"]} + + def _handle_get_job_results(self, request, context): + """Handler of `GET /job/{job_id}/results` (list batch job results).""" + job_id = self._get_job_id(request) + assert self.batch_jobs[job_id]["status"] == "finished" + return { + "id": job_id, + "assets": {"result.data": {"href": self.connection.build_url(f"/jobs/{job_id}/results/result.data")}}, + } + + def _handle_get_job_result_asset(self, request, context): + """Handler of `GET /job/{job_id}/results/result.data` (get batch job result asset).""" + job_id = self._get_job_id(request) + assert self.batch_jobs[job_id]["status"] == "finished" + return self.next_result + + def _handle_post_validation(self, request, context): + """Handler of `POST /validation` (validate process graph).""" + pg = request.json()["process_graph"] + self.validation_requests.append(pg) + return {"errors": self.next_validation_errors} + + def get_sync_pg(self) -> dict: + """Get one and only synchronous process graph""" + assert len(self.sync_requests) == 1 + return self.sync_requests[0] + + def get_batch_pg(self) -> dict: + """Get one and only batch process graph""" + assert len(self.batch_jobs) == 1 + return self.batch_jobs[max(self.batch_jobs.keys())]["pg"] + + def get_pg(self, process_id: Optional[str] = None) -> dict: + """ + Get one and only batch process graph (sync or batch) + + :param process_id: just return single process graph node with this process_id + :return: process graph (flat graph representation) or process graph node + """ + pgs = self.sync_requests + [b["pg"] for b in self.batch_jobs.values()] + assert len(pgs) == 1 + pg = pgs[0] + if process_id: + # Just return single node (by process_id) + found = [node for node in pg.values() if node.get("process_id") == process_id] + if len(found) != 1: + raise RuntimeError( + f"Expected single process graph node with process_id {process_id!r}, but found {len(found)}: {found}" + ) + return found[0] + return pg + + def execute(self, cube: Union[DataCube, VectorCube], process_id: Optional[str] = None) -> dict: + """ + Execute given cube (synchronously) and return observed process graph (or subset thereof). + + :param cube: cube to execute on dummy back-end + :param process_id: just return single process graph node with this process_id + :return: process graph (flat graph representation) or process graph node + """ + cube.execute() + return self.get_pg(process_id=process_id) + + +def build_capabilities( + *, + api_version: str = "1.0.0", + stac_version: str = "0.9.0", + basic_auth: bool = True, + oidc_auth: bool = True, + collections: bool = True, + processes: bool = True, + sync_processing: bool = True, + validation: bool = False, + batch_jobs: bool = True, + udp: bool = False, +) -> dict: + """Build a dummy capabilities document for testing purposes.""" + + endpoints = [] + if basic_auth: + endpoints.append({"path": "/credentials/basic", "methods": ["GET"]}) + if oidc_auth: + endpoints.append({"path": "/credentials/oidc", "methods": ["GET"]}) + if basic_auth or oidc_auth: + endpoints.append({"path": "/me", "methods": ["GET"]}) + + if collections: + endpoints.append({"path": "/collections", "methods": ["GET"]}) + endpoints.append({"path": "/collections/{collection_id}", "methods": ["GET"]}) + if processes: + endpoints.append({"path": "/processes", "methods": ["GET"]}) + if sync_processing: + endpoints.append({"path": "/result", "methods": ["POST"]}) + if validation: + endpoints.append({"path": "/validation", "methods": ["POST"]}) + if batch_jobs: + endpoints.extend( + [ + {"path": "/jobs", "methods": ["GET", "POST"]}, + {"path": "/jobs/{job_id}", "methods": ["GET", "DELETE"]}, + {"path": "/jobs/{job_id}/results", "methods": ["GET", "POST", "DELETE"]}, + {"path": "/jobs/{job_id}/logs", "methods": ["GET"]}, + ] + ) + if udp: + endpoints.extend( + [ + {"path": "/process_graphs", "methods": ["GET"]}, + {"path": "/process_graphs/{process_graph_id", "methods": ["GET", "PUT", "DELETE"]}, + ] + ) + + capabilities = { + "api_version": api_version, + "stac_version": stac_version, + "id": "dummy", + "title": "Dummy openEO back-end", + "description": "Dummy openeEO back-end", + "endpoints": endpoints, + "links": [], + } + return capabilities diff --git a/lib/openeo/rest/auth/__init__.py b/lib/openeo/rest/auth/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/openeo/rest/auth/auth.py b/lib/openeo/rest/auth/auth.py new file mode 100644 index 000000000..ca9b2bbd9 --- /dev/null +++ b/lib/openeo/rest/auth/auth.py @@ -0,0 +1,53 @@ +import collections +from typing import Optional + +from requests import Request +from requests.auth import AuthBase + + +class OpenEoApiAuthBase(AuthBase): + """ + Base class for authentication with the OpenEO REST API. + + Follows the authentication approach of the requests library: + an auth object is a callable object that can be passed with get/post request + to manipulate this request (typically setting headers). + """ + + def __call__(self, req: Request) -> Request: + # Do nothing by default + return req + + +class NullAuth(OpenEoApiAuthBase): + """No authentication""" + pass + + +class BearerAuth(OpenEoApiAuthBase): + """ + Requests are authenticated through a bearer token + https://open-eo.github.io/openeo-api/apireference/#section/Authentication/Bearer + """ + + def __init__(self, bearer: str): + self.bearer = bearer + + def __call__(self, req: Request) -> Request: + # Add bearer authorization header. + req.headers['Authorization'] = "Bearer {b}".format(b=self.bearer) + return req + + +class BasicBearerAuth(BearerAuth): + """Bearer token for Basic Auth (openEO API 1.0.0 style)""" + + def __init__(self, access_token: str): + super().__init__(bearer='basic//{t}'.format(t=access_token)) + + +class OidcBearerAuth(BearerAuth): + """Bearer token for OIDC Auth (openEO API 1.0.0 style)""" + + def __init__(self, provider_id: str, access_token: str): + super().__init__(bearer='oidc/{p}/{t}'.format(p=provider_id, t=access_token)) diff --git a/lib/openeo/rest/auth/cli.py b/lib/openeo/rest/auth/cli.py new file mode 100644 index 000000000..29784d4a0 --- /dev/null +++ b/lib/openeo/rest/auth/cli.py @@ -0,0 +1,381 @@ +import argparse +import builtins +import json +import logging +import sys +from collections import OrderedDict +from getpass import getpass +from pathlib import Path +from typing import List, Tuple + +from openeo import Connection, connect +from openeo.capabilities import ApiVersionException +from openeo.rest.auth.config import AuthConfig, RefreshTokenStore +from openeo.rest.auth.oidc import OidcProviderInfo + +_log = logging.getLogger(__name__) + + +class CliToolException(RuntimeError): + pass + + +_OIDC_FLOW_CHOICES = [ + "auth-code", + "device", + # TODO: add client credentials flow? +] + + +def main(argv=None): + root_parser = argparse.ArgumentParser( + description="Tool to manage openEO related authentication and configuration." + ) + root_parser.add_argument( + "--verbose", "-v", action="count", default=0, + help="Increase logging verbosity. Can be given multiple times." + ) + root_subparsers = root_parser.add_subparsers(title="Subcommands", dest="subparser_name") + + # Command: paths + paths_parser = root_subparsers.add_parser( + "paths", help="Show paths to config/token files." + ) + paths_parser.set_defaults(func=main_paths) + + # Command: config-dump + config_dump_parser = root_subparsers.add_parser( + "config-dump", help="Dump config file.", aliases=["config"] + ) + config_dump_parser.set_defaults(func=main_config_dump) + config_dump_parser.add_argument("--show-secrets", action="store_true", help="Don't redact secrets in the dump.") + + # Command: token-dump + token_dump_parser = root_subparsers.add_parser( + "token-dump", help="Dump OpenID Connect refresh tokens file.", aliases=["tokens"] + ) + token_dump_parser.set_defaults(func=main_token_dump) + token_dump_parser.add_argument("--show-secrets", action="store_true", help="Don't redact secrets in the dump.") + + # Command: token-clear + token_clear_parser = root_subparsers.add_parser( + "token-clear", help="Remove OpenID Connect refresh tokens file." + ) + token_clear_parser.set_defaults(func=main_token_clear) + token_clear_parser.add_argument("--force", "-f", action="store_true", help="Remove without asking confirmation.") + + # Command: add-basic + add_basic_parser = root_subparsers.add_parser( + "add-basic", help="Add or update config entry for basic auth." + ) + add_basic_parser.set_defaults(func=main_add_basic) + add_basic_parser.add_argument("backend", help="OpenEO Backend URL.") + add_basic_parser.add_argument("--username", help="Basic auth username.") + add_basic_parser.add_argument( + "--no-try", dest="try_auth", action="store_false", + help="Don't try out the credentials against the backend, just store them." + ) + + # Command: add-oidc + add_oidc_parser = root_subparsers.add_parser( + "add-oidc", help="Add or update config entry for OpenID Connect." + ) + add_oidc_parser.set_defaults(func=main_add_oidc) + add_oidc_parser.add_argument("backend", help="OpenEO Backend URL.") + add_oidc_parser.add_argument("--provider-id", help="Provider ID to use.") + add_oidc_parser.add_argument("--client-id", help="Client ID to use.") + add_oidc_parser.add_argument( + "--no-client-secret", dest="ask_client_secret", default=True, action="store_false", + help="Don't ask for secret (because client does not need one)." + ) + add_oidc_parser.add_argument( + "--use-default-client", action="store_true", + help="Use default client (as provided by backend)." + ) + + # Command: oidc-auth + oidc_auth_parser = root_subparsers.add_parser( + "oidc-auth", help="Do OpenID Connect authentication flow and store refresh tokens." + ) + oidc_auth_parser.set_defaults(func=main_oidc_auth) + oidc_auth_parser.add_argument("backend", help="OpenEO Backend URL.") + oidc_auth_parser.add_argument("--provider-id", help="Provider ID to use.") + oidc_auth_parser.add_argument( + "--flow", choices=_OIDC_FLOW_CHOICES, default="device", + help="OpenID Connect flow to use (default: device)." + ) + oidc_auth_parser.add_argument( + "--timeout", type=int, default=60, help="Timeout in seconds to wait for (user) response." + ) + + # Parse arguments and execute sub-command + args = root_parser.parse_args(argv) + logging.basicConfig(level={0: logging.WARN, 1: logging.INFO}.get(args.verbose, logging.DEBUG)) + _log.debug(repr(args)) + if args.subparser_name: + args.func(args) + else: + root_parser.print_help() + + +def main_paths(args): + """ + Print paths of auth config file and refresh token cache file. + """ + + def describe(p: Path): + if p.exists(): + return "perms: 0o{p:o}, size: {s}B".format(p=p.stat().st_mode & 0o777, s=p.stat().st_size) + else: + return "does not exist" + + config_path = AuthConfig().path + print("openEO auth config: {p} ({d})".format(p=str(config_path), d=describe(config_path))) + tokens_path = RefreshTokenStore().path + print("openEO OpenID Connect refresh token store: {p} ({d})".format(p=str(tokens_path), d=describe(tokens_path))) + + +def _redact(d: dict, keys_to_redact: List[str]): + """Redact secrets in given dict in-place.""" + for k, v in d.items(): + if k in keys_to_redact: + d[k] = "" + elif isinstance(v, dict): + _redact(v, keys_to_redact=keys_to_redact) + + +def main_config_dump(args): + """ + Dump auth config file + """ + config = AuthConfig() + print("### {p} ".format(p=str(config.path)).ljust(80, "#")) + data = config.load(empty_on_file_not_found=False) + if not args.show_secrets: + _redact(data, keys_to_redact=["client_secret", "password", "refresh_token"]) + json.dump(data, fp=sys.stdout, indent=2) + print() + + +def main_token_dump(args): + """ + Dump refresh token file + """ + tokens = RefreshTokenStore() + print("### {p} ".format(p=str(tokens.path)).ljust(80, "#")) + data = tokens.load(empty_on_file_not_found=False) + if not args.show_secrets: + _redact(data, keys_to_redact=["client_secret", "password", "refresh_token"]) + json.dump(data, fp=sys.stdout, indent=2) + print() + + +def main_token_clear(args): + """ + Remove refresh token file + """ + tokens = RefreshTokenStore() + path = tokens.path + if path.exists(): + if not args.force: + answer = builtins.input(f"Remove refresh token file {path}? 'y' or 'n': ") + if answer.lower()[:1] != "y": + print("Keeping refresh token file.") + return + tokens.remove() + print(f"Removed refresh token file {path}.") + else: + print(f"No refresh token file at {path}.") + + +def main_add_basic(args): + """ + Add a config entry for basic auth + """ + backend = args.backend + username = args.username + try_auth = args.try_auth + config = AuthConfig() + + print("Will add basic auth config for backend URL {b!r}".format(b=backend)) + print("to config file: {c!r}".format(c=str(config.path))) + + # Find username and password + if not username: + username = builtins.input("Enter username and press enter: ") + print("Using username {u!r}".format(u=username)) + password = getpass("Enter password and press enter: ") or None + + if try_auth: + print("Trying to authenticate with {b!r}".format(b=backend)) + con = connect(backend) + con.authenticate_basic(username, password) + print("Successfully authenticated {u!r}".format(u=username)) + + config.set_basic_auth(backend=backend, username=username, password=password) + print("Saved credentials to {p!r}".format(p=str(config.path))) + + +def _interactive_choice(title: str, options: List[Tuple[str, str]], attempts=10) -> str: + """ + Let user choose between options (given as dict) and return chosen key + """ + print(title) + for c, (k, v) in enumerate(options): + print("[{c:d}] {v}".format(c=c + 1, v=v)) + for _ in range(attempts): + try: + entered = builtins.input("Choose one (enter index): ") + return options[int(entered) - 1][0] + except Exception: + pass + raise CliToolException("Failed to pick valid option.") + + +def show_warning(message: str): + _log.warning(message) + + +def main_add_oidc(args): + """ + Add a config entry for OIDC auth + """ + backend = args.backend + provider_id = args.provider_id + client_id = args.client_id + ask_client_secret = args.ask_client_secret + use_default_client = args.use_default_client + config = AuthConfig() + + print("Will add OpenID Connect auth config for backend URL {b!r}".format(b=backend)) + print("to config file: {c!r}".format(c=str(config.path))) + + con = connect(backend) + con.capabilities().api_version_check.require_at_least("1.0.0") + + # Find provider ID + oidc_info = con.get("/credentials/oidc", expected_status=200).json() + providers = OrderedDict((p["id"], OidcProviderInfo.from_dict(p)) for p in oidc_info["providers"]) + + if not providers: + raise CliToolException("No OpenID Connect providers listed by backend {b!r}.".format(b=backend)) + if not provider_id: + if len(providers) == 1: + provider_id = list(providers.keys())[0] + else: + provider_id = _interactive_choice( + title="Backend {b!r} has multiple OpenID Connect providers.".format(b=backend), + options=[(p.id, "{t} (issuer {s})".format(t=p.title, s=p.issuer)) for p in providers.values()] + ) + if provider_id not in providers: + raise CliToolException("Invalid provider ID {p!r}. Should be one of {o}.".format( + p=provider_id, o=list(providers.keys()) + )) + provider = providers[provider_id] + print("Using provider ID {p!r} (issuer {i!r})".format(p=provider_id, i=provider.issuer)) + + # Get client_id and client_secret (if necessary) + if use_default_client: + if not provider.default_clients: + show_warning("No default clients declared for provider {p!r}".format(p=provider_id)) + client_id, client_secret = None, None + else: + if not client_id: + if provider.default_clients: + client_prompt = "Enter client_id or leave empty to use default client, and press enter: " + else: + client_prompt = "Enter client_id and press enter: " + client_id = builtins.input(client_prompt).strip() or None + print("Using client ID {u!r}".format(u=client_id)) + if not client_id and not provider.default_clients: + show_warning("Given client ID was empty.") + + if client_id and ask_client_secret: + client_secret = getpass("Enter client_secret or leave empty to not use a secret, and press enter: ") or None + else: + client_secret = None + + config.set_oidc_client_config( + backend=backend, provider_id=provider_id, client_id=client_id, client_secret=client_secret, + issuer=provider.issuer + ) + print("Saved client information to {p!r}".format(p=str(config.path))) + + +_webbrowser_open = None + + +def main_oidc_auth(args): + """ + Do OIDC auth flow and store refresh tokens. + """ + backend = args.backend + oidc_flow = args.flow + provider_id = args.provider_id + timeout = args.timeout + + config = AuthConfig() + + print("Will do OpenID Connect flow to authenticate with backend {b!r}.".format(b=backend)) + print("Using config {c!r}.".format(c=str(config.path))) + + # Determine provider + provider_configs = config.get_oidc_provider_configs(backend=backend) + _log.debug("Provider configs: {c!r}".format(c=provider_configs)) + if not provider_id: + if len(provider_configs) == 0: + print("Will try to use default provider_id.") + provider_id = None + elif len(provider_configs) == 1: + provider_id = list(provider_configs.keys())[0] + else: + provider_id = _interactive_choice( + title="Multiple OpenID Connect providers available for backend {b!r}".format(b=backend), + options=sorted( + (k, "{k}: issuer {s}".format(k=k, s=v.get("issuer", "n/a"))) + for k, v in provider_configs.items() + ) + ) + if not (provider_id is None or provider_id in provider_configs): + raise CliToolException("Invalid provider ID {p!r}. Should be `None` or one of {o}.".format( + p=provider_id, o=list(provider_configs.keys()) + )) + print("Using provider ID {p!r}.".format(p=provider_id)) + + # Get client id and secret + client_id, client_secret = config.get_oidc_client_configs(backend=backend, provider_id=provider_id) + if client_id: + print("Using client ID {c!r}.".format(c=client_id)) + else: + print("Will try to use default client.") + + refresh_token_store = RefreshTokenStore() + con = Connection(backend, refresh_token_store=refresh_token_store) + if oidc_flow == "auth-code": + print("Starting OpenID Connect authorization code flow:") + print("a browser window should open allowing you to log in with the identity provider\n" + "and grant access to the client {c!r} (timeout: {t}s).".format(c=client_id, t=timeout)) + con.authenticate_oidc_authorization_code( + client_id=client_id, client_secret=client_secret, + provider_id=provider_id, + timeout=timeout, + store_refresh_token=True, + webbrowser_open=_webbrowser_open + ) + print("The OpenID Connect authorization code flow was successful.") + elif oidc_flow == "device": + print("Starting OpenID Connect device flow.") + con.authenticate_oidc_device( + client_id=client_id, client_secret=client_secret, + provider_id=provider_id, + store_refresh_token=True + ) + print("The OpenID Connect device flow was successful.") + else: + raise CliToolException("Invalid flow {f!r}".format(f=oidc_flow)) + + print("Stored refresh token in {p!r}".format(p=str(refresh_token_store.path))) + + +if __name__ == '__main__': + main() diff --git a/lib/openeo/rest/auth/config.py b/lib/openeo/rest/auth/config.py new file mode 100644 index 000000000..d76697de7 --- /dev/null +++ b/lib/openeo/rest/auth/config.py @@ -0,0 +1,224 @@ +""" +Functionality to store and retrieve authentication settings (usernames, passwords, client ids, ...) +from local config files. +""" + +# TODO: also allow to set client_id, client_secret, refresh_token through env variables? + + +import json +import logging +import platform +import stat +from datetime import datetime +from pathlib import Path +from typing import Dict, Tuple, Union + +from openeo import __version__ +from openeo.config import get_user_config_dir, get_user_data_dir +from openeo.util import deep_get, deep_set, rfc3339 + +try: + # Use oschmod when available (fall back to POSIX-only functionality from stdlib otherwise) + # TODO: enforce oschmod as dependency for all platforms? + import oschmod +except ImportError: + oschmod = None + + +_PRIVATE_PERMS = stat.S_IRUSR | stat.S_IWUSR + +log = logging.getLogger(__name__) + + +def get_file_mode(path: Path) -> int: + """Get the file permission bits in a way that works on both *nix and Windows platforms.""" + if oschmod: + return oschmod.get_mode(str(path)) + return path.stat().st_mode + + +def set_file_mode(path: Path, mode: int): + """Set the file permission bits in a way that works on both *nix and Windows platforms.""" + if oschmod: + oschmod.set_mode(str(path), mode=mode) + else: + path.chmod(mode=mode) + + +def assert_private_file(path: Path): + """Check that given file is only readable by user.""" + mode = get_file_mode(path) + if (mode & stat.S_IRWXG) or (mode & stat.S_IRWXO): + message = "File {p} could be readable by others: mode {a:o} (expected: {e:o}).".format( + p=path, a=mode & (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO), e=_PRIVATE_PERMS + ) + if platform.system() == "Windows": + log.info(message) + else: + raise PermissionError(message) + + +def utcnow_rfc3339() -> str: + """Current datetime formatted as RFC-3339 string.""" + return rfc3339.datetime(datetime.utcnow()) + + +def _normalize_url(url: str) -> str: + """Normalize a url (trim trailing slash), to simplify equality checking.""" + return url.rstrip("/") or "/" + + +class PrivateJsonFile: + """ + Base class for private config/data files in JSON format. + """ + + DEFAULT_FILENAME = "private.json" + + def __init__(self, path: Path = None): + if path is None: + path = self.default_path() + if path.is_dir(): + path = path / self.DEFAULT_FILENAME + self._path = path + + @property + def path(self) -> Path: + return self._path + + @classmethod + def default_path(cls) -> Path: + return get_user_config_dir(auto_create=True) / cls.DEFAULT_FILENAME + + def load(self, empty_on_file_not_found=True) -> dict: + """Load all data from file""" + if not self._path.exists(): + if empty_on_file_not_found: + return {} + raise FileNotFoundError(self._path) + assert_private_file(self._path) + log.debug("Loading private JSON file {p}".format(p=self._path)) + # TODO: add file locking to avoid race conditions? + with self._path.open("r", encoding="utf8") as f: + return json.load(f) + + def _write(self, data: dict): + """Write whole data to file.""" + log.debug("Writing private JSON file {p}".format(p=self._path)) + # TODO: add file locking to avoid race conditions? + with self._path.open("w", encoding="utf8") as f: + json.dump(data, f, indent=2) + set_file_mode(self._path, mode=_PRIVATE_PERMS) + assert_private_file(self._path) + + def get(self, *keys, default=None) -> Union[dict, str, int]: + """Load JSON file and do deep get with given keys.""" + result = deep_get(self.load(), *keys, default=default) + if isinstance(result, Exception) or (isinstance(result, type) and issubclass(result, Exception)): + # pylint: disable=raising-bad-type + raise result + return result + + def set(self, *keys, value): + data = self.load() + deep_set(data, *keys, value=value) + self._write(data) + + def remove(self): + if self._path.exists(): + log.debug(f"Removing {self._path}") + self._path.unlink() + + +class AuthConfig(PrivateJsonFile): + DEFAULT_FILENAME = "auth-config.json" + + @classmethod + def default_path(cls) -> Path: + return get_user_config_dir(auto_create=True) / cls.DEFAULT_FILENAME + + def _write(self, data: dict): + # When starting fresh: add some metadata and defaults + if "metadata" not in data: + data["metadata"] = { + "type": "AuthConfig", + "created": utcnow_rfc3339(), + "created_by": "openeo-python-client {v}".format(v=__version__), + "version": 1, + } + data.setdefault("general", {}) + data.setdefault("backends", {}) + return super()._write(data=data) + + def get_basic_auth(self, backend: str) -> Tuple[Union[None, str], Union[None, str]]: + """Get username/password combo for given backend. Values will be None when no config is available.""" + basic = self.get("backends", _normalize_url(backend), "basic", default={}) + username = basic.get("username") + password = basic.get("password") if username else None + return username, password + + def set_basic_auth(self, backend: str, username: str, password: Union[str, None]): + data = self.load() + keys = ("backends", _normalize_url(backend), "basic",) + # TODO: support multiple basic auth credentials? (pick latest by default for example) + deep_set(data, *keys, "date", value=utcnow_rfc3339()) + deep_set(data, *keys, "username", value=username) + if password: + deep_set(data, *keys, "password", value=password) + self._write(data) + + def get_oidc_provider_configs(self, backend: str) -> Dict[str, dict]: + """ + Get provider config items for given backend. + + Returns a dict mapping provider_id to dicts with "client_id" and "client_secret" items + """ + return self.get("backends", _normalize_url(backend), "oidc", "providers", default={}) + + def get_oidc_client_configs(self, backend: str, provider_id: str) -> Tuple[str, str]: + """ + Get client_id and client_secret for given backend+provider_id. Values will be None when no config is available. + """ + client = self.get("backends", _normalize_url(backend), "oidc", "providers", provider_id, default={}) + client_id = client.get("client_id") + client_secret = client.get("client_secret") if client_id else None + return client_id, client_secret + + def set_oidc_client_config( + self, backend: str, provider_id: str, + client_id: Union[str, None], client_secret: Union[str, None] = None, issuer: Union[str, None] = None + ): + data = self.load() + keys = ("backends", _normalize_url(backend), "oidc", "providers", provider_id) + # TODO: support multiple clients? (pick latest by default for example) + deep_set(data, *keys, "date", value=utcnow_rfc3339()) + deep_set(data, *keys, "client_id", value=client_id) + deep_set(data, *keys, "client_secret", value=client_secret) + if issuer: + deep_set(data, *keys, "issuer", value=issuer) + self._write(data) + + +class RefreshTokenStore(PrivateJsonFile): + """ + Basic JSON-file based storage of refresh tokens. + """ + + DEFAULT_FILENAME = "refresh-tokens.json" + + @classmethod + def default_path(cls) -> Path: + return get_user_data_dir(auto_create=True) / cls.DEFAULT_FILENAME + + def get_refresh_token(self, issuer: str, client_id: str) -> Union[str, None]: + return self.get(_normalize_url(issuer), client_id, "refresh_token", default=None) + + def set_refresh_token(self, issuer: str, client_id: str, refresh_token: str): + data = self.load() + log.info("Storing refresh token for issuer {i!r} (client {c!r})".format(i=issuer, c=client_id)) + deep_set(data, _normalize_url(issuer), client_id, value={ + "date": utcnow_rfc3339(), + "refresh_token": refresh_token, + }) + self._write(data) diff --git a/lib/openeo/rest/auth/oidc.py b/lib/openeo/rest/auth/oidc.py new file mode 100644 index 000000000..c058a9568 --- /dev/null +++ b/lib/openeo/rest/auth/oidc.py @@ -0,0 +1,911 @@ +""" +OpenID Connect related functionality and helpers. + +""" + +from __future__ import annotations + +import base64 +import contextlib +import enum +import functools +import hashlib +import http.server +import inspect +import json +import logging +import random +import string +import threading +import time +import urllib.parse +import warnings +import webbrowser +from queue import Empty, Queue +from typing import Callable, List, NamedTuple, Optional, Tuple, Union + +import requests + +import openeo +from openeo.internal.jupyter import in_jupyter_context +from openeo.rest import OpenEoClientException +from openeo.util import SimpleProgressBar, clip, dict_no_none, url_join + +log = logging.getLogger(__name__) + + +class QueuingRequestHandler(http.server.BaseHTTPRequestHandler): + """ + Base class for simple HTTP request handlers to be used in threaded context. + The handler puts the requested paths in a thread-safe queue + """ + + def __init__(self, *args, **kwargs): + self._queue = kwargs.pop('queue', None) or Queue() + super().__init__(*args, **kwargs) + + def do_GET(self): + log.debug('{c} GET {p}'.format(c=self.__class__.__name__, p=self.path)) + status, body, headers = self.queue(self.path) + self.send_response(status) + self.send_header('Content-Length', str(len(body))) + for k, v in headers.items(): + self.send_header(k, v) + self.end_headers() + self.wfile.write(body.encode("utf-8")) + + def queue(self, path: str): + self._queue.put(path) + return 200, "queued", {} + + @classmethod + def with_queue(cls, queue: Queue): + """Create a factory for this object pre-bound with given queue object""" + return functools.partial(cls, queue=queue) + + def log_message(self, format, *args): + # Override the default implementation, which is a hardcoded `sys.stderr.write` + log.debug(format % args) + + +class OAuthRedirectRequestHandler(QueuingRequestHandler): + """Request handler for OAuth redirects""" + PATH = '/callback' + + TEMPLATE = """ + + openEO OIDC auth + + {content} +

    openEO Python client {version}

    + + + """ + + def queue(self, path: str): + if path.startswith(self.PATH + '?'): + super().queue(path) + # TODO: auto-close browser tab/window? + # TODO: make it a nicer page and bit more of metadata? + status = 200 + content = "

    OIDC Redirect URL request received.

    You can close this browser tab now.

    " + else: + status = 404 + content = "

    Not found.

    " + body = self.TEMPLATE.format(content=content, version=openeo.client_version()) + return status, body, {"Content-Type": "text/html; charset=UTF-8"} + + +class HttpServerThread(threading.Thread): + """ + Thread that runs a HTTP server (`http.server.HTTPServer`) + """ + + def __init__(self, RequestHandlerClass, server_address: Tuple[str, int] = None): + # Make it a daemon to minimize potential shutdown issues due to `serve_forever` + super().__init__(daemon=True) + self._RequestHandlerClass = RequestHandlerClass + # Server address ('', 0): listen on all ips and let OS pick a free port + self._server_address = server_address or ('', 0) + self._server = None + + def start(self): + self._server = http.server.HTTPServer(self._server_address, self._RequestHandlerClass) + self._log_status("start thread") + super().start() + + def run(self): + self._log_status("start serving") + self._server.serve_forever() + self._log_status("stop serving") + + def shutdown(self): + self._log_status("shut down thread") + self._server.shutdown() + + def server_address_info(self) -> Tuple[int, str, str]: + """ + Get server address info: (port, host_address, fully_qualified_domain_name) + """ + if self._server is None: + raise RuntimeError("Server is not set up yet") + return self._server.server_port, self._server.server_address[0], self._server.server_name + + def _log_status(self, message): + port, host, fqdn = self.server_address_info() + log.info("{c}: {m} (at {h}:{p}, {f})".format(c=self.__class__.__name__, m=message, h=host, p=port, f=fqdn)) + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.shutdown() + self.join() + self._log_status("thread joined") + + +def create_timer() -> Callable[[], float]: + """Create a timer function that returns elapsed time since creation of the timer function""" + start = time.time() + + def elapsed(): + return time.time() - start + + return elapsed + + +def drain_queue(queue: Queue, initial_timeout: float = 10, item_minimum: int = 1, tail_timeout=5, + on_empty=lambda **kwargs: None): + """ + Drain the given queue, requiring at least a given number of items (within an initial timeout). + + :param queue: queue to drain + :param initial_timeout: time in seconds within which a minimum number of items should be fetched + :param item_minimum: minimum number of items to fetch + :param tail_timeout: additional timeout to abort when queue doesn't get empty + :param on_empty: callable to call when/while queue is empty + :return: generator of items from the queue + """ + elapsed = create_timer() + + count = 0 + while True: + try: + yield queue.get(timeout=initial_timeout / 10) + count += 1 + except Empty: + on_empty(elapsed=elapsed(), count=count) + + if elapsed() > initial_timeout and count < item_minimum: + raise TimeoutError("Items after initial {t} timeout: {c} (<{m})".format( + c=count, m=item_minimum, t=initial_timeout)) + if queue.empty() and count >= item_minimum: + break + if elapsed() > initial_timeout + tail_timeout: + warnings.warn("Queue still not empty after overall timeout: aborting.") + break + + +def random_string(length=32, characters: str = None): + """ + Build a random string from given characters (alphanumeric by default) + """ + # TODO: move this to a utils module? + characters = characters or (string.ascii_letters + string.digits) + return "".join(random.choice(characters) for _ in range(length)) + + +class OidcException(OpenEoClientException): + pass + + +class AccessTokenResult(NamedTuple): + """Container for result of access_token request.""" + + access_token: str + id_token: Optional[str] = None + refresh_token: Optional[str] = None + + +def jwt_decode(token: str) -> Tuple[dict, dict]: + """ + Poor man's JWT decoding + TODO: use a real library that also handles verification properly? + """ + + def _decode(data: str) -> dict: + decoded = base64.b64decode(data + '=' * (4 - len(data) % 4)).decode('ascii') + return json.loads(decoded) + + header, payload, signature = token.split('.') + return _decode(header), _decode(payload) + + +class DefaultOidcClientGrant(enum.Enum): + """ + Enum with possible values for "grant_types" field of default OIDC clients provided by backend. + """ + IMPLICIT = "implicit" + AUTH_CODE = "authorization_code" + AUTH_CODE_PKCE = "authorization_code+pkce" + DEVICE_CODE = "urn:ietf:params:oauth:grant-type:device_code" + DEVICE_CODE_PKCE = "urn:ietf:params:oauth:grant-type:device_code+pkce" + REFRESH_TOKEN = "refresh_token" + + +# Type hint for function that checks if given list of OIDC grant types (DefaultOidcClientGrant enum values) +# fulfills a criterion. +GrantsChecker = Union[List[DefaultOidcClientGrant], Callable[[List[DefaultOidcClientGrant]], bool]] + + +class OidcProviderInfo: + """OpenID Connect Provider information, as provided by an openEO back-end (endpoint `/credentials/oidc`)""" + + def __init__( + self, + issuer: str = None, + discovery_url: str = None, + scopes: List[str] = None, + provider_id: str = None, + title: str = None, + default_clients: Union[List[dict], None] = None, + requests_session: Optional[requests.Session] = None, + ): + # TODO: id and title are required in the openEO API spec. + self.id = provider_id + self.title = title + if discovery_url: + self.discovery_url = discovery_url + elif issuer: + self.discovery_url = url_join(issuer, "/.well-known/openid-configuration") + else: + raise ValueError("At least `issuer` or `discovery_url` should be specified") + if not requests_session: + requests_session = requests.Session() + discovery_resp = requests_session.get(self.discovery_url, timeout=20) + discovery_resp.raise_for_status() + self.config = discovery_resp.json() + self.issuer = issuer or self.config["issuer"] + # Minimal set of scopes to request + self._supported_scopes = self.config.get("scopes_supported", ["openid"]) + self._scopes = {"openid"}.union(scopes or []).intersection(self._supported_scopes) + log.debug(f"Scopes: provider supported {self._supported_scopes} & backend desired {scopes} -> {self._scopes}") + self.default_clients = default_clients + + @classmethod + def from_dict(cls, data: dict) -> OidcProviderInfo: + return cls( + provider_id=data["id"], title=data["title"], + issuer=data["issuer"], + scopes=data.get("scopes"), + default_clients=data.get("default_clients"), + ) + + def get_scopes_string(self, request_refresh_token: bool = False) -> str: + """ + Build "scope" string for authentication request. + + :param request_refresh_token: include "offline_access" scope (if supported), + which some OIDC providers require in order to return refresh token + :return: space separated scope listing as single string + """ + scopes = self._scopes + if request_refresh_token and "offline_access" in self._supported_scopes: + scopes = scopes | {"offline_access"} + log.debug("Using scopes: {s}".format(s=scopes)) + return " ".join(sorted(scopes)) + + def get_default_client_id(self, grant_check: GrantsChecker) -> Union[str, None]: + """ + Get first default client that supports (as stated by provider's `grant_types`) + the desired grant types (as implemented by `grant_check`) + """ + if isinstance(grant_check, list): + # Simple `grant_check` mode: just provide list of grants that all must be supported. + desired_grants = grant_check + grant_check = lambda grants: all(g in grants for g in desired_grants) + + def normalize_grants(grants: List[str]): + for grant in grants: + try: + yield DefaultOidcClientGrant(grant) + except ValueError: + log.warning(f"Invalid OIDC grant type {grant!r}.") + + for client in self.default_clients or []: + client_id = client.get("id") + supported_grants = client.get("grant_types") + supported_grants = list(normalize_grants(supported_grants)) + if client_id and supported_grants and grant_check(supported_grants): + return client_id + + +class OidcClientInfo: + """ + Simple container holding basic info of an OIDC client + """ + + __slots__ = ["client_id", "provider", "client_secret"] + + def __init__(self, client_id: str, provider: OidcProviderInfo, client_secret: Optional[str] = None): + self.client_id = client_id + self.provider = provider + self.client_secret = client_secret + # TODO: also info client type (desktop app, web app, SPA, ...)? + + # TODO: load from config file + + def guess_device_flow_pkce_support(self): + """Best effort guess if PKCE should be used for device auth grant""" + # Check if this client is also defined as default client with device_code+pkce + default_clients = [c for c in self.provider.default_clients or [] if c["id"] == self.client_id] + grant_types = set(g for c in default_clients for g in c.get("grant_types", [])) + return any("device_code+pkce" in g for g in grant_types) + + +class OidcAuthenticator: + """ + Base class for OpenID Connect authentication flows. + """ + grant_type = NotImplemented + + def __init__( + self, + client_info: OidcClientInfo, + requests_session: Optional[requests.Session] = None, + ): + self._client_info = client_info + self._provider_config = client_info.provider.config + # TODO: check provider config (e.g. if grant type is supported) + self._requests = requests_session or requests.Session() + + @property + def client_info(self) -> OidcClientInfo: + return self._client_info + + @property + def client_id(self) -> str: + return self._client_info.client_id + + @property + def client_secret(self) -> str: + return self._client_info.client_secret + + @property + def provider_info(self) -> OidcProviderInfo: + return self._client_info.provider + + def get_tokens(self, request_refresh_token: bool = False) -> AccessTokenResult: + """Get access_token and possibly id_token+refresh_token.""" + result = self._do_token_post_request(post_data=self._get_token_endpoint_post_data()) + return self._get_access_token_result(result) + + def _get_token_endpoint_post_data(self) -> dict: + """Build POST data dict to send to token endpoint""" + return { + "grant_type": self.grant_type, + "client_id": self.client_id, + } + + def _do_token_post_request(self, post_data: dict) -> dict: + """Do POST to token endpoint to get access token""" + token_endpoint = self._provider_config['token_endpoint'] + log.info("Doing {g!r} token request {u!r} with post data fields {p!r} (client_id {c!r})".format( + g=self.grant_type, c=self.client_id, u=token_endpoint, p=list(post_data.keys())) + ) + resp = self._requests.post(url=token_endpoint, data=post_data) + if resp.status_code != 200: + # TODO: are other status_code values valid too? + raise OidcException("Failed to retrieve access token at {u!r}: {s} {r!r} {t!r}".format( + s=resp.status_code, r=resp.reason, u=resp.url, t=resp.text + )) + + result = resp.json() + log.debug("Token response with keys {k}".format(k=result.keys())) + return result + + def _get_access_token_result(self, data: dict, expected_nonce: str = None) -> AccessTokenResult: + """Parse JSON result from token request""" + return AccessTokenResult( + access_token=self._extract_token(data, "access_token"), + id_token=self._extract_token(data, "id_token", expected_nonce=expected_nonce, allow_absent=True), + refresh_token=self._extract_token(data, "refresh_token", allow_absent=True) + ) + + @staticmethod + def _extract_token(data: dict, key: str, expected_nonce: str = None, allow_absent=False) -> Union[str, None]: + """ + Extract token of given type ("access_token", "id_token", "refresh_token") from a token JSON response + """ + try: + token = data[key] + except KeyError: + if allow_absent: + return + raise OidcException("No {k!r} in response".format(k=key)) + if expected_nonce: + # TODO: verify the JWT properly? + _, payload = jwt_decode(token) + if payload['nonce'] != expected_nonce: + raise OidcException("Invalid nonce in {k}".format(k=key)) + return token + + +class PkceCode: + """ + Simple container for PKCE code verifier and code challenge. + + PKCE, pronounced "pixy", is short for "Proof Key for Code Exchange". + Also see https://tools.ietf.org/html/rfc7636 + """ + __slots__ = ["code_verifier", "code_challenge", "code_challenge_method"] + + def __init__(self): + self.code_verifier = random_string(64) + # Only SHA256 is supported for now. + self.code_challenge_method = "S256" + self.code_challenge = PkceCode.sha256_hash(self.code_verifier) + + @staticmethod + def sha256_hash(code: str) -> str: + """Apply SHA256 hash to code verifier to get code challenge""" + data = hashlib.sha256(code.encode('ascii')).digest() + return base64.urlsafe_b64encode(data).decode('ascii').replace('=', '') + + +class AuthCodeResult(NamedTuple): + auth_code: str + nonce: str + code_verifier: str + redirect_uri: str + + +class OidcAuthCodePkceAuthenticator(OidcAuthenticator): + """ + Implementation of OpenID Connect authentication using OAuth Authorization Code Flow with PKCE. + + This flow is to be used for interactive use cases (e.g. user is working in a Jupyter/IPython notebook). + + It goes roughly like this: + - A short living HTTP server is started in a side-thread to serve the redirect URI + that is required in this flow. + - A browser window/tab is opened showing the (third party) Identity Provider authorization endpoint + - (if not already:) User authenticates with the Identity Provider (e.g. with username and password) + - Identity Provider forwards to the redirect URI (which is served locally by the side-thread), + sending an authorization code (among others) along + - The request handler in the side thread captures the redirect and passes it to the main thread (through a queue) + - The main extracts the necessary information from the redirect request (like the authorization code) + and shuts down the side thread + - The authorization code is exchanged for an access code and id token + - The access code can be used as bearer token for subsequent API calls + + .. deprecated:: 0.19.0 + Usage of the Authorization Code flow is deprecated (because of its complexity) and will be removed. + """ + + grant_type = "authorization_code" + + TIMEOUT_DEFAULT = 60 + + def __init__( + self, + client_info: OidcClientInfo, + webbrowser_open: Callable = None, + timeout: int = None, + server_address: Tuple[str, int] = None, + requests_session: Optional[requests.Session] = None, + ): + super().__init__(client_info=client_info, requests_session=requests_session) + self._webbrowser_open = webbrowser_open or webbrowser.open + self._authentication_timeout = timeout or self.TIMEOUT_DEFAULT + self._server_address = server_address + + def _get_auth_code(self, request_refresh_token: bool = False) -> AuthCodeResult: + """ + Do OAuth authentication request and catch redirect to extract authentication code + :return: + """ + state = random_string(32) + nonce = random_string(21) + pkce = PkceCode() + + # Set up HTTP server (in separate thread) to catch OAuth redirect URL + callback_queue = Queue() + RequestHandlerClass = OAuthRedirectRequestHandler.with_queue(callback_queue) + http_server_thread = HttpServerThread( + RequestHandlerClass=RequestHandlerClass, + server_address=self._server_address + ) + with http_server_thread: + port, host, fqdn = http_server_thread.server_address_info() + # TODO: use fully qualified domain name instead of "localhost"? + # Otherwise things won't work when the client is for example + # running in a remotely hosted Jupyter setup. + # Maybe even FQDN will not resolve properly in the user's browser + # and we need additional means to get a working hostname? + redirect_uri = 'http://localhost:{p}'.format(f=fqdn, p=port) + OAuthRedirectRequestHandler.PATH + log.info("Using OAuth redirect URI {u!r}".format(u=redirect_uri)) + + # Build authentication URL + auth_url = "{endpoint}?{params}".format( + endpoint=self._provider_config['authorization_endpoint'], + params=urllib.parse.urlencode({ + "response_type": "code", + "client_id": self.client_id, + "scope": self._client_info.provider.get_scopes_string(request_refresh_token=request_refresh_token), + "redirect_uri": redirect_uri, + "state": state, + "nonce": nonce, + "code_challenge": pkce.code_challenge, + "code_challenge_method": pkce.code_challenge_method, + }) + ) + log.info("Sending user to auth URL {u!r}".format(u=auth_url)) + # Open browser window/tab with authentication URL + self._webbrowser_open(auth_url) + + # TODO: show some feedback here that we are waiting browser based interaction here? + + try: + # Collect data from redirect uri + log.info("Waiting for request to redirect URI (timeout {t}s)".format(t=self._authentication_timeout)) + # TODO: When authentication fails (e.g. identity provider is down), this might hang the client + # (e.g. jupyter notebook). Is there a way to abort this? use signals? handle "abort" request? + callbacks = list(drain_queue( + callback_queue, + initial_timeout=self._authentication_timeout, + on_empty=lambda **kwargs: log.info( + "No result yet (elapsed: {e:.2f}s)".format(e=kwargs.get("elapsed", 0)) + ) + )) + except TimeoutError: + raise OidcException("Timeout: no request to redirect URI after {t}s".format( + t=self._authentication_timeout) + ) + + if len(callbacks) != 1: + raise OidcException("Expected 1 OAuth redirect request, but got: {c}".format(c=len(callbacks))) + + # Parse OAuth redirect URL + redirect_request = callbacks[0] + log.debug("Parsing redirect request {r}".format(r=redirect_request)) + redirect_params = urllib.parse.parse_qs(urllib.parse.urlparse(redirect_request).query) + log.debug('Parsed redirect request: {p}'.format(p=redirect_params)) + if 'state' not in redirect_params or redirect_params['state'] != [state]: + raise OidcException("Invalid state") + if 'code' not in redirect_params: + raise OidcException("No auth code in redirect") + auth_code = redirect_params["code"][0] + + return AuthCodeResult( + auth_code=auth_code, nonce=nonce, code_verifier=pkce.code_verifier, redirect_uri=redirect_uri + ) + + def get_tokens(self, request_refresh_token: bool = False) -> AccessTokenResult: + """ + Do OpenID authentication flow with PKCE: + get auth code and exchange for access and id token + """ + # Get auth code from authentication provider + auth_code_result = self._get_auth_code(request_refresh_token=request_refresh_token) + + # Exchange authentication code for access token + result = self._do_token_post_request(post_data=dict_no_none( + grant_type=self.grant_type, + client_id=self.client_id, + client_secret=self.client_secret, + redirect_uri=auth_code_result.redirect_uri, + code=auth_code_result.auth_code, + code_verifier=auth_code_result.code_verifier, + )) + + return self._get_access_token_result(result, expected_nonce=auth_code_result.nonce) + + +class OidcClientCredentialsAuthenticator(OidcAuthenticator): + """ + Implementation of "Client Credentials" Flow. + """ + + grant_type = "client_credentials" + + def _get_token_endpoint_post_data(self) -> dict: + data = super()._get_token_endpoint_post_data() + data["client_secret"] = self.client_secret + data["scope"] = self._client_info.provider.get_scopes_string() + return data + + +class OidcResourceOwnerPasswordAuthenticator(OidcAuthenticator): + """ + Implementation of "Resource Owner Password Credentials" (ROPC) grant type. + + Note: This flow should only be used when end user owns (or highly trusts) the client code + and the password can be handled/stored/retrieved in a secure manner. + """ + + grant_type = "password" + + def __init__( + self, + client_info: OidcClientInfo, + username: str, + password: str, + requests_session: Optional[requests.Session] = None, + ): + super().__init__(client_info=client_info, requests_session=requests_session) + self._username = username + self._password = password + + def _get_token_endpoint_post_data(self) -> dict: + data = super()._get_token_endpoint_post_data() + data["client_secret"] = self.client_secret + data["scope"] = self._client_info.provider.get_scopes_string() + data["username"] = self._username + data["password"] = self._password + return data + + +class OidcRefreshTokenAuthenticator(OidcAuthenticator): + """ + Implementation of obtaining a new OpenID Connect access token through a refresh token. + """ + + grant_type = "refresh_token" + + def __init__( + self, + client_info: OidcClientInfo, + refresh_token: str, + requests_session: Optional[requests.Session] = None, + ): + super().__init__(client_info=client_info, requests_session=requests_session) + self._refresh_token = refresh_token + + def _get_token_endpoint_post_data(self) -> dict: + data = super()._get_token_endpoint_post_data() + if self.client_secret: + data["client_secret"] = self.client_secret + data["refresh_token"] = self._refresh_token + return data + + +class VerificationInfo(NamedTuple): + verification_uri: str + verification_uri_complete: Optional[str] + device_code: str + user_code: str + interval: int + + +def _like_print(display: Callable) -> Callable: + """Ensure that display function supports an `end` argument like `print`""" + if display is print or "end" in inspect.signature(display).parameters: + return display + else: + return lambda *args, end="\n", **kwargs: display(*args, **kwargs) + + +class _BasicDeviceCodePollUi: + """ + Basic (print + carriage return) implementation of the device code + polling loop UI (e.g. show progress bar and status). + """ + + def __init__( + self, + timeout: float, + elapsed: Callable[[], float], + max_width: int = 80, + display: Callable = print, + ): + self.timeout = timeout + self.elapsed = elapsed + self._max_width = max_width + self._status = "Authorization pending" + self._display = _like_print(display) + self._progress_bar = SimpleProgressBar(width=(max_width - 1) // 2) + + def _instructions(self, info: VerificationInfo) -> str: + if info.verification_uri_complete: + return f"Visit {info.verification_uri_complete} to authenticate." + else: + return f"Visit {info.verification_uri} and enter user code {info.user_code!r} to authenticate." + + def show_instructions(self, info: VerificationInfo) -> None: + self._display(self._instructions(info=info)) + + def set_status(self, status: str): + self._status = status + + def show_progress(self, status: Optional[str] = None): + if status: + self.set_status(status) + progress_bar = self._progress_bar.get(fraction=1.0 - self.elapsed() / self.timeout) + text = f"{progress_bar} {self._status}" + self._display(f"{text[:self._max_width]: <{self._max_width}s}", end="\r") + + def close(self): + self._display("", end="\n") + + +class _JupyterDeviceCodePollUi(_BasicDeviceCodePollUi): + def __init__( + self, + timeout: float, + elapsed: Callable[[], float], + max_width: int = 80, + ): + super().__init__(timeout=timeout, elapsed=elapsed, max_width=max_width) + import IPython.display + + self._instructions_display = IPython.display.display({"text/html": " "}, raw=True, display_id=True) + self._progress_display = IPython.display.display({"text/html": " "}, raw=True, display_id=True) + + def _instructions(self, info: VerificationInfo) -> str: + url = info.verification_uri_complete if info.verification_uri_complete else info.verification_uri + instructions = ( + f'Visit {url}' + ) + instructions += f' 📋' + if not info.verification_uri_complete: + instructions += f" and enter user code {info.user_code!r}" + instructions += " to authenticate." + return instructions + + def show_instructions(self, info: VerificationInfo) -> None: + self._instructions_display.update({"text/html": self._instructions(info=info)}, raw=True) + + def show_progress(self, status: Optional[str] = None): + # TODO Add emoticons to status? + if status: + self.set_status(status) + progress_bar = self._progress_bar.get(fraction=1.0 - self.elapsed() / self.timeout) + icon = self._status_icon(self._status) + self._progress_display.update({"text/html": f"{progress_bar} {icon} {self._status}"}, raw=True) + + def _status_icon(self, status: str) -> str: + status = status.lower() + if "polling" in status or "pending" in status: + return "\u231B" # Hourglass + elif "success" in status: + return "\u2705" # Green check mark + elif "timed out" in status: + return "\u274C" # Red cross mark + else: + return "" + + def close(self): + pass + + +class OidcDeviceCodePollTimeout(OidcException): + pass + + +class OidcDeviceAuthenticator(OidcAuthenticator): + """ + Implementation of OAuth Device Authorization grant/flow + """ + + grant_type = "urn:ietf:params:oauth:grant-type:device_code" + + DEFAULT_MAX_POLL_TIME = 5 * 60 + + def __init__( + self, + client_info: OidcClientInfo, + display: Callable[[str], None] = print, + device_code_url: Optional[str] = None, + max_poll_time: float = DEFAULT_MAX_POLL_TIME, + use_pkce: Optional[bool] = None, + requests_session: Optional[requests.Session] = None, + ): + super().__init__(client_info=client_info, requests_session=requests_session) + self._display = display + # Allow to specify/override device code URL for cases when it is not available in OIDC discovery doc. + self._device_code_url = device_code_url or self._provider_config.get("device_authorization_endpoint") + if not self._device_code_url: + raise OidcException("No support for device authorization grant") + self._max_poll_time = max_poll_time + if use_pkce is None: + use_pkce = client_info.client_secret is None and client_info.guess_device_flow_pkce_support() + self._pkce = PkceCode() if use_pkce else None + + def _get_verification_info(self, request_refresh_token: bool = False) -> VerificationInfo: + """Get verification URL and user code""" + post_data = { + "client_id": self.client_id, + "scope": self._client_info.provider.get_scopes_string(request_refresh_token=request_refresh_token) + } + if self._pkce: + post_data["code_challenge"] = self._pkce.code_challenge, + post_data["code_challenge_method"] = self._pkce.code_challenge_method + resp = self._requests.post(url=self._device_code_url, data=post_data) + if resp.status_code != 200: + raise OidcException("Failed to get verification URL and user code from {u!r}: {s} {r!r} {t!r}".format( + s=resp.status_code, r=resp.reason, u=resp.url, t=resp.text + )) + try: + data = resp.json() + verification_info = VerificationInfo( + # Google OAuth/OIDC implementation uses non standard "verification_url" instead of "verification_uri" + verification_uri=data["verification_uri"] if "verification_uri" in data else data["verification_url"], + # verification_uri_complete is optional, will be None if this key is not present + verification_uri_complete=data.get("verification_uri_complete"), + device_code=data["device_code"], + user_code=data["user_code"], + interval=data.get("interval", 5), + ) + except Exception as e: + raise OidcException("Failed to parse device authorization request: {e!r}".format(e=e)) + log.debug("Verification info: %r", verification_info) + return verification_info + + def get_tokens(self, request_refresh_token: bool = False) -> AccessTokenResult: + # Get verification url and user code + verification_info = self._get_verification_info(request_refresh_token=request_refresh_token) + + # Poll token endpoint + token_endpoint = self._provider_config['token_endpoint'] + post_data = { + "client_id": self.client_id, + "device_code": verification_info.device_code, + "grant_type": self.grant_type + } + if self._pkce: + post_data["code_verifier"] = self._pkce.code_verifier + else: + post_data["client_secret"] = self.client_secret + + poll_interval = verification_info.interval + log.debug("Start polling token endpoint (interval {i}s)".format(i=poll_interval)) + + elapsed = create_timer() + next_poll = elapsed() + poll_interval + # TODO: let poll UI determine sleep interval? + sleep = clip(self._max_poll_time / 100, min=1, max=5) + + if in_jupyter_context(): + poll_ui = _JupyterDeviceCodePollUi(timeout=self._max_poll_time, elapsed=elapsed) + else: + poll_ui = _BasicDeviceCodePollUi(timeout=self._max_poll_time, elapsed=elapsed, display=self._display) + poll_ui.show_instructions(info=verification_info) + + with contextlib.closing(poll_ui): + while elapsed() <= self._max_poll_time: + poll_ui.show_progress() + time.sleep(sleep) + + if elapsed() >= next_poll: + log.debug( + f"Doing {self.grant_type!r} token request {token_endpoint!r} with post data fields {list(post_data.keys())!r} (client_id {self.client_id!r})" + ) + poll_ui.show_progress(status="Polling") + resp = self._requests.post(url=token_endpoint, data=post_data, timeout=5) + if resp.status_code == 200: + log.info(f"[{elapsed():5.1f}s] Authorized successfully.") + poll_ui.show_progress(status="Authorized successfully") + # TODO remove progress bar when authorized succesfully? + return self._get_access_token_result(data=resp.json()) + else: + try: + error = resp.json()["error"] + except Exception: + error = "unknown" + log.info(f"[{elapsed():5.1f}s] not authorized yet: {error}") + if error == "authorization_pending": + poll_ui.show_progress(status="Authorization pending") + elif error == "slow_down": + poll_ui.show_progress(status="Slowing down") + poll_interval += 5 + else: + # TODO: skip occasional glitches (e.g. see `SkipIntermittentFailures` from openeo-aggregator) + raise OidcException( + f"Failed to retrieve access token at {token_endpoint!r}: {resp.status_code} {resp.reason!r} {resp.text!r}" + ) + next_poll = elapsed() + poll_interval + + poll_ui.show_progress(status="Timed out") + raise OidcDeviceCodePollTimeout(f"Timeout ({self._max_poll_time:.1f}s) while polling for access token.") diff --git a/lib/openeo/rest/auth/testing.py b/lib/openeo/rest/auth/testing.py new file mode 100644 index 000000000..854fb7ec7 --- /dev/null +++ b/lib/openeo/rest/auth/testing.py @@ -0,0 +1,317 @@ +""" +Helpers, mocks for testing (OIDC) authentication +""" + + +import base64 +import contextlib +import json +import urllib.parse +import uuid +from typing import List, Optional, Union +from unittest import mock + +import requests +import requests_mock.request + +from openeo.rest.auth.oidc import PkceCode, random_string +from openeo.util import dict_no_none, url_join + +DEVICE_CODE_POLL_INTERVAL = 2 + + +# Sentinel object to indicate that a field should be absent. +ABSENT = object() + + +class OidcMock: + """ + Fixture/mock to act as stand-in OIDC provider to test OIDC flows + """ + + def __init__( + self, + requests_mock: requests_mock.Mocker, + *, + expected_grant_type: Optional[str] = None, + oidc_issuer: str = "https://oidc.test", + expected_client_id: str = "myclient", + expected_fields: dict = None, + state: dict = None, + scopes_supported: List[str] = None, + device_code_flow_support: bool = True, + oidc_discovery_url: Optional[str] = None, + support_verification_uri_complete: bool = False, + ): + self.requests_mock = requests_mock + self.oidc_issuer = oidc_issuer + self.expected_grant_type = expected_grant_type + self.grant_request_history = [] + self.expected_client_id = expected_client_id + self.expected_fields = expected_fields or {} + self.expected_authorization_code = None + self.authorization_endpoint = url_join(self.oidc_issuer, "/auth") + self.token_endpoint = url_join(self.oidc_issuer, "/token") + self.device_code_endpoint = ( + url_join(self.oidc_issuer, "/device_code") + if device_code_flow_support + else None + ) + self.state = state or {} + self.scopes_supported = scopes_supported or ["openid", "email", "profile"] + self.support_verification_uri_complete = support_verification_uri_complete + self.mocks = {} + + oidc_discovery_url = oidc_discovery_url or url_join(oidc_issuer, "/.well-known/openid-configuration") + self.mocks["oidc_discovery"] = self.requests_mock.get( + oidc_discovery_url, + text=json.dumps( + dict_no_none( + { + # Rudimentary OpenID Connect discovery document + "issuer": self.oidc_issuer, + "authorization_endpoint": self.authorization_endpoint, + "token_endpoint": self.token_endpoint, + "device_authorization_endpoint": self.device_code_endpoint, + "scopes_supported": self.scopes_supported, + } + ) + ), + ) + self.mocks["token_endpoint"] = self.requests_mock.post(self.token_endpoint, text=self.token_callback) + + if self.device_code_endpoint: + self.mocks["device_code_endpoint"] = self.requests_mock.post( + self.device_code_endpoint, text=self.device_code_callback + ) + + def webbrowser_open(self, url: str): + """Doing fake browser and Oauth Provider handling here""" + assert url.startswith(self.authorization_endpoint) + params = self._get_query_params(url=url) + assert params["client_id"] == self.expected_client_id + assert params["response_type"] == "code" + assert params["scope"] == self.expected_fields["scope"] + for key in ["state", "nonce", "code_challenge", "redirect_uri", "scope"]: + self.state[key] = params[key] + redirect_uri = params["redirect_uri"] + # Don't mock the request to the redirect URI (it is hosted by the temporary web server in separate thread) + self.requests_mock.get(redirect_uri, real_http=True) + self.expected_authorization_code = "6uthc0d3" + requests.get( + redirect_uri, + params={"state": params["state"], "code": self.expected_authorization_code}, + ) + + def token_callback( + self, request: requests_mock.request._RequestObjectProxy, context + ): + params = self._get_query_params(query=request.text) + grant_type = params["grant_type"] + self.grant_request_history.append({"grant_type": grant_type}) + if self.expected_grant_type: + assert grant_type == self.expected_grant_type + callback = { + "authorization_code": self.token_callback_authorization_code, + "client_credentials": self.token_callback_client_credentials, + "password": self.token_callback_resource_owner_password_credentials, + "urn:ietf:params:oauth:grant-type:device_code": self.token_callback_device_code, + "refresh_token": self.token_callback_refresh_token, + }[grant_type] + result = callback(params=params, context=context) + try: + result_decoded = json.loads(result) + self.grant_request_history[-1]["response"] = result_decoded + except json.JSONDecodeError: + self.grant_request_history[-1]["response"] = result + return result + + def token_callback_authorization_code(self, params: dict, context): + """Fake code to token exchange by Oauth Provider""" + assert params["client_id"] == self.expected_client_id + assert params["grant_type"] == "authorization_code" + assert self.state["code_challenge"] == PkceCode.sha256_hash( + params["code_verifier"] + ) + assert params["code"] == self.expected_authorization_code + assert params["redirect_uri"] == self.state["redirect_uri"] + return self._build_token_response() + + def token_callback_client_credentials(self, params: dict, context): + assert params["client_id"] == self.expected_client_id + assert params["grant_type"] == "client_credentials" + assert params["scope"] == self.expected_fields["scope"] + assert params["client_secret"] == self.expected_fields["client_secret"] + return self._build_token_response(include_id_token=False, include_refresh_token=False) + + def token_callback_resource_owner_password_credentials(self, params: dict, context): + assert params["client_id"] == self.expected_client_id + assert params["grant_type"] == "password" + assert params["client_secret"] == self.expected_fields["client_secret"] + assert params["username"] == self.expected_fields["username"] + assert params["password"] == self.expected_fields["password"] + assert params["scope"] == self.expected_fields["scope"] + return self._build_token_response() + + def device_code_callback( + self, request: requests_mock.request._RequestObjectProxy, context + ): + params = self._get_query_params(query=request.text) + assert params["client_id"] == self.expected_client_id + assert params["scope"] == self.expected_fields["scope"] + self.state["device_code"] = random_string() + self.state["user_code"] = random_string(length=6).upper() + self.state["scope"] = params["scope"] + if "code_challenge" in self.expected_fields: + expect_code_challenge = self.expected_fields.get("code_challenge") + if expect_code_challenge in [True]: + assert "code_challenge" in params + self.state["code_challenge"] = params["code_challenge"] + elif expect_code_challenge in [False, ABSENT]: + assert "code_challenge" not in params + else: + raise ValueError(expect_code_challenge) + + response = { + # TODO: also verification_url (google tweak) + "verification_uri": url_join(self.oidc_issuer, "/dc"), + "device_code": self.state["device_code"], + "user_code": self.state["user_code"], + "interval": DEVICE_CODE_POLL_INTERVAL, + } + if self.support_verification_uri_complete: + response["verification_uri_complete"] = ( + response["verification_uri"] + f"?user_code={self.state['user_code']}" + ) + return json.dumps(response) + + def token_callback_device_code(self, params: dict, context): + assert params["client_id"] == self.expected_client_id + expected_client_secret = self.expected_fields.get("client_secret") + if expected_client_secret: + assert params["client_secret"] == expected_client_secret + else: + assert "client_secret" not in params + expect_code_verifier = self.expected_fields.get("code_verifier") + if expect_code_verifier in [True]: + assert ( + PkceCode.sha256_hash(params["code_verifier"]) + == self.state["code_challenge"] + ) + self.state["code_verifier"] = params["code_verifier"] + elif expect_code_verifier in [False, None, ABSENT]: + assert "code_verifier" not in params + assert "code_challenge" not in self.state + else: + raise ValueError(expect_code_verifier) + assert params["device_code"] == self.state["device_code"] + assert params["grant_type"] == "urn:ietf:params:oauth:grant-type:device_code" + # Fail with pending/too fast? + try: + result = self.state["device_code_callback_timeline"].pop(0) + except Exception: + result = "rest in peace" + if result == "great success": + return self._build_token_response() + else: + context.status_code = 400 + return json.dumps({"error": result}) + + def token_callback_refresh_token(self, params: dict, context): + assert params["client_id"] == self.expected_client_id + assert params["grant_type"] == "refresh_token" + if "client_secret" in self.expected_fields: + assert params["client_secret"] == self.expected_fields["client_secret"] + if params["refresh_token"] != self.expected_fields["refresh_token"]: + context.status_code = 401 + return json.dumps({"error": "invalid refresh token"}) + assert params["refresh_token"] == self.expected_fields["refresh_token"] + return self._build_token_response( + include_id_token=False, include_refresh_token=False + ) + + @staticmethod + def _get_query_params(*, url=None, query=None): + """Helper to extract query params from an url or query string""" + if not query: + query = urllib.parse.urlparse(url).query + params = {} + for param, values in urllib.parse.parse_qs(query).items(): + assert len(values) == 1 + params[param] = values[0] + return params + + @staticmethod + def _jwt_encode(header: dict, payload: dict, signature="s1gn6tur3"): + """Poor man's JWT encoding (just for unit testing purposes)""" + + def encode(d): + return ( + base64.urlsafe_b64encode(json.dumps(d).encode("ascii")) + .decode("ascii") + .replace("=", "") + ) + + return ".".join([encode(header), encode(payload), signature]) + + def _build_token_response( + self, + sub="123", + name="john", + include_id_token=True, + include_refresh_token: Optional[bool] = None, + ) -> str: + """Build JSON serialized access/id/refresh token response (and store tokens for use in assertions)""" + access_token = self._jwt_encode( + header={}, + payload=dict_no_none( + sub=sub, + name=name, + nonce=self.state.get("nonce"), + _uuid=uuid.uuid4().hex, + ), + ) + res = {"access_token": access_token} + + # Attempt to simulate real world refresh token support. + if include_refresh_token is None: + if "offline_access" in self.scopes_supported: + # "offline_access" scope as suggested in spec + # (https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess) + # Implemented by Microsoft, EGI Check-in + include_refresh_token = "offline_access" in self.state.get( + "scope", "" + ).split(" ") + else: + # Google OAuth style: no support for "offline_access", return refresh token automatically? + include_refresh_token = True + if include_refresh_token: + res["refresh_token"] = self._jwt_encode( + header={}, payload={"foo": "refresh", "_uuid": uuid.uuid4().hex} + ) + if include_id_token: + res["id_token"] = access_token + self.state.update(res) + self.state.update(name=name, sub=sub) + return json.dumps(res) + + def validate_access_token(self, access_token: str): + if access_token == self.state["access_token"]: + return {"user_id": self.state["name"], "sub": self.state["sub"]} + raise LookupError("Invalid access token") + + def invalidate_access_token(self): + self.state["access_token"] = "***invalidated***" + + def get_request_history( + self, url: Optional[str] = None, method: Optional[str] = None + ) -> List[requests_mock.request._RequestObjectProxy]: + """Get mocked request history: requests with given method/url.""" + if url and url.startswith("/"): + url = url_join(self.oidc_issuer, url) + return [ + r + for r in self.requests_mock.request_history + if (method is None or method.lower() == r.method.lower()) + and (url is None or url == r.url) + ] diff --git a/lib/openeo/rest/connection.py b/lib/openeo/rest/connection.py new file mode 100644 index 000000000..da86ab48b --- /dev/null +++ b/lib/openeo/rest/connection.py @@ -0,0 +1,1815 @@ +""" +This module provides a Connection object to manage and persist settings when interacting with the OpenEO API. +""" +from __future__ import annotations + +import datetime +import json +import logging +import os +import shlex +import sys +import warnings +from collections import OrderedDict +from pathlib import Path, PurePosixPath +from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Tuple, Union + +import requests +import shapely.geometry.base +from requests import Response +from requests.auth import AuthBase, HTTPBasicAuth + +import openeo +from openeo.capabilities import ApiVersionException, ComparableVersion +from openeo.config import config_log, get_config_option +from openeo.internal.documentation import openeo_process +from openeo.internal.graph_building import FlatGraphableMixin, PGNode, as_flat_graph +from openeo.internal.jupyter import VisualDict, VisualList +from openeo.internal.processes.builder import ProcessBuilderBase +from openeo.internal.warnings import deprecated, legacy_alias +from openeo.metadata import Band, BandDimension, CollectionMetadata, SpatialDimension, TemporalDimension +from openeo.rest import ( + CapabilitiesException, + OpenEoApiError, + OpenEoClientException, + OpenEoRestError, + OpenEoApiPlainError, +) +from openeo.rest._datacube import build_child_callback +from openeo.rest.auth.auth import BasicBearerAuth, BearerAuth, NullAuth, OidcBearerAuth +from openeo.rest.auth.config import AuthConfig, RefreshTokenStore +from openeo.rest.auth.oidc import ( + DefaultOidcClientGrant, + GrantsChecker, + OidcAuthCodePkceAuthenticator, + OidcAuthenticator, + OidcClientCredentialsAuthenticator, + OidcClientInfo, + OidcDeviceAuthenticator, + OidcException, + OidcProviderInfo, + OidcRefreshTokenAuthenticator, + OidcResourceOwnerPasswordAuthenticator, +) +from openeo.rest.datacube import DataCube, InputDate +from openeo.rest.graph_building import CollectionProperty +from openeo.rest.job import BatchJob, RESTJob +from openeo.rest.mlmodel import MlModel +from openeo.rest.rest_capabilities import RESTCapabilities +from openeo.rest.service import Service +from openeo.rest.udp import Parameter, RESTUserDefinedProcess +from openeo.rest.userfile import UserFile +from openeo.rest.vectorcube import VectorCube +from openeo.util import ( + ContextTimer, + LazyLoadCache, + dict_no_none, + ensure_list, + load_json_resource, + rfc3339, + str_truncate, + url_join, +) + +_log = logging.getLogger(__name__) + +# Default timeouts for requests +# TODO: get default_timeout from config? +DEFAULT_TIMEOUT = 20 * 60 +DEFAULT_TIMEOUT_SYNCHRONOUS_EXECUTE = 30 * 60 + + +class RestApiConnection: + """Base connection class implementing generic REST API request functionality""" + + def __init__( + self, + root_url: str, + auth: Optional[AuthBase] = None, + session: Optional[requests.Session] = None, + default_timeout: Optional[int] = None, + slow_response_threshold: Optional[float] = None, + ): + self._root_url = root_url + self.auth = auth or NullAuth() + self.session = session or requests.Session() + self.default_timeout = default_timeout or DEFAULT_TIMEOUT + self.default_headers = { + "User-Agent": "openeo-python-client/{cv} {py}/{pv} {pl}".format( + cv=openeo.client_version(), + py=sys.implementation.name, pv=".".join(map(str, sys.version_info[:3])), + pl=sys.platform + ) + } + self.slow_response_threshold = slow_response_threshold + + @property + def root_url(self): + return self._root_url + + def build_url(self, path: str): + return url_join(self._root_url, path) + + def _merged_headers(self, headers: dict) -> dict: + """Merge default headers with given headers""" + result = self.default_headers.copy() + if headers: + result.update(headers) + return result + + def _is_external(self, url: str) -> bool: + """Check if given url is external (not under root url)""" + root = self.root_url.rstrip("/") + return not (url == root or url.startswith(root + '/')) + + def request( + self, + method: str, + path: str, + *, + headers: Optional[dict] = None, + auth: Optional[AuthBase] = None, + check_error: bool = True, + expected_status: Optional[Union[int, Iterable[int]]] = None, + **kwargs, + ): + """Generic request send""" + url = self.build_url(path) + # Don't send default auth headers to external domains. + auth = auth or (self.auth if not self._is_external(url) else None) + slow_response_threshold = kwargs.pop("slow_response_threshold", self.slow_response_threshold) + if _log.isEnabledFor(logging.DEBUG): + _log.debug("Request `{m} {u}` with headers {h}, auth {a}, kwargs {k}".format( + m=method.upper(), u=url, h=headers and headers.keys(), a=type(auth).__name__, k=list(kwargs.keys())) + ) + with ContextTimer() as timer: + resp = self.session.request( + method=method, + url=url, + headers=self._merged_headers(headers), + auth=auth, + timeout=kwargs.pop("timeout", self.default_timeout), + **kwargs + ) + if slow_response_threshold and timer.elapsed() > slow_response_threshold: + _log.warning("Slow response: `{m} {u}` took {e:.2f}s (>{t:.2f}s)".format( + m=method.upper(), u=str_truncate(url, width=64), + e=timer.elapsed(), t=slow_response_threshold + )) + if _log.isEnabledFor(logging.DEBUG): + _log.debug("Got {r} headers {h!r}".format(r=resp, h=resp.headers)) + # Check for API errors and unexpected HTTP status codes as desired. + status = resp.status_code + expected_status = ensure_list(expected_status) if expected_status else [] + if check_error and status >= 400 and status not in expected_status: + self._raise_api_error(resp) + if expected_status and status not in expected_status: + raise OpenEoRestError("Got status code {s!r} for `{m} {p}` (expected {e!r}) with body {body}".format( + m=method.upper(), p=path, s=status, e=expected_status, body=resp.text) + ) + return resp + + def _raise_api_error(self, response: requests.Response): + """Convert API error response to Python exception""" + status_code = response.status_code + try: + # Try parsing the error info according to spec and wrap it in an exception. + info = response.json() + exception = OpenEoApiError( + http_status_code=status_code, + code=info.get("code", "unknown"), + message=info.get("message", "unknown error"), + id=info.get("id"), + url=info.get("url"), + ) + except Exception: + # Parsing of error info went wrong: let's see if we can still extract some helpful information. + text = response.text + error_message = None + _log.warning(f"Failed to parse API error response: [{status_code}] {text!r} (headers: {response.headers})") + if status_code == 502 and "Proxy Error" in text: + error_message = ( + "Received 502 Proxy Error." + " This typically happens when a synchronous openEO processing request takes too long and is aborted." + " Consider using a batch job instead." + ) + exception = OpenEoApiPlainError(message=text, http_status_code=status_code, error_message=error_message) + raise exception + + def get(self, path: str, stream: bool = False, auth: Optional[AuthBase] = None, **kwargs) -> Response: + """ + Do GET request to REST API. + + :param path: API path (without root url) + :param stream: True if the get request should be streamed, else False + :param auth: optional custom authentication to use instead of the default one + :return: response: Response + """ + return self.request("get", path=path, stream=stream, auth=auth, **kwargs) + + def post(self, path: str, json: Optional[dict] = None, **kwargs) -> Response: + """ + Do POST request to REST API. + + :param path: API path (without root url) + :param json: Data (as dictionary) to be posted with JSON encoding) + :return: response: Response + """ + return self.request("post", path=path, json=json, allow_redirects=False, **kwargs) + + def delete(self, path: str, **kwargs) -> Response: + """ + Do DELETE request to REST API. + + :param path: API path (without root url) + :return: response: Response + """ + return self.request("delete", path=path, allow_redirects=False, **kwargs) + + def patch(self, path: str, **kwargs) -> Response: + """ + Do PATCH request to REST API. + + :param path: API path (without root url) + :return: response: Response + """ + return self.request("patch", path=path, allow_redirects=False, **kwargs) + + def put(self, path: str, headers: Optional[dict] = None, data: Optional[dict] = None, **kwargs) -> Response: + """ + Do PUT request to REST API. + + :param path: API path (without root url) + :param headers: headers that gets added to the request. + :param data: data that gets added to the request. + :return: response: Response + """ + return self.request("put", path=path, data=data, headers=headers, allow_redirects=False, **kwargs) + + def __repr__(self): + return "<{c} to {r!r} with {a}>".format(c=type(self).__name__, r=self._root_url, a=type(self.auth).__name__) + + +class Connection(RestApiConnection): + """ + Connection to an openEO backend. + """ + + _MINIMUM_API_VERSION = ComparableVersion("1.0.0") + + def __init__( + self, + url: str, + *, + auth: Optional[AuthBase] = None, + session: Optional[requests.Session] = None, + default_timeout: Optional[int] = None, + auth_config: Optional[AuthConfig] = None, + refresh_token_store: Optional[RefreshTokenStore] = None, + slow_response_threshold: Optional[float] = None, + oidc_auth_renewer: Optional[OidcAuthenticator] = None, + auto_validate: bool = True, + ): + """ + Constructor of Connection, authenticates user. + + :param url: String Backend root url + """ + if "://" not in url: + url = "https://" + url + self._orig_url = url + super().__init__( + root_url=self.version_discovery(url, session=session, timeout=default_timeout), + auth=auth, session=session, default_timeout=default_timeout, + slow_response_threshold=slow_response_threshold, + ) + self._capabilities_cache = LazyLoadCache() + + # Initial API version check. + self._api_version.require_at_least(self._MINIMUM_API_VERSION) + + self._auth_config = auth_config + self._refresh_token_store = refresh_token_store + self._oidc_auth_renewer = oidc_auth_renewer + self._auto_validate = auto_validate + + @classmethod + def version_discovery( + cls, url: str, session: Optional[requests.Session] = None, timeout: Optional[int] = None + ) -> str: + """ + Do automatic openEO API version discovery from given url, using a "well-known URI" strategy. + + :param url: initial backend url (not including "/.well-known/openeo") + :return: root url of highest supported backend version + """ + try: + connection = RestApiConnection(url, session=session) + well_known_url_response = connection.get("/.well-known/openeo", timeout=timeout) + assert well_known_url_response.status_code == 200 + versions = well_known_url_response.json()["versions"] + supported_versions = [v for v in versions if cls._MINIMUM_API_VERSION <= v["api_version"]] + assert supported_versions + production_versions = [v for v in supported_versions if v.get("production", True)] + highest_version = max(production_versions or supported_versions, key=lambda v: v["api_version"]) + _log.debug("Highest supported version available in backend: %s" % highest_version) + return highest_version['url'] + except Exception: + # Be very lenient about failing on the well-known URI strategy. + return url + + def _get_auth_config(self) -> AuthConfig: + if self._auth_config is None: + self._auth_config = AuthConfig() + return self._auth_config + + def _get_refresh_token_store(self) -> RefreshTokenStore: + if self._refresh_token_store is None: + self._refresh_token_store = RefreshTokenStore() + return self._refresh_token_store + + def authenticate_basic(self, username: Optional[str] = None, password: Optional[str] = None) -> Connection: + """ + Authenticate a user to the backend using basic username and password. + + :param username: User name + :param password: User passphrase + """ + if not self.capabilities().supports_endpoint("/credentials/basic", method="GET"): + raise OpenEoClientException("This openEO back-end does not support basic authentication.") + if username is None: + username, password = self._get_auth_config().get_basic_auth(backend=self._orig_url) + if username is None: + raise OpenEoClientException("No username/password given or found.") + + resp = self.get( + '/credentials/basic', + # /credentials/basic is the only endpoint that expects a Basic HTTP auth + auth=HTTPBasicAuth(username, password) + ).json() + # Switch to bearer based authentication in further requests. + self.auth = BasicBearerAuth(access_token=resp["access_token"]) + return self + + def _get_oidc_provider(self, provider_id: Union[str, None] = None) -> Tuple[str, OidcProviderInfo]: + """ + Get OpenID Connect discovery URL for given provider_id + + :param provider_id: id of OIDC provider as specified by backend (/credentials/oidc). + Can be None if there is just one provider. + :return: updated provider_id and provider info object + """ + oidc_info = self.get("/credentials/oidc", expected_status=200).json() + providers = OrderedDict((p["id"], p) for p in oidc_info["providers"]) + if len(providers) < 1: + raise OpenEoClientException("Backend lists no OIDC providers.") + _log.info("Found OIDC providers: {p}".format(p=list(providers.keys()))) + + # TODO: also support specifying provider through issuer URL? + provider_id_from_env = os.environ.get("OPENEO_AUTH_PROVIDER_ID") + + if provider_id: + if provider_id not in providers: + raise OpenEoClientException( + "Requested OIDC provider {r!r} not available. Should be one of {p}.".format( + r=provider_id, p=list(providers.keys()) + ) + ) + provider = providers[provider_id] + elif provider_id_from_env and provider_id_from_env in providers: + _log.info(f"Using provider_id {provider_id_from_env!r} from OPENEO_AUTH_PROVIDER_ID env var") + provider_id = provider_id_from_env + provider = providers[provider_id] + elif len(providers) == 1: + provider_id, provider = providers.popitem() + _log.info( + f"No OIDC provider given, but only one available: {provider_id!r}. Using that one." + ) + else: + # Check if there is a single provider in the config to use. + backend = self._orig_url + provider_configs = self._get_auth_config().get_oidc_provider_configs( + backend=backend + ) + intersection = set(provider_configs.keys()).intersection(providers.keys()) + if len(intersection) == 1: + provider_id = intersection.pop() + provider = providers[provider_id] + _log.info( + f"No OIDC provider given, but only one in config (for backend {backend!r}): {provider_id!r}. Using that one." + ) + else: + provider_id, provider = providers.popitem(last=False) + _log.info( + f"No OIDC provider given. Using first provider {provider_id!r} as advertised by backend." + ) + provider = OidcProviderInfo.from_dict(provider) + return provider_id, provider + + def _get_oidc_provider_and_client_info( + self, + provider_id: str, + client_id: Union[str, None], + client_secret: Union[str, None], + default_client_grant_check: Union[None, GrantsChecker] = None, + ) -> Tuple[str, OidcClientInfo]: + """ + Resolve provider_id and client info (as given or from config) + + :param provider_id: id of OIDC provider as specified by backend (/credentials/oidc). + Can be None if there is just one provider. + + :return: OIDC provider id and client info + """ + provider_id, provider = self._get_oidc_provider(provider_id) + + if client_id is None: + _log.debug("No client_id: checking config for preferred client_id") + client_id, client_secret = self._get_auth_config().get_oidc_client_configs( + backend=self._orig_url, provider_id=provider_id + ) + if client_id: + _log.info("Using client_id {c!r} from config (provider {p!r})".format(c=client_id, p=provider_id)) + if client_id is None and default_client_grant_check: + # Try "default_clients" from backend's provider info. + _log.debug("No client_id given: checking default clients in backend's provider info") + client_id = provider.get_default_client_id(grant_check=default_client_grant_check) + if client_id: + _log.info("Using default client_id {c!r} from OIDC provider {p!r} info.".format( + c=client_id, p=provider_id + )) + if client_id is None: + raise OpenEoClientException("No client_id found.") + + client_info = OidcClientInfo(client_id=client_id, client_secret=client_secret, provider=provider) + + return provider_id, client_info + + def _authenticate_oidc( + self, + authenticator: OidcAuthenticator, + *, + provider_id: str, + store_refresh_token: bool = False, + fallback_refresh_token_to_store: Optional[str] = None, + oidc_auth_renewer: Optional[OidcAuthenticator] = None, + ) -> Connection: + """ + Authenticate through OIDC and set up bearer token (based on OIDC access_token) for further requests. + """ + tokens = authenticator.get_tokens(request_refresh_token=store_refresh_token) + _log.info("Obtained tokens: {t}".format(t=[k for k, v in tokens._asdict().items() if v])) + if store_refresh_token: + refresh_token = tokens.refresh_token or fallback_refresh_token_to_store + if refresh_token: + self._get_refresh_token_store().set_refresh_token( + issuer=authenticator.provider_info.issuer, + client_id=authenticator.client_id, + refresh_token=refresh_token + ) + if not oidc_auth_renewer: + oidc_auth_renewer = OidcRefreshTokenAuthenticator( + client_info=authenticator.client_info, refresh_token=refresh_token + ) + else: + _log.warning("No OIDC refresh token to store.") + token = tokens.access_token + self.auth = OidcBearerAuth(provider_id=provider_id, access_token=token) + self._oidc_auth_renewer = oidc_auth_renewer + return self + + def authenticate_oidc_authorization_code( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + timeout: Optional[int] = None, + server_address: Optional[Tuple[str, int]] = None, + webbrowser_open: Optional[Callable] = None, + store_refresh_token=False, + ) -> Connection: + """ + OpenID Connect Authorization Code Flow (with PKCE). + + .. deprecated:: 0.19.0 + Usage of the Authorization Code flow is deprecated (because of its complexity) and will be removed. + It is recommended to use the Device Code flow with :py:meth:`authenticate_oidc_device` + or Client Credentials flow with :py:meth:`authenticate_oidc_client_credentials`. + """ + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=[DefaultOidcClientGrant.AUTH_CODE_PKCE], + ) + authenticator = OidcAuthCodePkceAuthenticator( + client_info=client_info, + webbrowser_open=webbrowser_open, timeout=timeout, server_address=server_address + ) + return self._authenticate_oidc(authenticator, provider_id=provider_id, store_refresh_token=store_refresh_token) + + def authenticate_oidc_client_credentials( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + ) -> Connection: + """ + Authenticate with :ref:`OIDC Client Credentials flow ` + + Client id, secret and provider id can be specified directly through the available arguments. + It is also possible to leave these arguments empty and specify them through + environment variables ``OPENEO_AUTH_CLIENT_ID``, + ``OPENEO_AUTH_CLIENT_SECRET`` and ``OPENEO_AUTH_PROVIDER_ID`` respectively + as discussed in :ref:`authenticate_oidc_client_credentials_env_vars`. + + :param client_id: client id to use + :param client_secret: client secret to use + :param provider_id: provider id to use + Fallback value can be set through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + + .. versionchanged:: 0.18.0 Allow specifying client id, secret and provider id through environment variables. + """ + # TODO: option to get client id/secret from a config file too? + if client_id is None and "OPENEO_AUTH_CLIENT_ID" in os.environ and "OPENEO_AUTH_CLIENT_SECRET" in os.environ: + client_id = os.environ.get("OPENEO_AUTH_CLIENT_ID") + client_secret = os.environ.get("OPENEO_AUTH_CLIENT_SECRET") + _log.debug(f"Getting client id ({client_id}) and secret from environment") + + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret + ) + authenticator = OidcClientCredentialsAuthenticator(client_info=client_info) + return self._authenticate_oidc( + authenticator, provider_id=provider_id, store_refresh_token=False, oidc_auth_renewer=authenticator + ) + + def authenticate_oidc_resource_owner_password_credentials( + self, + username: str, + password: str, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + store_refresh_token: bool = False, + ) -> Connection: + """ + OpenId Connect Resource Owner Password Credentials + """ + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret + ) + # TODO: also get username and password from config? + authenticator = OidcResourceOwnerPasswordAuthenticator( + client_info=client_info, username=username, password=password + ) + return self._authenticate_oidc(authenticator, provider_id=provider_id, store_refresh_token=store_refresh_token) + + def authenticate_oidc_refresh_token( + self, + client_id: Optional[str] = None, + refresh_token: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + *, + store_refresh_token: bool = False, + ) -> Connection: + """ + Authenticate with :ref:`OIDC Refresh Token flow ` + + :param client_id: client id to use + :param refresh_token: refresh token to use + :param client_secret: client secret to use + :param provider_id: provider id to use. + Fallback value can be set through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + :param store_refresh_token: whether to store the received refresh token automatically + + .. versionchanged:: 0.19.0 Support fallback provider id through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + """ + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=[DefaultOidcClientGrant.REFRESH_TOKEN], + ) + + if refresh_token is None: + refresh_token = self._get_refresh_token_store().get_refresh_token( + issuer=client_info.provider.issuer, + client_id=client_info.client_id + ) + if refresh_token is None: + raise OpenEoClientException("No refresh token given or found") + + authenticator = OidcRefreshTokenAuthenticator(client_info=client_info, refresh_token=refresh_token) + return self._authenticate_oidc( + authenticator, + provider_id=provider_id, + store_refresh_token=store_refresh_token, + fallback_refresh_token_to_store=refresh_token, + oidc_auth_renewer=authenticator, + ) + + def authenticate_oidc_device( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + provider_id: Optional[str] = None, + *, + store_refresh_token: bool = False, + use_pkce: Optional[bool] = None, + max_poll_time: float = OidcDeviceAuthenticator.DEFAULT_MAX_POLL_TIME, + **kwargs, + ) -> Connection: + """ + Authenticate with the :ref:`OIDC Device Code flow ` + + :param client_id: client id to use instead of the default one + :param client_secret: client secret to use instead of the default one + :param provider_id: provider id to use. + Fallback value can be set through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + :param store_refresh_token: whether to store the received refresh token automatically + :param use_pkce: Use PKCE instead of client secret. + If not set explicitly to `True` (use PKCE) or `False` (use client secret), + it will be attempted to detect the best mode automatically. + Note that PKCE for device code is not widely supported among OIDC providers. + :param max_poll_time: maximum time in seconds to keep polling for successful authentication. + + .. versionchanged:: 0.5.1 Add :py:obj:`use_pkce` argument + .. versionchanged:: 0.17.0 Add :py:obj:`max_poll_time` argument + .. versionchanged:: 0.19.0 Support fallback provider id through environment variable ``OPENEO_AUTH_PROVIDER_ID``. + """ + _g = DefaultOidcClientGrant # alias for compactness + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=(lambda grants: _g.DEVICE_CODE in grants or _g.DEVICE_CODE_PKCE in grants), + ) + authenticator = OidcDeviceAuthenticator( + client_info=client_info, use_pkce=use_pkce, max_poll_time=max_poll_time, **kwargs + ) + return self._authenticate_oidc(authenticator, provider_id=provider_id, store_refresh_token=store_refresh_token) + + def authenticate_oidc( + self, + provider_id: Optional[str] = None, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + *, + store_refresh_token: bool = True, + use_pkce: Optional[bool] = None, + display: Callable[[str], None] = print, + max_poll_time: float = OidcDeviceAuthenticator.DEFAULT_MAX_POLL_TIME, + ): + """ + Generic method to do OpenID Connect authentication. + + In the context of interactive usage, this method first tries to use refresh tokens + and falls back on device code flow. + + For non-interactive, machine-to-machine contexts, it is also possible to trigger + the usage of the "client_credentials" flow through environment variables. + Assuming you have set up a OIDC client (with a secret): + set ``OPENEO_AUTH_METHOD`` to ``client_credentials``, + set ``OPENEO_AUTH_CLIENT_ID`` to the client id, + and set ``OPENEO_AUTH_CLIENT_SECRET`` to the client secret. + + See :ref:`authenticate_oidc_automatic` for more details. + + :param provider_id: provider id to use + :param client_id: client id to use + :param client_secret: client secret to use + :param max_poll_time: maximum time in seconds to keep polling for successful authentication. + + .. versionadded:: 0.6.0 + .. versionchanged:: 0.17.0 Add :py:obj:`max_poll_time` argument + .. versionchanged:: 0.18.0 Add support for client credentials flow. + """ + # TODO: unify `os.environ.get` with `get_config_option`? + # TODO also support OPENEO_AUTH_CLIENT_ID, ... env vars for refresh token and device code auth? + + auth_method = os.environ.get("OPENEO_AUTH_METHOD") + if auth_method == "client_credentials": + _log.debug("authenticate_oidc: going for 'client_credentials' authentication") + return self.authenticate_oidc_client_credentials( + client_id=client_id, client_secret=client_secret, provider_id=provider_id + ) + elif auth_method: + raise ValueError(f"Unhandled auth method {auth_method}") + + _g = DefaultOidcClientGrant # alias for compactness + provider_id, client_info = self._get_oidc_provider_and_client_info( + provider_id=provider_id, client_id=client_id, client_secret=client_secret, + default_client_grant_check=lambda grants: ( + _g.REFRESH_TOKEN in grants and (_g.DEVICE_CODE in grants or _g.DEVICE_CODE_PKCE in grants) + ) + ) + + # Try refresh token first. + refresh_token = self._get_refresh_token_store().get_refresh_token( + issuer=client_info.provider.issuer, + client_id=client_info.client_id + ) + if refresh_token: + try: + _log.info("Found refresh token: trying refresh token based authentication.") + authenticator = OidcRefreshTokenAuthenticator(client_info=client_info, refresh_token=refresh_token) + con = self._authenticate_oidc( + authenticator, + provider_id=provider_id, + store_refresh_token=store_refresh_token, + fallback_refresh_token_to_store=refresh_token, + ) + # TODO: pluggable/jupyter-aware display function? + print("Authenticated using refresh token.") + return con + except OidcException as e: + _log.info("Refresh token based authentication failed: {e}.".format(e=e)) + + # Fall back on device code flow + # TODO: make it possible to do other fallback flows too? + _log.info("Trying device code flow.") + authenticator = OidcDeviceAuthenticator( + client_info=client_info, use_pkce=use_pkce, display=display, max_poll_time=max_poll_time + ) + con = self._authenticate_oidc( + authenticator, + provider_id=provider_id, + store_refresh_token=store_refresh_token, + ) + print("Authenticated using device code flow.") + return con + + def request( + self, + method: str, + path: str, + headers: Optional[dict] = None, + auth: Optional[AuthBase] = None, + check_error: bool = True, + expected_status: Optional[Union[int, Iterable[int]]] = None, + **kwargs, + ): + # Do request, but with retry when access token has expired and refresh token is available. + def _request(): + return super(Connection, self).request( + method=method, path=path, headers=headers, auth=auth, + check_error=check_error, expected_status=expected_status, **kwargs, + ) + + try: + # Initial request attempt + return _request() + except OpenEoApiError as api_exc: + if api_exc.http_status_code in {401, 403} and api_exc.code == "TokenInvalid": + # Auth token expired: can we refresh? + if isinstance(self.auth, OidcBearerAuth) and self._oidc_auth_renewer: + msg = f"OIDC access token expired ({api_exc.http_status_code} {api_exc.code})." + try: + self._authenticate_oidc( + authenticator=self._oidc_auth_renewer, + provider_id=self._oidc_auth_renewer.provider_info.id, + store_refresh_token=False, + oidc_auth_renewer=self._oidc_auth_renewer, + ) + _log.info(f"{msg} Obtained new access token (grant {self._oidc_auth_renewer.grant_type!r}).") + except OpenEoClientException as auth_exc: + _log.error( + f"{msg} Failed to obtain new access token (grant {self._oidc_auth_renewer.grant_type!r}): {auth_exc!r}." + ) + else: + # Retry request. + return _request() + raise + + def describe_account(self) -> dict: + """ + Describes the currently authenticated user account. + """ + return self.get('/me', expected_status=200).json() + + @deprecated("use :py:meth:`list_jobs` instead", version="0.4.10") + def user_jobs(self) -> List[dict]: + return self.list_jobs() + + def list_collections(self) -> List[dict]: + """ + List basic metadata of all collections provided by the back-end. + + .. caution:: + + Only the basic collection metadata will be returned. + To obtain full metadata of a particular collection, + it is recommended to use :py:meth:`~openeo.rest.connection.Connection.describe_collection` instead. + + :return: list of dictionaries with basic collection metadata. + """ + # TODO: add caching #383 + data = self.get('/collections', expected_status=200).json()["collections"] + return VisualList("collections", data=data) + + def list_collection_ids(self) -> List[str]: + """ + List all collection ids provided by the back-end. + + .. seealso:: + + :py:meth:`~openeo.rest.connection.Connection.describe_collection` + to get the metadata of a particular collection. + + :return: list of collection ids + """ + return [collection['id'] for collection in self.list_collections() if 'id' in collection] + + def capabilities(self) -> RESTCapabilities: + """ + Loads all available capabilities. + """ + return self._capabilities_cache.get( + "capabilities", + load=lambda: RESTCapabilities(data=self.get('/', expected_status=200).json(), url=self._orig_url) + ) + + def list_input_formats(self) -> dict: + return self.list_file_formats().get("input", {}) + + def list_output_formats(self) -> dict: + return self.list_file_formats().get("output", {}) + + list_file_types = legacy_alias( + list_output_formats, "list_file_types", since="0.4.6" + ) + + def list_file_formats(self) -> dict: + """ + Get available input and output formats + """ + formats = self._capabilities_cache.get( + key="file_formats", + load=lambda: self.get('/file_formats', expected_status=200).json() + ) + return VisualDict("file-formats", data=formats) + + def list_service_types(self) -> dict: + """ + Loads all available service types. + + :return: data_dict: Dict All available service types + """ + types = self._capabilities_cache.get( + key="service_types", + load=lambda: self.get('/service_types', expected_status=200).json() + ) + return VisualDict("service-types", data=types) + + def list_udf_runtimes(self) -> dict: + """ + Loads all available UDF runtimes. + + :return: data_dict: Dict All available UDF runtimes + """ + runtimes = self._capabilities_cache.get( + key="udf_runtimes", + load=lambda: self.get('/udf_runtimes', expected_status=200).json() + ) + return VisualDict("udf-runtimes", data=runtimes) + + def list_services(self) -> dict: + """ + Loads all available services of the authenticated user. + + :return: data_dict: Dict All available services + """ + # TODO return parsed service objects + services = self.get('/services', expected_status=200).json()["services"] + return VisualList("data-table", data=services, parameters={'columns': 'services'}) + + def describe_collection(self, collection_id: str) -> dict: + """ + Get full collection metadata for given collection id. + + .. seealso:: + + :py:meth:`~openeo.rest.connection.Connection.list_collection_ids` + to list all collection ids provided by the back-end. + + :param collection_id: collection id + :return: collection metadata. + """ + # TODO: duplication with `Connection.collection_metadata`: deprecate one or the other? + # TODO: add caching #383 + data = self.get(f"/collections/{collection_id}", expected_status=200).json() + return VisualDict("collection", data=data) + + def collection_items( + self, + name, + spatial_extent: Optional[List[float]] = None, + temporal_extent: Optional[List[Union[str, datetime.datetime]]] = None, + limit: Optional[int] = None, + ) -> Iterator[dict]: + """ + Loads items for a specific image collection. + May not be available for all collections. + + This is an experimental API and is subject to change. + + :param name: String Id of the collection + :param spatial_extent: Limits the items to the given bounding box in WGS84: + 1. Lower left corner, coordinate axis 1 + 2. Lower left corner, coordinate axis 2 + 3. Upper right corner, coordinate axis 1 + 4. Upper right corner, coordinate axis 2 + + :param temporal_extent: Limits the items to the specified temporal interval. + :param limit: The amount of items per request/page. If None, the back-end decides. + The interval has to be specified as an array with exactly two elements (start, end). + Also supports open intervals by setting one of the boundaries to None, but never both. + + :return: data_list: List A list of items + """ + url = '/collections/{}/items'.format(name) + params = {} + if spatial_extent: + params["bbox"] = ",".join(str(c) for c in spatial_extent) + if temporal_extent: + params["datetime"] = "/".join(".." if t is None else rfc3339.normalize(t) for t in temporal_extent) + if limit is not None and limit > 0: + params['limit'] = limit + + return paginate(self, url, params, lambda response, page: VisualDict("items", data = response, parameters = {'show-map': True, 'heading': 'Page {} - Items'.format(page)})) + + def collection_metadata(self, name) -> CollectionMetadata: + # TODO: duplication with `Connection.describe_collection`: deprecate one or the other? + return CollectionMetadata(metadata=self.describe_collection(name)) + + def list_processes(self, namespace: Optional[str] = None) -> List[dict]: + # TODO: Maybe format the result dictionary so that the process_id is the key of the dictionary. + """ + Loads all available processes of the back end. + + :param namespace: The namespace for which to list processes. + + :return: processes_dict: Dict All available processes of the back end. + """ + if namespace is None: + processes = self._capabilities_cache.get( + key=("processes", "backend"), + load=lambda: self.get('/processes', expected_status=200).json()["processes"] + ) + else: + processes = self.get('/processes/' + namespace, expected_status=200).json()["processes"] + return VisualList("processes", data=processes, parameters={'show-graph': True, 'provide-download': False}) + + def describe_process(self, id: str, namespace: Optional[str] = None) -> dict: + """ + Returns a single process from the back end. + + :param id: The id of the process. + :param namespace: The namespace of the process. + + :return: The process definition. + """ + + processes = self.list_processes(namespace) + for process in processes: + if process["id"] == id: + return VisualDict("process", data=process, parameters={'show-graph': True, 'provide-download': False}) + + raise OpenEoClientException("Process does not exist.") + + def list_jobs(self) -> List[dict]: + """ + Lists all jobs of the authenticated user. + + :return: job_list: Dict of all jobs of the user. + """ + # TODO: Parse the result so that there get Job classes returned? + resp = self.get('/jobs', expected_status=200).json() + if resp.get("federation:missing"): + _log.warning("Partial user job listing due to missing federation components: {c}".format( + c=",".join(resp["federation:missing"]) + )) + jobs = resp["jobs"] + return VisualList("data-table", data=jobs, parameters={'columns': 'jobs'}) + + def assert_user_defined_process_support(self): + """ + Capabilities document based verification that back-end supports user-defined processes. + + .. versionadded:: 0.23.0 + """ + if not self.capabilities().supports_endpoint("/process_graphs"): + raise CapabilitiesException("Backend does not support user-defined processes.") + + def save_user_defined_process( + self, user_defined_process_id: str, + process_graph: Union[dict, ProcessBuilderBase], + parameters: List[Union[dict, Parameter]] = None, + public: bool = False, + summary: Optional[str] = None, + description: Optional[str] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, + ) -> RESTUserDefinedProcess: + """ + Store a process graph and its metadata on the backend as a user-defined process for the authenticated user. + + :param user_defined_process_id: unique identifier for the user-defined process + :param process_graph: a process graph + :param parameters: a list of parameters + :param public: visible to other users? + :param summary: A short summary of what the process does. + :param description: Detailed description to explain the entity. CommonMark 0.29 syntax MAY be used for rich text representation. + :param returns: Description and schema of the return value. + :param categories: A list of categories. + :param examples: A list of examples. + :param links: A list of links. + :return: a RESTUserDefinedProcess instance + """ + self.assert_user_defined_process_support() + if user_defined_process_id in set(p["id"] for p in self.list_processes()): + warnings.warn("Defining user-defined process {u!r} with same id as a pre-defined process".format( + u=user_defined_process_id)) + if not parameters: + warnings.warn("Defining user-defined process {u!r} without parameters".format(u=user_defined_process_id)) + udp = RESTUserDefinedProcess(user_defined_process_id=user_defined_process_id, connection=self) + udp.store( + process_graph=process_graph, parameters=parameters, public=public, + summary=summary, description=description, + returns=returns, categories=categories, examples=examples, links=links + ) + return udp + + def list_user_defined_processes(self) -> List[dict]: + """ + Lists all user-defined processes of the authenticated user. + """ + self.assert_user_defined_process_support() + data = self.get("/process_graphs", expected_status=200).json()["processes"] + return VisualList("processes", data=data, parameters={'show-graph': True, 'provide-download': False}) + + def user_defined_process(self, user_defined_process_id: str) -> RESTUserDefinedProcess: + """ + Get the user-defined process based on its id. The process with the given id should already exist. + + :param user_defined_process_id: the id of the user-defined process + :return: a RESTUserDefinedProcess instance + """ + return RESTUserDefinedProcess(user_defined_process_id=user_defined_process_id, connection=self) + + def validate_process_graph(self, process_graph: dict) -> List[dict]: + """ + Validate a process graph without executing it. + + :param process_graph: (flat) dict representing process graph + :return: list of errors (dictionaries with "code" and "message" fields) + """ + pg_with_metadata = self._build_request_with_process_graph(process_graph)["process"] + return self.post(path="/validation", json=pg_with_metadata, expected_status=200).json()["errors"] + + @property + def _api_version(self) -> ComparableVersion: + # TODO make this a public property (it's also useful outside the Connection class) + return self.capabilities().api_version_check + + def vectorcube_from_paths( + self, paths: List[str], format: str, options: dict = {} + ) -> VectorCube: + """ + Loads one or more files referenced by url or path that is accessible by the backend. + + :param paths: The files to read. + :param format: The file format to read from. It must be one of the values that the server reports as supported input file formats. + :param options: The file format parameters to be used to read the files. Must correspond to the parameters that the server reports as supported parameters for the chosen format. + + :return: A :py:class:`VectorCube`. + + .. versionadded:: 0.14.0 + """ + # TODO #457 deprecate this in favor of `load_url` and standard support for `load_uploaded_files` + graph = PGNode( + "load_uploaded_files", + arguments=dict(paths=paths, format=format, options=options), + ) + # TODO: load_uploaded_files might also return a raster data cube. Determine this based on format? + return VectorCube(graph=graph, connection=self) + + def datacube_from_process(self, process_id: str, namespace: Optional[str] = None, **kwargs) -> DataCube: + """ + Load a data cube from a (custom) process. + + :param process_id: The process id. + :param namespace: optional: process namespace + :param kwargs: The arguments of the custom process + :return: A :py:class:`DataCube`, without valid metadata, as the client is not aware of this custom process. + """ + graph = PGNode(process_id, namespace=namespace, arguments=kwargs) + return DataCube(graph=graph, connection=self) + + def datacube_from_flat_graph(self, flat_graph: dict, parameters: Optional[dict] = None) -> DataCube: + """ + Construct a :py:class:`DataCube` from a flat dictionary representation of a process graph. + + :param flat_graph: flat dictionary representation of a process graph + or a process dictionary with such a flat process graph under a "process_graph" field + (and optionally parameter metadata under a "parameters" field). + :return: A :py:class:`DataCube` corresponding with the operations encoded in the process graph + """ + parameters = parameters or {} + + if "process_graph" in flat_graph: + # `flat_graph` is a "process" structure + # Extract defaults from declared parameters. + for param in flat_graph.get("parameters") or []: + if "default" in param: + parameters.setdefault(param["name"], param["default"]) + + flat_graph = flat_graph["process_graph"] + + pgnode = PGNode.from_flat_graph(flat_graph=flat_graph, parameters=parameters or {}) + return DataCube(graph=pgnode, connection=self) + + def datacube_from_json(self, src: Union[str, Path], parameters: Optional[dict] = None) -> DataCube: + """ + Construct a :py:class:`DataCube` from JSON resource containing (flat) process graph representation. + + :param src: raw JSON string, URL to JSON resource or path to local JSON file + :return: A :py:class:`DataCube` corresponding with the operations encoded in the process graph + """ + return self.datacube_from_flat_graph(load_json_resource(src), parameters=parameters) + + @openeo_process + def load_collection( + self, + collection_id: Union[str, Parameter], + spatial_extent: Union[Dict[str, float], Parameter, None] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Union[None, List[str], Parameter] = None, + properties: Union[ + None, Dict[str, Union[str, PGNode, Callable]], List[CollectionProperty], CollectionProperty + ] = None, + max_cloud_cover: Optional[float] = None, + fetch_metadata=True, + ) -> DataCube: + """ + Load a DataCube by collection id. + + :param collection_id: image collection identifier + :param spatial_extent: limit data to specified bounding box or polygons + :param temporal_extent: limit data to specified temporal interval. + Typically, just a two-item list or tuple containing start and end date. + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + :param bands: only add the specified bands. + :param properties: limit data by collection metadata property predicates. + See :py:func:`~openeo.rest.graph_building.collection_property` for easy construction of such predicates. + :param max_cloud_cover: shortcut to set maximum cloud cover ("eo:cloud_cover" collection property) + :return: a datacube containing the requested data + + .. versionadded:: 0.13.0 + added the ``max_cloud_cover`` argument. + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + + .. versionchanged:: 0.26.0 + Add :py:func:`~openeo.rest.graph_building.collection_property` support to ``properties`` argument. + """ + return DataCube.load_collection( + collection_id=collection_id, + connection=self, + spatial_extent=spatial_extent, + temporal_extent=temporal_extent, + bands=bands, + properties=properties, + max_cloud_cover=max_cloud_cover, + fetch_metadata=fetch_metadata, + ) + + # TODO: remove this #100 #134 0.4.10 + imagecollection = legacy_alias( + load_collection, name="imagecollection", since="0.4.10" + ) + + @openeo_process + def load_result( + self, + id: str, + spatial_extent: Optional[Dict[str, float]] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Optional[List[str]] = None, + ) -> DataCube: + """ + 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. + + :param id: The id of a batch job with results. + :param spatial_extent: limit data to specified bounding box or polygons + :param temporal_extent: limit data to specified temporal interval. + Typically, just a two-item list or tuple containing start and end date. + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + :param bands: only add the specified bands + + :return: a :py:class:`DataCube` + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + """ + # TODO: add check that back-end supports `load_result` process? + cube = self.datacube_from_process( + process_id="load_result", + id=id, + **dict_no_none( + spatial_extent=spatial_extent, + temporal_extent=temporal_extent and DataCube._get_temporal_extent(extent=temporal_extent), + bands=bands, + ), + ) + return cube + + @openeo_process + def load_stac( + self, + url: str, + spatial_extent: Optional[Dict[str, float]] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Optional[List[str]] = None, + properties: Optional[Dict[str, Union[str, PGNode, Callable]]] = None, + ) -> DataCube: + """ + Loads data from a static STAC catalog or a STAC API Collection and returns the data as a processable :py:class:`DataCube`. + A batch job result can be loaded by providing a reference to it. + + If supported by the underlying metadata and file format, the data that is added to the data cube can be + restricted with the parameters ``spatial_extent``, ``temporal_extent`` and ``bands``. + If no data is available for the given extents, a ``NoDataAvailable`` error is thrown. + + Remarks: + + * 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``. + * 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 values should be processed only after the data has been limited to the required extent + and as a consequence also to a manageable size. + + + :param url: The URL to a static STAC catalog (STAC Item, STAC Collection, or STAC Catalog) + or a specific STAC API Collection that allows to filter items and to download assets. + This includes batch job results, which itself are compliant to STAC. + For external URLs, authentication details such as API keys or tokens may need to be included in the URL. + + Batch job results can be specified in two ways: + + - For Batch job results at the same back-end, a URL pointing to the corresponding batch job results + endpoint should be provided. The URL usually ends with ``/jobs/{id}/results`` and ``{id}`` + is the corresponding batch job ID. + - For external results, a signed URL must be provided. Not all back-ends support signed URLs, + which are provided as a link with the link relation `canonical` in the batch job result metadata. + :param spatial_extent: + Limits the data to load to the specified bounding box or polygons. + + For raster data, the process loads the pixel into the data cube if the point at the pixel center intersects + with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). + + For vector data, the process loads the geometry into the data cube if the geometry is fully within the + bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). + Empty geometries may only be in the data cube if no spatial extent has been provided. + + The GeoJSON can be one of the following feature types: + + * A ``Polygon`` or ``MultiPolygon`` geometry, + * a ``Feature`` with a ``Polygon`` or ``MultiPolygon`` geometry, or + * a ``FeatureCollection`` containing at least one ``Feature`` with ``Polygon`` or ``MultiPolygon`` geometries. + + Set this parameter to ``None`` 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. + + :param temporal_extent: + Limits the data to load 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: + + 1. The first element is the start of the temporal interval. + The specified instance in time is **included** in the interval. + 2. The second element is the end of the temporal interval. + The specified instance in time is **excluded** from the interval. + + The second element must always be greater/later than the first element. + Otherwise, a `TemporalExtentEmpty` exception is thrown. + + Also supports open intervals by setting one of the boundaries to ``None``, but never both. + + Set this parameter to ``None`` 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. + + :param bands: + 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`. + + Either 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. + + The 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. + + It is recommended to use this parameter instead of using ``filter_bands()`` directly after loading unbounded data. + + :param properties: + Limits the data by metadata properties to include only data in the data cube which + all given conditions return ``True`` for (AND operation). + + Specify key-value-pairs with the key being the name of the metadata property, + which can be retrieved with the openEO Data Discovery for Collections. + The value must be a condition (user-defined process) to be evaluated against a STAC API. + This parameter is not supported for static STAC. + + .. versionadded:: 0.17.0 + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + """ + # TODO #425 move this implementation to `DataCube` and just forward here (like with `load_collection`) + # TODO #425 detect actual metadata from URL + arguments = {"url": url} + # TODO #425 more normalization/validation of extent/band parameters + if spatial_extent: + arguments["spatial_extent"] = spatial_extent + if temporal_extent: + arguments["temporal_extent"] = DataCube._get_temporal_extent(extent=temporal_extent) + if bands: + arguments["bands"] = bands + if properties: + arguments["properties"] = { + prop: build_child_callback(pred, parent_parameters=["value"]) for prop, pred in properties.items() + } + cube = self.datacube_from_process(process_id="load_stac", **arguments) + return cube + + def load_ml_model(self, id: Union[str, BatchJob]) -> MlModel: + """ + Loads a machine learning model from a STAC Item. + + :param id: STAC item reference, as URL, batch job (id) or user-uploaded file + :return: + + .. versionadded:: 0.10.0 + """ + return MlModel.load_ml_model(connection=self, id=id) + + @openeo_process + def load_geojson( + self, + data: Union[dict, str, Path, shapely.geometry.base.BaseGeometry, Parameter], + properties: Optional[List[str]] = None, + ): + """ + Converts GeoJSON data as defined by RFC 7946 into a vector data cube. + + :param data: the geometry to load. One of: + + - GeoJSON-style data structure: e.g. a dictionary with ``"type": "Polygon"`` and ``"coordinates"`` fields + - a path to a local GeoJSON file + - a GeoJSON string + - a shapely geometry object + + :param properties: A list of properties from the GeoJSON file to construct an additional dimension from. + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + return VectorCube.load_geojson(connection=self, data=data, properties=properties) + + @openeo_process + def load_url(self, url: str, format: str, options: Optional[dict] = None): + """ + Loads a file from a URL + + :param url: The URL to read from. Authentication details such as API keys or tokens may need to be included in the URL. + :param format: The file format to use when loading the data. + :param options: The file format parameters to use when reading the data. + Must correspond to the parameters that the server reports as supported parameters for the chosen ``format`` + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + if format not in self.list_input_formats(): + # TODO: make this an error? + _log.warning(f"Format {format!r} not listed in back-end input formats") + # TODO: Inspect format's gis_data_type to see if we need to load a VectorCube or classic raster DataCube + return VectorCube.load_url(connection=self, url=url, format=format, options=options) + + def create_service(self, graph: dict, type: str, **kwargs) -> Service: + # TODO: type hint for graph: is it a nested or a flat one? + pg_with_metadata = self._build_request_with_process_graph(process_graph=graph, type=type, **kwargs) + self._preflight_validation(pg_with_metadata=pg_with_metadata) + response = self.post(path="/services", json=pg_with_metadata, expected_status=201) + service_id = response.headers.get("OpenEO-Identifier") + return Service(service_id, self) + + @deprecated("Use :py:meth:`openeo.rest.service.Service.delete_service` instead.", version="0.8.0") + def remove_service(self, service_id: str): + """ + Stop and remove a secondary web service. + + :param service_id: service identifier + :return: + """ + Service(service_id, self).delete_service() + + @deprecated("Use :py:meth:`openeo.rest.job.BatchJob.get_results` instead.", version="0.4.10") + def job_results(self, job_id) -> dict: + """Get batch job results metadata.""" + return BatchJob(job_id=job_id, connection=self).list_results() + + @deprecated("Use :py:meth:`openeo.rest.job.BatchJob.logs` instead.", version="0.4.10") + def job_logs(self, job_id, offset) -> list: + """Get batch job logs.""" + return BatchJob(job_id=job_id, connection=self).logs(offset=offset) + + def list_files(self) -> List[UserFile]: + """ + Lists all user-uploaded files in the user workspace on the back-end. + + :return: List of the user-uploaded files. + """ + files = self.get('/files', expected_status=200).json()['files'] + files = [UserFile.from_metadata(metadata=f, connection=self) for f in files] + return VisualList("data-table", data=files, parameters={'columns': 'files'}) + + def get_file( + self, path: Union[str, PurePosixPath], metadata: Optional[dict] = None + ) -> UserFile: + """ + Gets a handle to a user-uploaded file in the user workspace on the back-end. + + :param path: The path on the user workspace. + """ + return UserFile(path=path, connection=self, metadata=metadata) + + def upload_file( + self, + source: Union[Path, str], + target: Optional[Union[str, PurePosixPath]] = None, + ) -> UserFile: + """ + Uploads a file to the given target location in the user workspace on the back-end. + + If a file at the target path exists in the user workspace it will be replaced. + + :param source: A path to a file on the local file system to upload. + :param target: The desired path (which can contain a folder structure if desired) on the user workspace. + If not set: defaults to the original filename (without any folder structure) of the local file . + """ + source = Path(source) + target = target or source.name + # TODO: support other non-path sources too: bytes, open file, url, ... + with source.open("rb") as f: + resp = self.put(f"/files/{target!s}", expected_status=200, data=f) + metadata = resp.json() + return UserFile.from_metadata(metadata=metadata, connection=self) + + def _build_request_with_process_graph(self, process_graph: Union[dict, FlatGraphableMixin, Any], **kwargs) -> dict: + """ + Prepare a json payload with a process graph to submit to /result, /services, /jobs, ... + :param process_graph: flat dict representing a "process graph with metadata" ({"process": {"process_graph": ...}, ...}) + """ + # TODO: make this a more general helper (like `as_flat_graph`) + result = kwargs + process_graph = as_flat_graph(process_graph) + if "process_graph" not in process_graph: + process_graph = {"process_graph": process_graph} + # TODO: also check if `process_graph` already has "process" key (i.e. is a "process graph with metadata" already) + result["process"] = process_graph + return result + + def _preflight_validation(self, pg_with_metadata: dict, *, validate: Optional[bool] = None): + """ + Preflight validation of process graph to execute. + + :param pg_with_metadata: flat dict representation of process graph with metadata, + e.g. as produced by `_build_request_with_process_graph` + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: + """ + if validate is None: + validate = self._auto_validate + if validate and self.capabilities().supports_endpoint("/validation", "POST"): + # At present, the intention is that a failed validation does not block + # the job from running, it is only reported as a warning. + # Therefor we also want to continue when something *else* goes wrong + # *during* the validation. + try: + resp = self.post(path="/validation", json=pg_with_metadata["process"], expected_status=200) + validation_errors = resp.json()["errors"] + if validation_errors: + _log.warning( + "Preflight process graph validation raised: " + + (" ".join(f"[{e.get('code')}] {e.get('message')}" for e in validation_errors)) + ) + except Exception as e: + _log.error(f"Preflight process graph validation failed: {e}") + + # TODO: additional validation and sanity checks: e.g. is there a result node, are all process_ids valid, ...? + + # TODO: unify `download` and `execute` better: e.g. `download` always writes to disk, `execute` returns result (raw or as JSON decoded dict) + def download( + self, + graph: Union[dict, FlatGraphableMixin, str, Path], + outputfile: Union[Path, str, None] = None, + timeout: Optional[int] = None, + validate: Optional[bool] = None, + ) -> Union[None, bytes]: + """ + Downloads the result of a process graph synchronously, + and save the result to the given file or return bytes object if no outputfile is specified. + This method is useful to export binary content such as images. For json content, the execute method is recommended. + + :param graph: (flat) dict representing a process graph, or process graph as raw JSON string, + or as local file path or URL + :param outputfile: output file + :param timeout: timeout to wait for response + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + """ + pg_with_metadata = self._build_request_with_process_graph(process_graph=graph) + self._preflight_validation(pg_with_metadata=pg_with_metadata, validate=validate) + response = self.post( + path="/result", + json=pg_with_metadata, + expected_status=200, + stream=True, + timeout=timeout or DEFAULT_TIMEOUT_SYNCHRONOUS_EXECUTE, + ) + + if outputfile is not None: + with Path(outputfile).open(mode="wb") as f: + for chunk in response.iter_content(chunk_size=None): + f.write(chunk) + else: + return response.content + + def execute( + self, + process_graph: Union[dict, str, Path], + timeout: Optional[int] = None, + validate: Optional[bool] = None, + ): + """ + Execute a process graph synchronously and return the result (assumed to be JSON). + + :param process_graph: (flat) dict representing a process graph, or process graph as raw JSON string, + or as local file path or URL + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: parsed JSON response + """ + pg_with_metadata = self._build_request_with_process_graph(process_graph=process_graph) + self._preflight_validation(pg_with_metadata=pg_with_metadata, validate=validate) + return self.post( + path="/result", + json=pg_with_metadata, + expected_status=200, + timeout=timeout or DEFAULT_TIMEOUT_SYNCHRONOUS_EXECUTE, + ).json() # TODO: only do JSON decoding when mimetype is actually JSON? + + def create_job( + self, + process_graph: Union[dict, str, Path], + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + additional: Optional[dict] = None, + validate: Optional[bool] = None, + ) -> BatchJob: + """ + Create a new job from given process graph on the back-end. + + :param process_graph: (flat) dict representing a process graph, or process graph as raw JSON string, + or as local file path or URL + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param additional: additional job options to pass to the backend + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + :return: Created job + """ + # TODO move all this (BatchJob factory) logic to BatchJob? + + pg_with_metadata = self._build_request_with_process_graph( + process_graph=process_graph, + **dict_no_none(title=title, description=description, plan=plan, budget=budget) + ) + if additional: + # TODO: get rid of this non-standard field? https://github.com/Open-EO/openeo-api/issues/276 + pg_with_metadata["job_options"] = additional + + self._preflight_validation(pg_with_metadata=pg_with_metadata, validate=validate) + response = self.post("/jobs", json=pg_with_metadata, expected_status=201) + + job_id = None + if "openeo-identifier" in response.headers: + job_id = response.headers['openeo-identifier'].strip() + elif "location" in response.headers: + _log.warning("Backend did not explicitly respond with job id, will guess it from redirect URL.") + job_id = response.headers['location'].split("/")[-1] + if not job_id: + raise OpenEoClientException("Job creation response did not contain a valid job id") + return BatchJob(job_id=job_id, connection=self) + + def job(self, job_id: str) -> BatchJob: + """ + Get the job based on the id. The job with the given id should already exist. + + Use :py:meth:`openeo.rest.connection.Connection.create_job` to create new jobs + + :param job_id: the job id of an existing job + :return: A job object. + """ + return BatchJob(job_id=job_id, connection=self) + + def service(self, service_id: str) -> Service: + """ + Get the secondary web service based on the id. The service with the given id should already exist. + + Use :py:meth:`openeo.rest.connection.Connection.create_service` to create new services + + :param job_id: the service id of an existing secondary web service + :return: A service object. + """ + return Service(service_id, connection=self) + + def load_disk_collection( + self, format: str, glob_pattern: str, options: Optional[dict] = None + ) -> DataCube: + """ + Loads image data from disk as a :py:class:`DataCube`. + + :param format: the file format, e.g. 'GTiff' + :param glob_pattern: a glob pattern that matches the files to load from disk + :param options: options specific to the file format + """ + return DataCube.load_disk_collection( + self, format, glob_pattern, **(options or {}) + ) + + def as_curl( + self, + data: Union[dict, DataCube, FlatGraphableMixin], + path="/result", + method="POST", + obfuscate_auth: bool = False, + ) -> str: + """ + Build curl command to evaluate given process graph or data cube + (including authorization and content-type headers). + + >>> print(connection.as_curl(cube)) + curl -i -X POST -H 'Content-Type: application/json' -H 'Authorization: Bearer ...' \\ + --data '{"process":{"process_graph":{...}}' \\ + https://openeo.example/openeo/1.1/result + + :param data: something that is convertable to an openEO process graph: a dictionary, + a :py:class:`~openeo.rest.datacube.DataCube` object, + a :py:class:`~openeo.processes.ProcessBuilder`, ... + :param path: endpoint to send request to: typically ``"/result"`` (default) for synchronous requests + or ``"/jobs"`` for batch jobs + :param method: HTTP method to use (typically ``"POST"``) + :param obfuscate_auth: don't show actual bearer token + + :return: curl command as a string + """ + cmd = ["curl", "-i", "-X", method] + cmd += ["-H", "Content-Type: application/json"] + if isinstance(self.auth, BearerAuth): + cmd += ["-H", f"Authorization: Bearer {'...' if obfuscate_auth else self.auth.bearer}"] + pg_with_metadata = self._build_request_with_process_graph(data) + post_json = json.dumps(pg_with_metadata, separators=(",", ":")) + cmd += ["--data", post_json] + cmd += [self.build_url(path)] + return " ".join(shlex.quote(c) for c in cmd) + + def version_info(self): + """List version of the openEO client, API, back-end, etc.""" + capabilities = self.capabilities() + return { + "client": openeo.client_version(), + "api": capabilities.api_version(), + "backend": dict_no_none({ + "root_url": self.root_url, + "version": capabilities.get("backend_version"), + "processing:software": capabilities.get("processing:software"), + }), + } + + +def connect( + url: Optional[str] = None, + *, + auth_type: Optional[str] = None, + auth_options: Optional[dict] = None, + session: Optional[requests.Session] = None, + default_timeout: Optional[int] = None, + auto_validate: bool = True, +) -> Connection: + """ + This method is the entry point to OpenEO. + You typically create one connection object in your script or application + and re-use it for all calls to that backend. + + If the backend requires authentication, you can pass authentication data directly to this function, + but it could be easier to authenticate as follows: + + >>> # For basic authentication + >>> conn = connect(url).authenticate_basic(username="john", password="foo") + >>> # For OpenID Connect authentication + >>> conn = connect(url).authenticate_oidc(client_id="myclient") + + :param url: The http url of the OpenEO back-end. + :param auth_type: Which authentication to use: None, "basic" or "oidc" (for OpenID Connect) + :param auth_options: Options/arguments specific to the authentication type + :param default_timeout: default timeout (in seconds) for requests + :param auto_validate: toggle to automatically validate process graphs before execution + + .. versionadded:: 0.24.0 + added ``auto_validate`` argument + """ + + def _config_log(message): + _log.info(message) + config_log(message) + + if url is None: + default_backend = get_config_option("connection.default_backend") + if default_backend: + url = default_backend + _config_log(f"Using default back-end URL {url!r} (from config)") + default_backend_auto_auth = get_config_option("connection.default_backend.auto_authenticate") + if default_backend_auto_auth and default_backend_auto_auth.lower() in {"basic", "oidc"}: + auth_type = default_backend_auto_auth.lower() + _config_log(f"Doing auto-authentication {auth_type!r} (from config)") + + if auth_type is None: + auto_authenticate = get_config_option("connection.auto_authenticate") + if auto_authenticate and auto_authenticate.lower() in {"basic", "oidc"}: + auth_type = auto_authenticate.lower() + _config_log(f"Doing auto-authentication {auth_type!r} (from config)") + + if not url: + raise OpenEoClientException("No openEO back-end URL given or known to connect to.") + connection = Connection(url, session=session, default_timeout=default_timeout, auto_validate=auto_validate) + + auth_type = auth_type.lower() if isinstance(auth_type, str) else auth_type + if auth_type in {None, False, 'null', 'none'}: + pass + elif auth_type == "basic": + connection.authenticate_basic(**(auth_options or {})) + elif auth_type in {"oidc", "openid"}: + connection.authenticate_oidc(**(auth_options or {})) + else: + raise ValueError("Unknown auth type {a!r}".format(a=auth_type)) + return connection + + +@deprecated("Use :py:func:`openeo.connect` instead", version="0.0.9") +def session(userid=None, endpoint: str = "https://openeo.org/openeo") -> Connection: + """ + This method is the entry point to OpenEO. You typically create one session object in your script or application, per back-end. + and re-use it for all calls to that backend. + If the backend requires authentication, you should set pass your credentials. + + :param endpoint: The http url of an OpenEO endpoint. + :rtype: openeo.sessions.Session + """ + return connect(url=endpoint) + + +def paginate(con: Connection, url: str, params: Optional[dict] = None, callback: Callable = lambda resp, page: resp): + # TODO: make this a method `get_paginated` on `RestApiConnection`? + # TODO: is it necessary to have `callback`? It's only used just before yielding, + # so it's probably cleaner (even for the caller) to to move it outside. + page = 1 + while True: + response = con.get(url, params=params).json() + yield callback(response, page) + next_links = [link for link in response.get("links", []) if link.get("rel") == "next" and "href" in link] + if not next_links: + break + url = next_links[0]["href"] + page += 1 + params = {} diff --git a/lib/openeo/rest/conversions.py b/lib/openeo/rest/conversions.py new file mode 100644 index 000000000..6268bed1a --- /dev/null +++ b/lib/openeo/rest/conversions.py @@ -0,0 +1,124 @@ +""" +Helpers for data conversions between Python ecosystem data types and openEO data structures. +""" + +from __future__ import annotations + +import typing + +import numpy as np +import pandas + +from openeo.internal.warnings import deprecated + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + import xarray + + from openeo.udf import XarrayDataCube + + +class InvalidTimeSeriesException(ValueError): + pass + + +def timeseries_json_to_pandas(timeseries: dict, index: str = "date", auto_collapse=True) -> pandas.DataFrame: + """ + Convert a timeseries JSON object as returned by the `aggregate_spatial` process to a pandas DataFrame object + + This timeseries data has three dimensions in general: date, polygon index and band index. + One of these will be used as index of the resulting dataframe (as specified by the `index` argument), + and the other two will be used as multilevel columns. + When there is just a single polygon or band in play, the dataframe will be simplified + by removing the corresponding dimension if `auto_collapse` is enabled (on by default). + + :param timeseries: dictionary as returned by `aggregate_spatial` + :param index: which dimension should be used for the DataFrame index: 'date' or 'polygon' + :param auto_collapse: whether single band or single polygon cases should be simplified automatically + + :return: pandas DataFrame or Series + """ + # The input timeseries dictionary is assumed to have this structure: + # {dict mapping date -> [list with one item per polygon: [list with one float/None per band or empty list]]} + # TODO is this format of `aggregate_spatial` standardized across backends? Or can we detect the structure? + # TODO: option to pass a path to a JSON file as input? + + # Some quick checks + if len(timeseries) == 0: + raise InvalidTimeSeriesException("Empty data set") + polygon_counts = set(len(polygon_data) for polygon_data in timeseries.values()) + if polygon_counts == {0}: + raise InvalidTimeSeriesException("No polygon data for each date") + elif 0 in polygon_counts: + # TODO: still support this use case? + raise InvalidTimeSeriesException("No polygon data for some dates ({p})".format(p=polygon_counts)) + elif len(polygon_counts) > 1: + raise InvalidTimeSeriesException("Inconsistent polygon counts: {p}".format(p=polygon_counts)) + # Count the number of bands in the timeseries, so we can provide a fallback array for missing data + band_counts = set(len(band_data) for polygon_data in timeseries.values() for band_data in polygon_data) + if band_counts == {0}: + raise InvalidTimeSeriesException("Zero bands everywhere") + band_counts.discard(0) + if len(band_counts) != 1: + raise InvalidTimeSeriesException("Inconsistent band counts: {b}".format(b=band_counts)) + band_count = band_counts.pop() + band_data_fallback = [np.nan] * band_count + # Load the timeseries data in a pandas Series with multi-index ["date", "polygon", "band"] + s = pandas.DataFrame.from_records( + ( + (date, polygon_index, band_index, value) + for (date, polygon_data) in timeseries.items() + for polygon_index, band_data in enumerate(polygon_data) + for band_index, value in enumerate(band_data or band_data_fallback) + ), + columns=["date", "polygon", "band", "value"], + index=["date", "polygon", "band"] + )["value"].rename(None) + # TODO convert date to real date index? + + if auto_collapse: + if s.index.levshape[2] == 1: + # Single band case + s.index = s.index.droplevel("band") + if s.index.levshape[1] == 1: + # Single polygon case + s.index = s.index.droplevel("polygon") + + # Reshape as desired + if index == "date": + if len(s.index.names) > 1: + return s.unstack("date").T + else: + return s + elif index == "polygon": + return s.unstack("polygon").T + else: + raise ValueError(index) + + +@deprecated("Use :py:meth:`XarrayDataCube.from_file` instead.", version="0.7.0") +def datacube_from_file(filename, fmt="netcdf") -> XarrayDataCube: + from openeo.udf.xarraydatacube import XarrayDataCube + return XarrayDataCube.from_file(path=filename, fmt=fmt) + + +@deprecated("Use :py:meth:`XarrayDataCube.save_to_file` instead.", version="0.7.0") +def datacube_to_file(datacube: XarrayDataCube, filename, fmt="netcdf"): + return datacube.save_to_file(path=filename, fmt=fmt) + + +@deprecated("Use :py:meth:`XarrayIO.to_json_file` instead", version="0.7.0") +def _save_DataArray_to_JSON(filename, array: xarray.DataArray): + from openeo.udf.xarraydatacube import XarrayIO + return XarrayIO.to_json_file(array=array, path=filename) + + +@deprecated("Use :py:meth:`XarrayIO.to_netcdf_file` instead", version="0.7.0") +def _save_DataArray_to_NetCDF(filename, array: xarray.DataArray): + from openeo.udf.xarraydatacube import XarrayIO + return XarrayIO.to_netcdf_file(array=array, path=filename) + + +@deprecated("Use :py:meth:`XarrayDataCube.plot` instead.", version="0.7.0") +def datacube_plot(datacube: XarrayDataCube, *args, **kwargs): + datacube.plot(*args, **kwargs) diff --git a/lib/openeo/rest/datacube.py b/lib/openeo/rest/datacube.py new file mode 100644 index 000000000..2e3b70d2b --- /dev/null +++ b/lib/openeo/rest/datacube.py @@ -0,0 +1,2530 @@ +""" +The main module for creating earth observation processes. It aims to easily build complex process chains, that can +be evaluated by an openEO backend. + +.. data:: THIS + + Symbolic reference to the current data cube, to be used as argument in :py:meth:`DataCube.process()` calls + +""" +from __future__ import annotations + +import datetime +import logging +import pathlib +import typing +import warnings +from builtins import staticmethod +from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union + +import numpy as np +import shapely.geometry +import shapely.geometry.base +from shapely.geometry import MultiPolygon, Polygon, mapping + +from openeo.api.process import Parameter +from openeo.dates import get_temporal_extent +from openeo.internal.documentation import openeo_process +from openeo.internal.graph_building import PGNode, ReduceNode, _FromNodeMixin +from openeo.internal.jupyter import in_jupyter_context +from openeo.internal.processes.builder import ProcessBuilderBase, convert_callable_to_pgnode, get_parameter_names +from openeo.internal.warnings import UserDeprecationWarning, deprecated, legacy_alias +from openeo.metadata import Band, BandDimension, CollectionMetadata, SpatialDimension, TemporalDimension +from openeo.processes import ProcessBuilder +from openeo.rest import BandMathException, OpenEoClientException, OperatorException +from openeo.rest._datacube import THIS, UDF, _ProcessGraphAbstraction, build_child_callback +from openeo.rest.graph_building import CollectionProperty +from openeo.rest.job import BatchJob, RESTJob +from openeo.rest.mlmodel import MlModel +from openeo.rest.service import Service +from openeo.rest.udp import RESTUserDefinedProcess +from openeo.rest.vectorcube import VectorCube +from openeo.util import dict_no_none, guess_format, normalize_crs, rfc3339 + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + import xarray + + from openeo.rest.connection import Connection + from openeo.udf import XarrayDataCube + + +log = logging.getLogger(__name__) + + +# Type annotation aliases +InputDate = Union[str, datetime.date, Parameter, PGNode, ProcessBuilderBase, None] + + +class DataCube(_ProcessGraphAbstraction): + """ + Class representing a openEO (raster) data cube. + + The data cube is represented by its corresponding openeo "process graph" + and this process graph can be "grown" to a desired workflow by calling the appropriate methods. + """ + + # TODO: set this based on back-end or user preference? + _DEFAULT_RASTER_FORMAT = "GTiff" + + def __init__(self, graph: PGNode, connection: Connection, metadata: Optional[CollectionMetadata] = None): + super().__init__(pgnode=graph, connection=connection) + self.metadata: Optional[CollectionMetadata] = metadata + + def process( + self, + process_id: str, + arguments: Optional[dict] = None, + metadata: Optional[CollectionMetadata] = None, + namespace: Optional[str] = None, + **kwargs, + ) -> DataCube: + """ + Generic helper to create a new DataCube by applying a process. + + :param process_id: process id of the process. + :param arguments: argument dictionary for the process. + :param metadata: optional: metadata to override original cube metadata (e.g. when reducing dimensions) + :param namespace: optional: process namespace + :return: new DataCube instance + """ + pg = self._build_pgnode(process_id=process_id, arguments=arguments, namespace=namespace, **kwargs) + return DataCube(graph=pg, connection=self._connection, metadata=metadata or self.metadata) + + graph_add_node = legacy_alias(process, "graph_add_node", since="0.1.1") + + def process_with_node(self, pg: PGNode, metadata: Optional[CollectionMetadata] = None) -> DataCube: + """ + Generic helper to create a new DataCube by applying a process (given as process graph node) + + :param pg: process graph node (containing process id and arguments) + :param metadata: optional: metadata to override original cube metadata (e.g. when reducing dimensions) + :return: new DataCube instance + """ + # TODO: deep copy `self.metadata` instead of using same instance? + # TODO: cover more cases where metadata has to be altered + # TODO: deprecate `process_with_node``: little added value over just calling DataCube() directly + return DataCube(graph=pg, connection=self._connection, metadata=metadata or self.metadata) + + def _do_metadata_normalization(self) -> bool: + """Do metadata-based normalization/validation of dimension names, band names, ...""" + return isinstance(self.metadata, CollectionMetadata) + + def _assert_valid_dimension_name(self, name: str) -> str: + if self._do_metadata_normalization(): + self.metadata.assert_valid_dimension(name) + return name + + @classmethod + @openeo_process + def load_collection( + cls, + collection_id: Union[str, Parameter], + connection: Connection = None, + spatial_extent: Union[Dict[str, float], Parameter, None] = None, + temporal_extent: Union[Sequence[InputDate], Parameter, str, None] = None, + bands: Union[None, List[str], Parameter] = None, + fetch_metadata: bool = True, + properties: Union[ + None, Dict[str, Union[str, PGNode, typing.Callable]], List[CollectionProperty], CollectionProperty + ] = None, + max_cloud_cover: Optional[float] = None, + ) -> DataCube: + """ + Create a new Raster Data cube. + + :param collection_id: image collection identifier + :param connection: The connection to use to connect with the backend. + :param spatial_extent: limit data to specified bounding box or polygons + :param temporal_extent: limit data to specified temporal interval. + Typically, just a two-item list or tuple containing start and end date. + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + :param bands: only add the specified bands. + :param properties: limit data by metadata property predicates. + See :py:func:`~openeo.rest.graph_building.collection_property` for easy construction of such predicates. + :param max_cloud_cover: shortcut to set maximum cloud cover ("eo:cloud_cover" collection property) + :return: new DataCube containing the collection + + .. versionchanged:: 0.13.0 + added the ``max_cloud_cover`` argument. + + .. versionchanged:: 0.23.0 + Argument ``temporal_extent``: add support for year/month shorthand notation + as discussed at :ref:`date-shorthand-handling`. + + .. versionchanged:: 0.26.0 + Add :py:func:`~openeo.rest.graph_building.collection_property` support to ``properties`` argument. + """ + if temporal_extent: + temporal_extent = cls._get_temporal_extent(extent=temporal_extent) + + if isinstance(spatial_extent, Parameter): + if spatial_extent.schema.get("type") != "object": + warnings.warn( + "Unexpected parameterized `spatial_extent` in `load_collection`:" + f" expected schema with type 'object' but got {spatial_extent.schema!r}." + ) + arguments = { + 'id': collection_id, + # TODO: spatial_extent could also be a "geojson" subtype object, so we might want to allow (and convert) shapely shapes as well here. + 'spatial_extent': spatial_extent, + 'temporal_extent': temporal_extent, + } + if isinstance(collection_id, Parameter): + fetch_metadata = False + metadata: Optional[CollectionMetadata] = ( + connection.collection_metadata(collection_id) if fetch_metadata else None + ) + if bands: + if isinstance(bands, str): + bands = [bands] + elif isinstance(bands, Parameter): + metadata = None + if metadata: + bands = [b if isinstance(b, str) else metadata.band_dimension.band_name(b) for b in bands] + metadata = metadata.filter_bands(bands) + arguments['bands'] = bands + + if isinstance(properties, list): + # TODO: warn about items that are not CollectionProperty objects instead of silently dropping them. + properties = {p.name: p.from_node() for p in properties if isinstance(p, CollectionProperty)} + if isinstance(properties, CollectionProperty): + properties = {properties.name: properties.from_node()} + elif properties is None: + properties = {} + if max_cloud_cover: + properties["eo:cloud_cover"] = lambda v: v <= max_cloud_cover + if properties: + summaries = metadata and metadata.get("summaries") or {} + undefined_properties = set(properties.keys()).difference(summaries.keys()) + if undefined_properties: + warnings.warn( + f"{collection_id} property filtering with properties that are undefined " + f"in the collection metadata (summaries): {', '.join(undefined_properties)}.", + stacklevel=2, + ) + arguments["properties"] = { + prop: build_child_callback(pred, parent_parameters=["value"]) for prop, pred in properties.items() + } + + pg = PGNode( + process_id='load_collection', + arguments=arguments + ) + return cls(graph=pg, connection=connection, metadata=metadata) + + create_collection = legacy_alias( + load_collection, name="create_collection", since="0.4.6" + ) + + @classmethod + def load_disk_collection(cls, connection: Connection, file_format: str, glob_pattern: str, **options) -> DataCube: + """ + Loads image data from disk as a DataCube. + This is backed by a non-standard process ('load_disk_data'). This will eventually be replaced by standard options such as + https://processes.openeo.org/#load_uploaded_files + + + :param connection: The connection to use to connect with the backend. + :param file_format: the file format, e.g. 'GTiff' + :param glob_pattern: a glob pattern that matches the files to load from disk + :param options: options specific to the file format + :return: the data as a DataCube + """ + pg = PGNode( + process_id='load_disk_data', + arguments={ + 'format': file_format, + 'glob_pattern': glob_pattern, + 'options': options + } + ) + return cls(graph=pg, connection=connection) + + @classmethod + def _get_temporal_extent( + cls, + *args, + start_date: InputDate = None, + end_date: InputDate = None, + extent: Union[Sequence[InputDate], Parameter, str, None] = None, + ) -> Union[List[Union[str, Parameter, PGNode, None]], Parameter]: + """Parameter aware temporal_extent normalizer""" + # TODO: move this outside of DataCube class + # TODO: return extent as tuple instead of list + if len(args) == 1 and isinstance(args[0], Parameter): + assert start_date is None and end_date is None and extent is None + return args[0] + elif len(args) == 0 and isinstance(extent, Parameter): + assert start_date is None and end_date is None + # TODO: warn about unexpected parameter schema + return extent + else: + def convertor(d: Any) -> Any: + # TODO: can this be generalized through _FromNodeMixin? + if isinstance(d, Parameter) or isinstance(d, PGNode): + # TODO: warn about unexpected parameter schema + return d + elif isinstance(d, ProcessBuilderBase): + return d.pgnode + else: + return rfc3339.normalize(d) + + return list( + get_temporal_extent(*args, start_date=start_date, end_date=end_date, extent=extent, convertor=convertor) + ) + + @openeo_process + def filter_temporal( + self, + *args, + start_date: InputDate = None, + end_date: InputDate = None, + extent: Union[Sequence[InputDate], Parameter, str, None] = None, + ) -> DataCube: + """ + Limit the DataCube to a certain date range, which can be specified in several ways: + + >>> cube.filter_temporal("2019-07-01", "2019-08-01") + >>> cube.filter_temporal(["2019-07-01", "2019-08-01"]) + >>> cube.filter_temporal(extent=["2019-07-01", "2019-08-01"]) + >>> cube.filter_temporal(start_date="2019-07-01", end_date="2019-08-01"]) + + See :ref:`filtering-on-temporal-extent-section` for more details on temporal extent handling and shorthand notation. + + :param start_date: start date of the filter (inclusive), as a string or date object + :param end_date: end date of the filter (exclusive), as a string or date object + :param extent: temporal extent. + Typically, specified as a two-item list or tuple containing start and end date. + + .. versionchanged:: 0.23.0 + Arguments ``start_date``, ``end_date`` and ``extent``: + add support for year/month shorthand notation as discussed at :ref:`date-shorthand-handling`. + """ + return self.process( + process_id='filter_temporal', + arguments={ + 'data': THIS, + 'extent': self._get_temporal_extent(*args, start_date=start_date, end_date=end_date, extent=extent) + } + ) + + @openeo_process + def filter_bbox( + self, + *args, + west: Optional[float] = None, + south: Optional[float] = None, + east: Optional[float] = None, + north: Optional[float] = None, + crs: Optional[Union[int, str]] = None, + base: Optional[float] = None, + height: Optional[float] = None, + bbox: Optional[Sequence[float]] = None, + ) -> DataCube: + """ + Limits the data cube to the specified bounding box. + + The bounding box can be specified in multiple ways. + + - With keyword arguments:: + + >>> cube.filter_bbox(west=3, south=51, east=4, north=52, crs=4326) + + - With a (west, south, east, north) list or tuple + (note that EPSG:4326 is the default CRS, so it's not necessary to specify it explicitly):: + + >>> cube.filter_bbox([3, 51, 4, 52]) + >>> cube.filter_bbox(bbox=[3, 51, 4, 52]) + + - With a bbox dictionary:: + + >>> bbox = {"west": 3, "south": 51, "east": 4, "north": 52, "crs": 4326} + >>> cube.filter_bbox(bbox) + >>> cube.filter_bbox(bbox=bbox) + >>> cube.filter_bbox(**bbox) + + - With a shapely geometry (of which the bounding box will be used):: + + >>> cube.filter_bbox(geometry) + >>> cube.filter_bbox(bbox=geometry) + + - Passing a parameter:: + + >>> bbox_param = Parameter(name="my_bbox", schema="object") + >>> cube.filter_bbox(bbox_param) + >>> cube.filter_bbox(bbox=bbox_param) + + - With a CRS other than EPSG 4326:: + + >>> cube.filter_bbox( + ... west=652000, east=672000, north=5161000, south=5181000, + ... crs=32632 + ... ) + + - Deprecated: positional arguments are also supported, + but follow a non-standard order for legacy reasons:: + + >>> west, east, north, south = 3, 4, 52, 51 + >>> cube.filter_bbox(west, east, north, south) + + :param crs: value describing the coordinate reference system. + Typically just an int (interpreted as EPSG code, e.g. ``4326``) + or a string (handled as authority string, e.g. ``"EPSG:4326"``). + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + """ + if args and any(k is not None for k in (west, south, east, north, bbox)): + raise ValueError("Don't mix positional arguments with keyword arguments.") + if bbox and any(k is not None for k in (west, south, east, north)): + raise ValueError("Don't mix `bbox` with `west`/`south`/`east`/`north` keyword arguments.") + + if args: + if 4 <= len(args) <= 5: + # Handle old-style west-east-north-south order + # TODO remove handling of this legacy order? + warnings.warn("Deprecated argument order usage: `filter_bbox(west, east, north, south)`." + " Use keyword arguments or tuple/list argument instead.") + west, east, north, south = args[:4] + if len(args) > 4: + crs = normalize_crs(args[4]) + elif len(args) == 1 and (isinstance(args[0], (list, tuple)) and len(args[0]) == 4 + or isinstance(args[0], (dict, shapely.geometry.base.BaseGeometry, Parameter))): + bbox = args[0] + else: + raise ValueError(args) + + if isinstance(bbox, Parameter): + if bbox.schema.get("type") != "object": + warnings.warn( + "Unexpected parameterized `extent` in `filter_bbox`:" + f" expected schema with type 'object' but got {bbox.schema!r}." + ) + extent = bbox + else: + if bbox: + if isinstance(bbox, shapely.geometry.base.BaseGeometry): + west, south, east, north = bbox.bounds + elif isinstance(bbox, (list, tuple)) and len(bbox) == 4: + west, south, east, north = bbox[:4] + elif isinstance(bbox, dict): + west, south, east, north = (bbox[k] for k in ["west", "south", "east", "north"]) + if "crs" in bbox: + crs = bbox["crs"] + else: + raise ValueError(bbox) + + extent = {'west': west, 'east': east, 'north': north, 'south': south} + extent.update(dict_no_none(crs=crs, base=base, height=height)) + + return self.process( + process_id='filter_bbox', + arguments={ + 'data': THIS, + 'extent': extent + } + ) + + @openeo_process + def filter_spatial(self, geometries) -> DataCube: + """ + Limits the data cube over the spatial dimensions to the specified geometries. + + - For polygons, the filter retains a pixel in the data cube if the point at the pixel center intersects with + at least one of the polygons (as defined in the Simple Features standard by the OGC). + - For points, the process considers the closest pixel center. + - For lines (line strings), the process considers all the pixels whose centers are closest to at least one + point on the line. + + More specifically, pixels outside of the bounding box of the given geometry will not be available after filtering. + All pixels inside the bounding box that are not retained will be set to null (no data). + + :param geometries: One or more geometries used for filtering, specified as GeoJSON in EPSG:4326. + :return: A data cube restricted to the specified geometries. The dimensions and dimension properties (name, + type, labels, reference system and resolution) remain unchanged, except that the spatial dimensions have less + (or the same) dimension labels. + """ + valid_geojson_types = [ + "Point", "MultiPoint", "LineString", "MultiLineString", + "Polygon", "MultiPolygon", "GeometryCollection", "FeatureCollection" + ] + geometries = self._get_geometry_argument(geometries, valid_geojson_types=valid_geojson_types, crs=None) + return self.process( + process_id='filter_spatial', + arguments={ + 'data': THIS, + 'geometries': geometries + } + ) + + @openeo_process + def filter_bands(self, bands: Union[List[Union[str, int]], str]) -> DataCube: + """ + Filter the data cube by the given bands + + :param bands: list of band names, common names or band indices. Single band name can also be given as string. + :return: a DataCube instance + """ + if isinstance(bands, str): + bands = [bands] + if self._do_metadata_normalization(): + bands = [self.metadata.band_dimension.band_name(b) for b in bands] + cube = self.process( + process_id="filter_bands", + arguments={"data": THIS, "bands": bands}, + metadata=self.metadata.filter_bands(bands) if self.metadata else None, + ) + return cube + + band_filter = legacy_alias(filter_bands, "band_filter", since="0.1.0") + + def band(self, band: Union[str, int]) -> DataCube: + """ + Filter out a single band + + :param band: band name, band common name or band index. + :return: a DataCube instance + """ + if self._do_metadata_normalization(): + band = self.metadata.band_dimension.band_index(band) + return self.reduce_bands( + reducer=PGNode( + process_id="array_element", + arguments={"data": {"from_parameter": "data"}, "index": band}, + ) + ) + + @openeo_process + def resample_spatial( + self, resolution: Union[float, Tuple[float, float]], projection: Union[int, str] = None, + method: str = 'near', align: str = 'upper-left' + ) -> DataCube: + return self.process('resample_spatial', { + 'data': THIS, + 'resolution': resolution, + 'projection': projection, + 'method': method, + 'align': align + }) + + def resample_cube_spatial(self, target: DataCube, method: str = "near") -> DataCube: + """ + Resamples the spatial dimensions (x,y) from a source data cube to align with the corresponding + dimensions of the given target data cube. + Returns a new data cube with the resampled dimensions. + + To resample a data cube to a specific resolution or projection regardless of an existing target + data cube, refer to :py:meth:`resample_spatial`. + + :param target: A data cube that describes the spatial target resolution. + :param method: Resampling method to use. + :return: + """ + return self.process("resample_cube_spatial", {"data": self, "target": target, "method": method}) + + @openeo_process + def resample_cube_temporal( + self, target: DataCube, dimension: Optional[str] = None, valid_within: Optional[int] = None + ) -> DataCube: + """ + 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. + + By 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``. + + The rare case of ties is resolved by choosing the earlier timestamps. + + :param target: A data cube that describes the temporal target resolution. + :param dimension: The name of the temporal dimension to resample. + :param valid_within: + :return: + + .. versionadded:: 0.10.0 + """ + return self.process( + "resample_cube_temporal", + dict_no_none({"data": self, "target": target, "dimension": dimension, "valid_within": valid_within}) + ) + + def _operator_binary(self, operator: str, other: Union[DataCube, int, float], reverse=False) -> DataCube: + """Generic handling of (mathematical) binary operator""" + band_math_mode = self._in_bandmath_mode() + if band_math_mode: + if isinstance(other, (int, float)): + return self._bandmath_operator_binary_scalar(operator, other, reverse=reverse) + elif isinstance(other, DataCube): + return self._bandmath_operator_binary_cubes(operator, other) + else: + if isinstance(other, DataCube): + return self._merge_operator_binary_cubes(operator, other) + elif isinstance(other, (int, float)): + # "`apply` math" mode + return self._apply_operator( + operator=operator, other=other, reverse=reverse + ) + raise OperatorException( + f"Unsupported operator {operator!r} with `other` type {type(other)!r} (band math mode={band_math_mode})" + ) + + def _operator_unary(self, operator: str, **kwargs) -> DataCube: + band_math_mode = self._in_bandmath_mode() + if band_math_mode: + return self._bandmath_operator_unary(operator, **kwargs) + else: + return self._apply_operator(operator=operator, extra_arguments=kwargs) + + def _apply_operator( + self, + operator: str, + other: Optional[Union[int, float]] = None, + reverse: Optional[bool] = None, + extra_arguments: Optional[dict] = None, + ) -> DataCube: + """ + Apply a unary or binary operator/process, + by appending to existing `apply` node, or starting a new one. + + :param operator: process id of operator + :param other: for binary operators: "other" argument + :param reverse: for binary operators: "self" and "other" should be swapped (reflected operator mode) + """ + if self.result_node().process_id == "apply": + # Append to existing `apply` node + orig_apply = self.result_node() + data = orig_apply.arguments["data"] + x = {"from_node": orig_apply.arguments["process"]["process_graph"]} + context = orig_apply.arguments.get("context") + else: + # Start new `apply` node. + data = self + x = {"from_parameter": "x"} + context = None + # Build args for child callback. + args = {"x": x, **(extra_arguments or {})} + if other is not None: + # Binary operator mode + args["y"] = other + if reverse: + args["x"], args["y"] = args["y"], args["x"] + child_pg = PGNode(process_id=operator, arguments=args) + return self.process_with_node( + PGNode( + process_id="apply", + arguments=dict_no_none( + data=data, + process={"process_graph": child_pg}, + context=context, + ), + ) + ) + + @openeo_process(mode="operator") + def add(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("add", other, reverse=reverse) + + @openeo_process(mode="operator") + def subtract(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("subtract", other, reverse=reverse) + + @openeo_process(mode="operator") + def divide(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("divide", other, reverse=reverse) + + @openeo_process(mode="operator") + def multiply(self, other: Union[DataCube, int, float], reverse=False) -> DataCube: + return self._operator_binary("multiply", other, reverse=reverse) + + @openeo_process + def normalized_difference(self, other: DataCube) -> DataCube: + # This DataCube method is only a convenience function when in band math mode + assert self._in_bandmath_mode() + assert other._in_bandmath_mode() + return self._operator_binary("normalized_difference", other) + + @openeo_process(process_id="or", mode="operator") + def logical_or(self, other: DataCube) -> DataCube: + """ + Apply element-wise logical `or` operation + + :param other: + :return: logical_or(this, other) + """ + return self._operator_binary("or", other) + + @openeo_process(process_id="and", mode="operator") + def logical_and(self, other: DataCube) -> DataCube: + """ + Apply element-wise logical `and` operation + + :param other: + :return: logical_and(this, other) + """ + return self._operator_binary("and", other) + + @openeo_process(process_id="not", mode="operator") + def __invert__(self) -> DataCube: + return self._operator_unary("not") + + @openeo_process(process_id="neq", mode="operator") + def __ne__(self, other: Union[DataCube, int, float]) -> DataCube: + return self._operator_binary("neq", other) + + @openeo_process(process_id="eq", mode="operator") + def __eq__(self, other: Union[DataCube, int, float]) -> DataCube: + """ + Pixelwise comparison of this data cube with another cube or constant. + + :param other: Another data cube, or a constant + :return: + """ + return self._operator_binary("eq", other) + + @openeo_process(process_id="gt", mode="operator") + def __gt__(self, other: Union[DataCube, int, float]) -> DataCube: + """ + Pairwise comparison of the bands in this data cube with the bands in the 'other' data cube. + + :param other: + :return: this > other + """ + return self._operator_binary("gt", other) + + @openeo_process(process_id="ge", mode="operator") + def __ge__(self, other: Union[DataCube, int, float]) -> DataCube: + return self._operator_binary("gte", other) + + @openeo_process(process_id="lt", mode="operator") + def __lt__(self, other: Union[DataCube, int, float]) -> DataCube: + """ + Pairwise comparison of the bands in this data cube with the bands in the 'other' data cube. + The number of bands in both data cubes has to be the same. + + :param other: + :return: this < other + """ + return self._operator_binary("lt", other) + + @openeo_process(process_id="le", mode="operator") + def __le__(self, other: Union[DataCube, int, float]) -> DataCube: + return self._operator_binary("lte", other) + + @openeo_process(process_id="add", mode="operator") + def __add__(self, other) -> DataCube: + return self.add(other) + + @openeo_process(process_id="add", mode="operator") + def __radd__(self, other) -> DataCube: + return self.add(other, reverse=True) + + @openeo_process(process_id="subtract", mode="operator") + def __sub__(self, other) -> DataCube: + return self.subtract(other) + + @openeo_process(process_id="subtract", mode="operator") + def __rsub__(self, other) -> DataCube: + return self.subtract(other, reverse=True) + + @openeo_process(process_id="multiply", mode="operator") + def __neg__(self) -> DataCube: + return self.multiply(-1) + + @openeo_process(process_id="multiply", mode="operator") + def __mul__(self, other) -> DataCube: + return self.multiply(other) + + @openeo_process(process_id="multiply", mode="operator") + def __rmul__(self, other) -> DataCube: + return self.multiply(other, reverse=True) + + @openeo_process(process_id="divide", mode="operator") + def __truediv__(self, other) -> DataCube: + return self.divide(other) + + @openeo_process(process_id="divide", mode="operator") + def __rtruediv__(self, other) -> DataCube: + return self.divide(other, reverse=True) + + @openeo_process(process_id="power", mode="operator") + def __rpow__(self, other) -> DataCube: + return self._power(other, reverse=True) + + @openeo_process(process_id="power", mode="operator") + def __pow__(self, other) -> DataCube: + return self._power(other, reverse=False) + + def _power(self, other, reverse=False): + node = self._get_bandmath_node() + x = node.reducer_process_graph() + y = other + if reverse: + x, y = y, x + return self.process_with_node(node.clone_with_new_reducer( + PGNode(process_id="power", base=x, p=y) + )) + + @openeo_process(process_id="power", mode="operator") + def power(self, p: float): + return self._power(other=p, reverse=False) + + @openeo_process(process_id="ln", mode="operator") + def ln(self) -> DataCube: + return self._operator_unary("ln") + + @openeo_process(process_id="log", mode="operator") + def logarithm(self, base: float) -> DataCube: + return self._operator_unary("log", base=base) + + @openeo_process(process_id="log", mode="operator") + def log2(self) -> DataCube: + return self.logarithm(base=2) + + @openeo_process(process_id="log", mode="operator") + def log10(self) -> DataCube: + return self.logarithm(base=10) + + @openeo_process(process_id="or", mode="operator") + def __or__(self, other) -> DataCube: + return self.logical_or(other) + + @openeo_process(process_id="and", mode="operator") + def __and__(self, other): + return self.logical_and(other) + + def _bandmath_operator_binary_cubes( + self, operator, other: DataCube, left_arg_name="x", right_arg_name="y" + ) -> DataCube: + """Band math binary operator with cube as right hand side argument""" + left = self._get_bandmath_node() + right = other._get_bandmath_node() + if left.arguments["data"] != right.arguments["data"]: + raise BandMathException("'Band math' between bands of different data cubes is not supported yet.") + + # Build reducer's sub-processgraph + merged = PGNode( + process_id=operator, + arguments={ + left_arg_name: {"from_node": left.reducer_process_graph()}, + right_arg_name: {"from_node": right.reducer_process_graph()}, + }, + ) + return self.process_with_node(left.clone_with_new_reducer(merged)) + + def _bandmath_operator_binary_scalar(self, operator: str, other: Union[int, float], reverse=False) -> DataCube: + """Band math binary operator with scalar value (int or float) as right hand side argument""" + node = self._get_bandmath_node() + x = {'from_node': node.reducer_process_graph()} + y = other + if reverse: + x, y = y, x + return self.process_with_node(node.clone_with_new_reducer( + PGNode(operator, x=x, y=y) + )) + + def _bandmath_operator_unary(self, operator: str, **kwargs) -> DataCube: + node = self._get_bandmath_node() + return self.process_with_node(node.clone_with_new_reducer( + PGNode(operator, x={'from_node': node.reducer_process_graph()}, **kwargs) + )) + + def _in_bandmath_mode(self) -> bool: + """So-called "band math" mode: current result node is reduce_dimension along "bands" dimension.""" + # TODO #123 is it (still) necessary to make "band" math a special case? + return isinstance(self._pg, ReduceNode) and self._pg.band_math_mode + + def _get_bandmath_node(self) -> ReduceNode: + """Check we are in bandmath mode and return the node""" + if not self._in_bandmath_mode(): + raise BandMathException("Must be in band math mode already") + return self._pg + + def _merge_operator_binary_cubes( + self, operator: str, other: DataCube, left_arg_name="x", right_arg_name="y" + ) -> DataCube: + """Merge two cubes with given operator as overlap_resolver.""" + # TODO #123 reuse an existing merge_cubes process graph if it already exists? + return self.merge_cubes(other, overlap_resolver=PGNode( + process_id=operator, + arguments={ + left_arg_name: {"from_parameter": "x"}, + right_arg_name: {"from_parameter": "y"}, + } + )) + + def _get_geometry_argument( + self, + geometry: Union[ + shapely.geometry.base.BaseGeometry, + dict, + str, + pathlib.Path, + Parameter, + _FromNodeMixin, + ], + valid_geojson_types: List[str], + crs: Optional[str] = None, + ) -> Union[dict, Parameter, PGNode]: + """ + Convert input to a geometry as "geojson" subtype object. + + :param crs: value that encodes a coordinate reference system. + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + """ + if isinstance(geometry, (str, pathlib.Path)): + # Assumption: `geometry` is path to polygon is a path to vector file at backend. + # TODO #104: `read_vector` is non-standard process. + # TODO: If path exists client side: load it client side? + return PGNode(process_id="read_vector", arguments={"filename": str(geometry)}) + elif isinstance(geometry, Parameter): + return geometry + elif isinstance(geometry, _FromNodeMixin): + return geometry.from_node() + + if isinstance(geometry, shapely.geometry.base.BaseGeometry): + geometry = mapping(geometry) + if not isinstance(geometry, dict): + raise OpenEoClientException("Invalid geometry argument: {g!r}".format(g=geometry)) + + if geometry.get("type") not in valid_geojson_types: + raise OpenEoClientException("Invalid geometry type {t!r}, must be one of {s}".format( + t=geometry.get("type"), s=valid_geojson_types + )) + if crs: + # TODO: don't warn when the crs is Lon-Lat like EPSG:4326? + warnings.warn(f"Geometry with non-Lon-Lat CRS {crs!r} is only supported by specific back-ends.") + # TODO #204 alternative for non-standard CRS in GeoJSON object? + epsg_code = normalize_crs(crs) + if epsg_code is not None: + # proj did recognize the CRS + crs_name = f"EPSG:{epsg_code}" + else: + # proj did not recognise this CRS + warnings.warn(f"non-Lon-Lat CRS {crs!r} is not known to the proj library and might not be supported.") + crs_name = crs + geometry["crs"] = {"type": "name", "properties": {"name": crs_name}} + return geometry + + @openeo_process + def aggregate_spatial( + self, + geometries: Union[ + shapely.geometry.base.BaseGeometry, + dict, + str, + pathlib.Path, + Parameter, + VectorCube, + ], + reducer: Union[str, typing.Callable, PGNode], + target_dimension: Optional[str] = None, + crs: Optional[Union[int, str]] = None, + context: Optional[dict] = None, + # TODO arguments: target dimension, context + ) -> VectorCube: + """ + Aggregates statistics for one or more geometries (e.g. zonal statistics for polygons) + over the spatial dimensions. + + :param geometries: a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute ` (:ref:`predefined openEO process function `) + - ``lambda data: data.min()`` (function or lambda) + + :param target_dimension: The new dimension name to be used for storing the results. + :param crs: The spatial reference system of the provided polygon. + By default, longitude-latitude (EPSG:4326) is assumed. + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + + :param context: Additional data to be passed to the reducer process. + + .. note:: this ``crs`` argument is a non-standard/experimental feature, only supported by specific back-ends. + See https://github.com/Open-EO/openeo-processes/issues/235 for details. + """ + valid_geojson_types = [ + "Point", "MultiPoint", "LineString", "MultiLineString", + "Polygon", "MultiPolygon", "GeometryCollection", "Feature", "FeatureCollection" + ] + geometries = self._get_geometry_argument(geometries, valid_geojson_types=valid_geojson_types, crs=crs) + reducer = build_child_callback(reducer, parent_parameters=["data"]) + return VectorCube( + graph=self._build_pgnode( + process_id="aggregate_spatial", + data=THIS, + geometries=geometries, + reducer=reducer, + arguments=dict_no_none( + target_dimension=target_dimension, context=context + ), + ), + connection=self._connection, + # TODO: metadata? And correct dimension of created vector cube? #457 + ) + + @openeo_process + def aggregate_spatial_window( + self, + reducer: Union[str, typing.Callable, PGNode], + size: List[int], + boundary: str = "pad", + align: str = "upper-left", + context: Optional[dict] = None, + # TODO arguments: target dimension, context + ) -> DataCube: + """ + Aggregates statistics over the horizontal spatial dimensions (axes x and y) of the data cube. + + The 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. For each of these windows, the reducer process computes the result. + + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + :param size: Window size in pixels along the horizontal spatial dimensions. + The first value corresponds to the x axis, the second value corresponds to the y axis. + :param boundary: 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: + + - ``pad`` (default): pad the data cube with the no-data value null to fit the required window size. + - ``trim``: trim the data cube to fit the required window size. + + Use the parameter ``align`` to align the data to the desired corner. + + :param align: 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. + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values and the same dimensions. + """ + valid_boundary_types = ["pad", "trim"] + valid_align_types = ["lower-left", "upper-left", "lower-right", "upper-right"] + if boundary not in valid_boundary_types: + raise ValueError(f"Provided boundary type not supported. Please use one of {valid_boundary_types} .") + if align not in valid_align_types: + raise ValueError(f"Provided align type not supported. Please use one of {valid_align_types} .") + if len(size) != 2: + raise ValueError(f"Provided size not supported. Please provide a list of 2 integer values.") + + reducer = build_child_callback(reducer, parent_parameters=["data"]) + arguments = { + "data": THIS, + "boundary": boundary, + "align": align, + "size": size, + "reducer": reducer, + "context": context, + } + return self.process(process_id="aggregate_spatial_window", arguments=arguments) + + @openeo_process + def apply_dimension( + self, + code: Optional[str] = None, + runtime=None, + # TODO: drop None default of process (when `code` and `runtime` args can be dropped) + process: Union[str, typing.Callable, UDF, PGNode] = None, + version: Optional[str] = None, + # TODO: dimension has no default (per spec)? + dimension: str = "t", + target_dimension: Optional[str] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Applies a process to all pixel values along a dimension of a raster data cube. For example, + if the temporal dimension is specified the process will work on a time series of pixel values. + + The process to apply is specified by either `code` and `runtime` in case of a UDF, or by providing a callback function + in the `process` argument. + + The process reduce_dimension also applies a process to pixel values along a dimension, but drops + the dimension afterwards. The process apply applies a process to each pixel value in the data cube. + + The target dimension is the source dimension if not specified otherwise in the target_dimension parameter. + The pixel values in the target dimension get replaced by the computed pixel values. The name, type and + reference system are preserved. + + The dimension labels are preserved when the target dimension is the source dimension and the number of + pixel values in the source dimension is equal to the number of values computed by the process. Otherwise, + the dimension labels will be incrementing integers starting from zero, which can be changed using + rename_labels afterwards. The number of labels will equal to the number of values computed by the process. + + :param code: [**deprecated**] UDF code or process identifier (optional) + :param runtime: [**deprecated**] UDF runtime to use (optional) + :param process: the "child callback": + the name of a single process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns an array of numerical values. + For example: + + - ``"sort"`` (string) + - :py:func:`sort ` (:ref:`predefined openEO process function `) + - ``lambda data: data.concat([42, -3])`` (function or lambda) + + + :param version: [**deprecated**] Version of the UDF runtime to use + :param dimension: The name of the source dimension to apply the process on. Fails with a DimensionNotAvailable error if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or null (the default) to use the source dimension + specified in the parameter dimension. By 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. + :param context: Additional data to be passed to the process. + + :return: A datacube with the UDF applied to the given dimension. + :raises: DimensionNotAvailable + + .. versionchanged:: 0.13.0 + arguments ``code``, ``runtime`` and ``version`` are deprecated if favor of the standard approach + of using an :py:class:`UDF ` object in the ``process`` argument. + See :ref:`old_udf_api` for more background about the changes. + + """ + # TODO #137 #181 #312 remove support for code/runtime/version + if runtime or (isinstance(code, str) and "\n" in code) or version: + if process: + raise ValueError( + "Cannot specify `process` argument together with deprecated `code`/`runtime`/`version` arguments." + ) + else: + warnings.warn( + "Specifying UDF code through `code`, `runtime` and `version` arguments is deprecated. " + "Instead create an `openeo.UDF` object and pass that to the `process` argument.", + category=UserDeprecationWarning, + stacklevel=2, + ) + process = UDF(code=code, runtime=runtime, version=version, context=context) + else: + process = process or code + process = build_child_callback( + process=process, parent_parameters=["data", "context"], connection=self.connection + ) + arguments = { + "data": THIS, + "process": process, + "dimension": self._assert_valid_dimension_name(dimension), + } + if target_dimension is not None: + arguments["target_dimension"] = target_dimension + if context is not None: + arguments["context"] = context + result_cube = self.process(process_id="apply_dimension", arguments=arguments) + + return result_cube + + @openeo_process + def reduce_dimension( + self, + dimension: str, + reducer: Union[str, typing.Callable, UDF, PGNode], + context: Optional[dict] = None, + process_id="reduce_dimension", + band_math_mode: bool = False, + ) -> DataCube: + """ + Add a reduce process with given reducer callback along given dimension + + :param dimension: the label of the dimension to reduce + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute ` (:ref:`predefined openEO process function `) + - ``lambda data: data.min()`` (function or lambda) + + :param context: Additional data to be passed to the process. + """ + # TODO: check if dimension is valid according to metadata? #116 + # TODO: #125 use/test case for `reduce_dimension_binary`? + reducer = build_child_callback( + process=reducer, parent_parameters=["data", "context"], connection=self.connection + ) + + return self.process_with_node( + ReduceNode( + process_id=process_id, + data=self, + reducer=reducer, + dimension=self._assert_valid_dimension_name(dimension), + context=context, + # TODO #123 is it (still) necessary to make "band" math a special case? + band_math_mode=band_math_mode, + ), + metadata=self.metadata.reduce_dimension(dimension_name=dimension) if self.metadata else None, + ) + + @openeo_process + def reduce_spatial( + self, + reducer: Union[str, typing.Callable, UDF, PGNode], + context: Optional[dict] = None, + ) -> "DataCube": + """ + Add a reduce process with given reducer callback along the spatial dimensions + + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute ` (:ref:`predefined openEO process function `) + - ``lambda data: data.min()`` (function or lambda) + + :param context: Additional data to be passed to the process. + """ + reducer = build_child_callback( + process=reducer, parent_parameters=["data", "context"], connection=self.connection + ) + return self.process( + process_id="reduce_spatial", + data=self, + reducer=reducer, + context=context, + metadata=self.metadata.reduce_spatial(), + ) + + @deprecated("Use :py:meth:`apply_polygon`.", version="0.26.0") + def chunk_polygon( + self, + chunks: Union[shapely.geometry.base.BaseGeometry, dict, str, pathlib.Path, Parameter, VectorCube], + process: Union[str, PGNode, typing.Callable, UDF], + mask_value: float = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Apply a process to spatial chunks of a data cube. + + .. warning:: experimental process: not generally supported, API subject to change. + + :param chunks: Polygons, provided as a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param process: "child callback" function, see :ref:`callbackfunctions` + :param mask_value: The value used for cells outside the polygon. + This provides a distinction between NoData cells within the polygon (due to e.g. clouds) + and masked cells outside it. If no value is provided, NoData cells are used outside the polygon. + :param context: Additional data to be passed to the process. + """ + process = build_child_callback(process, parent_parameters=["data"], connection=self.connection) + valid_geojson_types = [ + "Polygon", + "MultiPolygon", + "GeometryCollection", + "Feature", + "FeatureCollection", + ] + chunks = self._get_geometry_argument( + chunks, valid_geojson_types=valid_geojson_types + ) + mask_value = float(mask_value) if mask_value is not None else None + return self.process( + process_id="chunk_polygon", + data=THIS, + chunks=chunks, + process=process, + arguments=dict_no_none( + mask_value=mask_value, + context=context, + ), + ) + + @openeo_process + def apply_polygon( + self, + polygons: Union[shapely.geometry.base.BaseGeometry, dict, str, pathlib.Path, Parameter, VectorCube], + process: Union[str, PGNode, typing.Callable, UDF], + mask_value: Optional[float] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Apply a process to segments of the data cube that are defined by the given polygons. + For each polygon provided, all pixels for which the point at the pixel center intersects + with the polygon (as defined in the Simple Features standard by the OGC) are collected into sub data cubes. + If a pixel is part of multiple of the provided polygons (e.g., when the polygons overlap), + the GeometriesOverlap exception is thrown. + Each sub data cube is passed individually to the given process. + + .. warning:: experimental process: not generally supported, API subject to change. + + :param polygons: Polygons, provided as a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param process: "child callback" function, see :ref:`callbackfunctions` + :param mask_value: The value used for pixels outside the polygon. + :param context: Additional data to be passed to the process. + """ + process = build_child_callback(process, parent_parameters=["data"], connection=self.connection) + valid_geojson_types = ["Polygon", "MultiPolygon", "Feature", "FeatureCollection"] + polygons = self._get_geometry_argument(polygons, valid_geojson_types=valid_geojson_types) + mask_value = float(mask_value) if mask_value is not None else None + return self.process( + process_id="apply_polygon", + data=THIS, + polygons=polygons, + process=process, + arguments=dict_no_none( + mask_value=mask_value, + context=context, + ), + ) + + def reduce_bands(self, reducer: Union[str, PGNode, typing.Callable, UDF]) -> DataCube: + """ + Shortcut for :py:meth:`reduce_dimension` along the band dimension + + :param reducer: "child callback" function, see :ref:`callbackfunctions` + """ + return self.reduce_dimension( + dimension=self.metadata.band_dimension.name if self.metadata else "bands", + reducer=reducer, + band_math_mode=True, + ) + + def reduce_temporal(self, reducer: Union[str, PGNode, typing.Callable, UDF]) -> DataCube: + """ + Shortcut for :py:meth:`reduce_dimension` along the temporal dimension + + :param reducer: "child callback" function, see :ref:`callbackfunctions` + """ + return self.reduce_dimension( + dimension=self.metadata.temporal_dimension.name if self.metadata else "t", + reducer=reducer, + ) + + @deprecated( + "Use :py:meth:`reduce_bands` with :py:class:`UDF ` as reducer.", + version="0.13.0", + ) + def reduce_bands_udf(self, code: str, runtime: Optional[str] = None, version: Optional[str] = None) -> DataCube: + """ + Use `reduce_dimension` process with given UDF along band/spectral dimension. + """ + # TODO #181 #312 drop this deprecated pattern + return self.reduce_bands(reducer=UDF(code=code, runtime=runtime, version=version)) + + @openeo_process + def add_dimension(self, name: str, label: str, type: Optional[str] = None): + """ + Adds a new named dimension to the data cube. + Afterwards, 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. + + This call does not modify the datacube in place, but returns a new datacube with the additional dimension. + + :param name: The name of the dimension to add + :param label: The dimension label. + :param type: Dimension type, allowed values: 'spatial', 'temporal', 'bands', 'other', default value is 'other' + :return: The data cube with a newly added dimension. The new dimension has exactly one dimension label. All other dimensions remain unchanged. + """ + return self.process( + process_id="add_dimension", + arguments=dict_no_none({"data": self, "name": name, "label": label, "type": type}), + metadata=self.metadata.add_dimension(name=name, label=label, type=type) if self.metadata else None, + ) + + @openeo_process + def drop_dimension(self, name: str): + """ + Drops a dimension from the data cube. + Dropping 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. + + :param name: The name of the dimension to drop + :return: The data cube with the given dimension dropped. + """ + return self.process( + process_id="drop_dimension", + arguments={"data": self, "name": name}, + metadata=self.metadata.drop_dimension(name=name) if self.metadata else None, + ) + + @deprecated( + "Use :py:meth:`reduce_temporal` with :py:class:`UDF ` as reducer", + version="0.13.0", + ) + def reduce_temporal_udf(self, code: str, runtime="Python", version="latest"): + """ + Apply reduce (`reduce_dimension`) process with given UDF along temporal dimension. + + :param code: The UDF code, compatible with the given runtime and version + :param runtime: The UDF runtime + :param version: The UDF runtime version + """ + # TODO #181 #312 drop this deprecated pattern + return self.reduce_temporal(reducer=UDF(code=code, runtime=runtime, version=version)) + + reduce_tiles_over_time = legacy_alias( + reduce_temporal_udf, name="reduce_tiles_over_time", since="0.1.1" + ) + + @openeo_process + def apply_neighborhood( + self, + process: Union[str, PGNode, typing.Callable, UDF], + size: List[Dict], + overlap: List[dict] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Applies a focal process to a data cube. + + A 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`. + + An 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 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. + + The process must not add new dimensions, or remove entire dimensions, but the result can have different dimension labels. + + For the special case of 2D convolution, it is recommended to use ``apply_kernel()``. + + :param size: + :param overlap: + :param process: a callback function that creates a process graph, see :ref:`callbackfunctions` + :param context: Additional data to be passed to the process. + + :return: + """ + return self.process( + process_id="apply_neighborhood", + arguments=dict_no_none( + data=THIS, + process=build_child_callback(process=process, parent_parameters=["data"], connection=self.connection), + size=size, + overlap=overlap, + context=context, + ) + ) + + @openeo_process + def apply( + self, + process: Union[str, typing.Callable, UDF, PGNode], + context: Optional[dict] = None, + ) -> DataCube: + """ + Applies a unary process (a local operation) to each value of the specified or all dimensions in the data cube. + + :param process: the "child callback": + the name of a single process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + + The callback should correspond to a process that + receives a single numerical value + and returns a single numerical value. + For example: + + - ``"absolute"`` (string) + - :py:func:`absolute ` (:ref:`predefined openEO process function `) + - ``lambda x: x * 2 + 3`` (function or lambda) + + :param context: Additional data to be passed to the process. + + :return: A data cube with the newly computed values. The resolution, cardinality and the number of dimensions are the same as for the original data cube. + """ + return self.process( + process_id="apply", + arguments=dict_no_none( + { + "data": THIS, + "process": build_child_callback(process, parent_parameters=["x"], connection=self.connection), + "context": context, + } + ), + ) + + reduce_temporal_simple = legacy_alias( + reduce_temporal, "reduce_temporal_simple", since="0.13.0" + ) + + @openeo_process(process_id="min", mode="reduce_dimension") + def min_time(self) -> DataCube: + """ + Finds the minimum value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("min") + + @openeo_process(process_id="max", mode="reduce_dimension") + def max_time(self) -> DataCube: + """ + Finds the maximum value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("max") + + @openeo_process(process_id="mean", mode="reduce_dimension") + def mean_time(self) -> DataCube: + """ + Finds the mean value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("mean") + + @openeo_process(process_id="median", mode="reduce_dimension") + def median_time(self) -> DataCube: + """ + Finds the median value of a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("median") + + @openeo_process(process_id="count", mode="reduce_dimension") + def count_time(self) -> DataCube: + """ + Counts the number of images with a valid mask in a time series for all bands of the input dataset. + + :return: a DataCube instance + """ + return self.reduce_temporal("count") + + @openeo_process + def aggregate_temporal( + self, + intervals: List[list], + reducer: Union[str, typing.Callable, PGNode], + labels: Optional[List[str]] = None, + dimension: Optional[str] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Computes a temporal aggregation based on an array of date and/or time intervals. + + Calendar hierarchies such as year, month, week etc. must be transformed into specific intervals by the clients. For each interval, all data along the dimension will be passed through the reducer. The computed values will be projected to the labels, so the number of labels and the number of intervals need to be equal. + + If the dimension is not set, the data cube is expected to only have one temporal dimension. + + :param intervals: Temporal left-closed intervals so that the start time is contained, but not the end time. + :param reducer: the "child callback": + the name of a single openEO process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns a single numerical value. + For example: + + - ``"mean"`` (string) + - :py:func:`absolute ` (:ref:`predefined openEO process function `) + - ``lambda data: data.min()`` (function or lambda) + + :param labels: Labels for the intervals. The number of labels and the number of groups need to be equal. + :param dimension: The temporal dimension for aggregation. All data along the dimension will be passed through the specified reducer. If the dimension is not set, the data cube is expected to only have one temporal dimension. + :param context: Additional data to be passed to the reducer. Not set by default. + + :return: A :py:class:`DataCube` containing a result for each time window + """ + return self.process( + process_id="aggregate_temporal", + arguments=dict_no_none( + data=THIS, + intervals=intervals, + labels=labels, + dimension=dimension, + reducer=build_child_callback(reducer, parent_parameters=["data"]), + context=context, + ), + ) + + @openeo_process + def aggregate_temporal_period( + self, + period: str, + reducer: Union[str, PGNode, typing.Callable], + dimension: Optional[str] = None, + context: Optional[Dict] = None, + ) -> DataCube: + """ + Computes a temporal aggregation based on calendar hierarchies such as years, months or seasons. For other calendar hierarchies aggregate_temporal can be used. + + For each interval, all data along the dimension will be passed through the reducer. + + If the dimension is not set or is set to null, the data cube is expected to only have one temporal dimension. + + The period argument specifies the time intervals to aggregate. The following pre-defined values are available: + + - hour: Hour of the day + - day: Day of the year + - week: Week of the year + - 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. + - month: Month of the year + - season: Three month periods of the calendar seasons (December - February, March - May, June - August, September - November). + - tropical-season: Six month periods of the tropical seasons (November - April, May - October). + - year: Proleptic years + - decade: Ten year periods (0-to-9 decade), from a year ending in a 0 to the next year ending in a 9. + - decade-ad: Ten year periods (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. + + + :param period: The period of the time intervals to aggregate. + :param reducer: A reducer to be applied on all values along the specified dimension. The reducer must be a callable process (or a set processes) that accepts an array and computes a single return value of the same type as the input values, for example median. + :param dimension: The temporal dimension for aggregation. All data along the dimension will be passed through the specified reducer. If the dimension is not set, the data cube is expected to only have one temporal dimension. + :param context: Additional data to be passed to the reducer. + + :return: A data cube with the same dimensions. The dimension properties (name, type, labels, reference system and resolution) remain unchanged. + """ + return self.process( + process_id="aggregate_temporal_period", + arguments=dict_no_none( + data=THIS, + period=period, + dimension=dimension, + reducer=build_child_callback(reducer, parent_parameters=["data"]), + context=context, + ), + ) + + @openeo_process + def ndvi(self, nir: str = None, red: str = None, target_band: str = None) -> DataCube: + """ + Normalized Difference Vegetation Index (NDVI) + + :param nir: (optional) name of NIR band + :param red: (optional) name of red band + :param target_band: (optional) name of the newly created band + + :return: a DataCube instance + """ + if self.metadata is None: + metadata = None + elif target_band is None: + metadata = self.metadata.reduce_dimension(self.metadata.band_dimension.name) + else: + # TODO: first drop "bands" dim and re-add it with single "ndvi" band + metadata = self.metadata.append_band(Band(name=target_band, common_name="ndvi")) + return self.process( + process_id="ndvi", + arguments=dict_no_none( + data=THIS, nir=nir, red=red, target_band=target_band + ), + metadata=metadata, + ) + + @openeo_process + def rename_dimension(self, source: str, target: str): + """ + Renames a dimension in the data cube while preserving all other properties. + + :param source: The current name of the dimension. Fails with a DimensionNotAvailable error if the specified dimension does not exist. + :param target: A new Name for the dimension. Fails with a DimensionExists error if a dimension with the specified name exists. + + :return: A new datacube with the dimension renamed. + """ + if self._do_metadata_normalization() and target in self.metadata.dimension_names(): + raise ValueError('Target dimension name conflicts with existing dimension: %s.' % target) + return self.process( + process_id="rename_dimension", + arguments=dict_no_none( + data=THIS, + source=self._assert_valid_dimension_name(source), + target=target, + ), + metadata=self.metadata.rename_dimension(source, target) if self.metadata else None, + ) + + @openeo_process + def rename_labels(self, dimension: str, target: list, source: list = None) -> DataCube: + """ + Renames the labels of the specified dimension in the data cube from source to target. + + :param dimension: Dimension name + :param target: The new names for the labels. + :param source: The names of the labels as they are currently in the data cube. + + :return: An DataCube instance + """ + return self.process( + process_id="rename_labels", + arguments=dict_no_none( + data=THIS, + dimension=self._assert_valid_dimension_name(dimension), + target=target, + source=source, + ), + metadata=self.metadata.rename_labels(dimension, target, source) if self.metadata else None, + ) + + @openeo_process(mode="apply") + def linear_scale_range(self, input_min, input_max, output_min, output_max) -> DataCube: + """ + Performs a linear transformation between the input and output range. + + The 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. + + Potential use case include 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 or calculating percentages (0 - 100). + + The no-data value null is passed through and therefore gets propagated. + + :param input_min: Minimum input value + :param input_max: Maximum input value + :param output_min: Minimum value of the desired output range. + :param output_max: Maximum value of the desired output range. + :return: a DataCube instance + """ + + return self.apply(lambda x: x.linear_scale_range(input_min, input_max, output_min, output_max)) + + @openeo_process + def mask(self, mask: DataCube = None, replacement=None) -> DataCube: + """ + Applies a mask to a raster data cube. To apply a vector mask use `mask_polygon`. + + A 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). + + :param mask: the raster mask + :param replacement: the value to replace the masked pixels with + """ + return self.process( + process_id="mask", + arguments=dict_no_none(data=self, mask=mask, replacement=replacement), + ) + + @openeo_process + def mask_polygon( + self, + mask: Union[shapely.geometry.base.BaseGeometry, dict, str, pathlib.Path, Parameter, VectorCube], + srs: str = None, + replacement=None, + inside: bool = None, + ) -> DataCube: + """ + Applies a polygon mask to a raster data cube. To apply a raster mask use `mask`. + + All 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. + + The pixel values are replaced with the value specified for `replacement`, + which defaults to `no data`. + + :param mask: The geometry to mask with: a shapely geometry, a GeoJSON-style dictionary, + a public GeoJSON URL, or a path (that is valid for the back-end) to a GeoJSON file. + :param srs: The spatial reference system of the provided polygon. + By default longitude-latitude (EPSG:4326) is assumed. + + .. note:: this ``srs`` argument is a non-standard/experimental feature, only supported by specific back-ends. + See https://github.com/Open-EO/openeo-processes/issues/235 for details. + :param replacement: the value to replace the masked pixels with + """ + valid_geojson_types = ["Polygon", "MultiPolygon", "GeometryCollection", "Feature", "FeatureCollection"] + mask = self._get_geometry_argument(mask, valid_geojson_types=valid_geojson_types, crs=srs) + return self.process( + process_id="mask_polygon", + arguments=dict_no_none( + data=THIS, + mask=mask, + replacement=replacement, + inside=inside + ) + ) + + @openeo_process + def merge_cubes( + self, + other: DataCube, + overlap_resolver: Union[str, PGNode, typing.Callable] = None, + context: Optional[dict] = None, + ) -> DataCube: + """ + Merging two data cubes + + 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. + An 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. + + Examples for merging two data cubes: + + #. 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. + #. 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. + #. Data cubes with the dimensions x, y and t have the same dimension labels in x,y and t. There are two options: + * 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. + * 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. + #. 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. + + :param other: The data cube to merge with. + :param overlap_resolver: A reduction operator that resolves the conflict if the data overlaps. The reducer must return a value of the same data type as the input values are. The reduction operator may be a single process such as multiply or consist of multiple sub-processes. null (the default) can be specified if no overlap resolver is required. + :param context: Additional data to be passed to the process. + + :return: The merged data cube. + """ + arguments = {"cube1": self, "cube2": other} + if overlap_resolver: + arguments["overlap_resolver"] = build_child_callback(overlap_resolver, parent_parameters=["x", "y"]) + if ( + self.metadata + and self.metadata.has_band_dimension() + and isinstance(other, DataCube) + and other.metadata + and other.metadata.has_band_dimension() + ): + # Minimal client side metadata merging + merged_metadata = self.metadata + for b in other.metadata.band_dimension.bands: + if b not in merged_metadata.bands: + merged_metadata = merged_metadata.append_band(b) + else: + merged_metadata = None + # Overlapping bands without overlap resolver will give an error in the backend + if context: + arguments["context"] = context + return self.process(process_id="merge_cubes", arguments=arguments, metadata=merged_metadata) + + merge = legacy_alias(merge_cubes, name="merge", since="0.4.6") + + @openeo_process + def apply_kernel( + self, kernel: Union[np.ndarray, List[List[float]]], factor=1.0, border=0, + replace_invalid=0 + ) -> DataCube: + """ + Applies a focal operation based on a weighted kernel to each value of the specified dimensions in the data cube. + + The border parameter determines how the data is extended when the kernel overlaps with the borders. + The following options are available: + + * numeric value - fill with a user-defined constant number n: nnnnnn|abcdefgh|nnnnnn (default, with n = 0) + * replicate - repeat the value from the pixel at the border: aaaaaa|abcdefgh|hhhhhh + * reflect - mirror/reflect from the border: fedcba|abcdefgh|hgfedc + * reflect_pixel - mirror/reflect from the center of the pixel at the border: gfedcb|abcdefgh|gfedcb + * wrap - repeat/wrap the image: cdefgh|abcdefgh|abcdef + + + :param kernel: The kernel to be applied on the data cube. The kernel has to be as many dimensions as the data cube has dimensions. + :param factor: A factor that is multiplied to each value computed by the focal operation. This is basically a shortcut for explicitly multiplying each value by a factor afterwards, which is often required for some kernel-based algorithms such as the Gaussian blur. + :param border: Determines how the data is extended when the kernel overlaps with the borders. Defaults to fill the border with zeroes. + :param replace_invalid: This parameter specifies the value to replace non-numerical or infinite numerical values with. By default, those values are replaced with zeroes. + :return: A data cube with the newly computed values. The resolution, cardinality and the number of dimensions are the same as for the original data cube. + """ + return self.process('apply_kernel', { + 'data': THIS, + 'kernel': kernel.tolist() if isinstance(kernel, np.ndarray) else kernel, + 'factor': factor, + 'border': border, + 'replace_invalid': replace_invalid + }) + + @openeo_process + def resolution_merge( + self, high_resolution_bands: List[str], low_resolution_bands: List[str], method: str = None + ) -> DataCube: + """ + Resolution merging algorithms try to improve the spatial resolution of lower resolution bands + (e.g. Sentinel-2 20M) based on higher resolution bands. (e.g. Sentinel-2 10M). + + External references: + + `Pansharpening explained `_ + + `Example publication: 'Improving the Spatial Resolution of Land Surface Phenology by Fusing Medium- and + Coarse-Resolution Inputs' `_ + + .. warning:: experimental process: not generally supported, API subject to change. + + :param high_resolution_bands: A list of band names to use as 'high-resolution' band. 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. The 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. These bands will remain unmodified. + :param low_resolution_bands: A list of band names for which the spatial resolution should be increased. 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. The 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. These bands will be modified by the process. + :param method: The method to use. The supported algorithms can vary between back-ends. Set to `null` (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility.. + :return: A datacube with the same bands and metadata as the input, but algorithmically increased spatial resolution for the selected bands. + """ + return self.process('resolution_merge', { + 'data': THIS, + 'high_resolution_bands': high_resolution_bands, + 'low_resolution_bands': low_resolution_bands, + 'method': method, + + }) + + def raster_to_vector(self) -> VectorCube: + """ + Converts this raster data cube into a :py:class:`~openeo.rest.vectorcube.VectorCube`. + The bounding polygon of homogenous areas of pixels is constructed. + + .. warning:: experimental process: not generally supported, API subject to change. + + :return: a :py:class:`~openeo.rest.vectorcube.VectorCube` + """ + pg_node = PGNode(process_id="raster_to_vector", arguments={"data": self}) + return VectorCube(pg_node, connection=self._connection) + + ####VIEW methods ####### + + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'mean'``.", version="0.10.0" + ) + def polygonal_mean_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a mean time series for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="mean") + + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'histogram'``.", + version="0.10.0", + ) + def polygonal_histogram_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a histogram time series for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="histogram") + + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'median'``.", version="0.10.0" + ) + def polygonal_median_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a median time series for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="median") + + @deprecated( + "Use :py:meth:`aggregate_spatial` with reducer ``'sd'``.", version="0.10.0" + ) + def polygonal_standarddeviation_timeseries( + self, polygon: Union[Polygon, MultiPolygon, str] + ) -> VectorCube: + """ + Extract a time series of standard deviations for the given (multi)polygon. Its points are + expected to be in the EPSG:4326 coordinate + reference system. + + :param polygon: The (multi)polygon; or a file path or HTTP URL to a GeoJSON file or shape file + """ + return self.aggregate_spatial(geometries=polygon, reducer="sd") + + @openeo_process + def ard_surface_reflectance( + self, atmospheric_correction_method: str, cloud_detection_method: str, elevation_model: str = None, + atmospheric_correction_options: dict = None, cloud_detection_options: dict = None, + ) -> DataCube: + """ + Computes CARD4L compliant surface reflectance values from optical input. + + :param atmospheric_correction_method: The atmospheric correction method to use. + :param cloud_detection_method: The cloud detection method to use. + :param elevation_model: The digital elevation model to use, leave empty to allow the back-end to make a suitable choice. + :param atmospheric_correction_options: Proprietary options for the atmospheric correction method. + :param cloud_detection_options: Proprietary options for the cloud detection method. + :return: Data cube containing bottom of atmosphere reflectances with atmospheric disturbances like clouds and cloud shadows removed. The data returned is CARD4L compliant and contains metadata. + """ + return self.process('ard_surface_reflectance', { + 'data': THIS, + 'atmospheric_correction_method': atmospheric_correction_method, + 'cloud_detection_method': cloud_detection_method, + 'elevation_model': elevation_model, + 'atmospheric_correction_options': atmospheric_correction_options or {}, + 'cloud_detection_options': cloud_detection_options or {}, + }) + + @openeo_process + def atmospheric_correction(self, method: str = None, elevation_model: str = None, options: dict = None) -> DataCube: + """ + Applies an atmospheric correction that converts top of atmosphere reflectance values into bottom of atmosphere/top of canopy reflectance values. + + Note that multiple atmospheric methods exist, but may not be supported by all backends. The method parameter gives + you the option of requiring a specific method, but this may result in an error if the backend does not support it. + + :param method: The atmospheric correction method to use. To get reproducible results, you have to set a specific method. Set 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. + :param elevation_model: The digital elevation model to use, leave empty to allow the back-end to make a suitable choice. + :param options: Proprietary options for the atmospheric correction method. + :return: datacube with bottom of atmosphere reflectances + """ + return self.process('atmospheric_correction', { + 'data': THIS, + 'method': method, + 'elevation_model': elevation_model, + 'options': options or {}, + }) + + @openeo_process + def save_result( + self, + format: str = _DEFAULT_RASTER_FORMAT, + options: Optional[dict] = None, + ) -> DataCube: + formats = set(self._connection.list_output_formats().keys()) + # TODO: map format to correct casing too? + if format.lower() not in {f.lower() for f in formats}: + raise ValueError("Invalid format {f!r}. Should be one of {s}".format(f=format, s=formats)) + return self.process( + process_id="save_result", + arguments={ + "data": THIS, + "format": format, + # TODO: leave out options if unset? + "options": options or {} + } + ) + + def _ensure_save_result( + self, + format: Optional[str] = None, + options: Optional[dict] = None, + ) -> DataCube: + """ + Make sure there is a (final) `save_result` node in the process graph. + If there is already one: check if it is consistent with the given format/options (if any) + and add a new one otherwise. + + :param format: (optional) desired `save_result` file format + :param options: (optional) desired `save_result` file format parameters + :return: + """ + # TODO #401 Unify with VectorCube._ensure_save_result and move to generic data cube parent class (not only for raster cubes, but also vector cubes) + result_node = self.result_node() + if result_node.process_id == "save_result": + # There is already a `save_result` node: + # check if it is consistent with given format/options (if any) + args = result_node.arguments + if format is not None and format.lower() != args["format"].lower(): + raise ValueError( + f"Existing `save_result` node with different format {args['format']!r} != {format!r}" + ) + if options is not None and options != args["options"]: + raise ValueError( + f"Existing `save_result` node with different options {args['options']!r} != {options!r}" + ) + cube = self + else: + # No `save_result` node yet: automatically add it. + cube = self.save_result( + format=format or self._DEFAULT_RASTER_FORMAT, options=options + ) + return cube + + def download( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + format: Optional[str] = None, + options: Optional[dict] = None, + *, + validate: Optional[bool] = None, + ) -> Union[None, bytes]: + """ + Execute synchronously and download the raster data cube, e.g. as GeoTIFF. + + If outputfile is provided, the result is stored on disk locally, otherwise, a bytes object is returned. + The bytes object can be passed on to a suitable decoder for decoding. + + :param outputfile: Optional, an output file if the result needs to be stored on disk. + :param format: Optional, an output format supported by the backend. + :param options: Optional, file format options + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + :return: None if the result is stored to disk, or a bytes object returned by the backend. + """ + if format is None and outputfile: + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + format = guess_format(outputfile) + cube = self._ensure_save_result(format=format, options=options) + return self._connection.download(cube.flat_graph(), outputfile, validate=validate) + + def validate(self) -> List[dict]: + """ + Validate a process graph without executing it. + + :return: list of errors (dictionaries with "code" and "message" fields) + """ + return self._connection.validate_process_graph(self.flat_graph()) + + def tiled_viewing_service(self, type: str, **kwargs) -> Service: + return self._connection.create_service(self.flat_graph(), type=type, **kwargs) + + def _get_spatial_extent_from_load_collection(self): + pg = self.flat_graph() + for node in pg: + if pg[node]["process_id"] == "load_collection": + if "spatial_extent" in pg[node]["arguments"] and all( + cd in pg[node]["arguments"]["spatial_extent"] for cd in ["east", "west", "south", "north"] + ): + return pg[node]["arguments"]["spatial_extent"] + return None + + def preview( + self, + center: Union[Iterable, None] = None, + zoom: Union[int, None] = None, + ): + """ + Creates a service with the process graph and displays a map widget. Only supports XYZ. + + :param center: (optional) Map center. Default is (0,0). + :param zoom: (optional) Zoom level of the map. Default is 1. + + :return: ipyleaflet Map object and the displayed Service + + .. warning:: experimental feature, subject to change. + .. versionadded:: 0.19.0 + """ + if "XYZ" not in self.connection.list_service_types(): + raise OpenEoClientException("Backend does not support service type 'XYZ'.") + + if not in_jupyter_context(): + raise Exception("On-demand preview only supported in Jupyter notebooks!") + try: + import ipyleaflet + except ImportError: + raise Exception( + "Additional modules must be installed for on-demand preview. Run `pip install openeo[jupyter]` or refer to the documentation." + ) + + service = self.tiled_viewing_service("XYZ") + service_metadata = service.describe_service() + + m = ipyleaflet.Map( + center=center or (0, 0), + zoom=zoom or 1, + scroll_wheel_zoom=True, + basemap=ipyleaflet.basemaps.OpenStreetMap.Mapnik, + ) + service_layer = ipyleaflet.TileLayer(url=service_metadata["url"]) + m.add(service_layer) + + if center is None and zoom is None: + spatial_extent = self._get_spatial_extent_from_load_collection() + if spatial_extent is not None: + m.fit_bounds( + [ + [spatial_extent["south"], spatial_extent["west"]], + [spatial_extent["north"], spatial_extent["east"]], + ] + ) + + class Preview: + """ + On-demand preview instance holding the associated XYZ service and ipyleaflet Map + """ + + def __init__(self, service: Service, ipyleaflet_map: ipyleaflet.Map): + self.service = service + self.map = ipyleaflet_map + + def _repr_html_(self): + from IPython.display import display + + display(self.map) + + def delete_service(self): + self.service.delete_service() + + return Preview(service, m) + + def execute_batch( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + out_format: Optional[str] = None, + *, + print: typing.Callable[[str], None] = print, + max_poll_interval: float = 60, + connection_retry_interval: float = 30, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + # TODO: avoid `format_options` as keyword arguments + **format_options, + ) -> BatchJob: + """ + Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. + This method is mostly recommended if the batch job is expected to run in a reasonable amount of time. + + For very long-running jobs, you probably do not want to keep the client running. + + :param outputfile: The path of a file to which a result can be written + :param out_format: (optional) File format to use for the job result. + :param job_options: + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + """ + if "format" in format_options and not out_format: + out_format = format_options["format"] # align with 'download' call arg name + if out_format is None and outputfile: + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + out_format = guess_format(outputfile) + + job = self.create_job(out_format=out_format, job_options=job_options, validate=validate, **format_options) + return job.run_synchronous( + outputfile=outputfile, + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + ) + + def create_job( + self, + out_format: Optional[str] = None, + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + # TODO: avoid `format_options` as keyword arguments + **format_options, + ) -> BatchJob: + """ + Sends the datacube's process graph as a batch job to the back-end + and return a :py:class:`~openeo.rest.job.BatchJob` instance. + + Note that the batch job will just be created at the back-end, + it still needs to be started and tracked explicitly. + Use :py:meth:`execute_batch` instead to have the openEO Python client take care of that job management. + + :param out_format: output file format. + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param job_options: custom job options. + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: Created job. + """ + # TODO: add option to also automatically start the job? + # TODO: avoid using all kwargs as format_options + # TODO: centralize `create_job` for `DataCube`, `VectorCube`, `MlModel`, ... + cube = self._ensure_save_result(format=out_format, options=format_options or None) + return self._connection.create_job( + process_graph=cube.flat_graph(), + title=title, + description=description, + plan=plan, + budget=budget, + validate=validate, + additional=job_options, + ) + + send_job = legacy_alias(create_job, name="send_job", since="0.10.0") + + def save_user_defined_process( + self, + user_defined_process_id: str, + public: bool = False, + summary: Optional[str] = None, + description: Optional[str] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, + ) -> RESTUserDefinedProcess: + """ + Saves this process graph in the backend as a user-defined process for the authenticated user. + + :param user_defined_process_id: unique identifier for the process + :param public: visible to other users? + :param summary: A short summary of what the process does. + :param description: Detailed description to explain the entity. CommonMark 0.29 syntax MAY be used for rich text representation. + :param returns: Description and schema of the return value. + :param categories: A list of categories. + :param examples: A list of examples. + :param links: A list of links. + :return: a RESTUserDefinedProcess instance + """ + return self._connection.save_user_defined_process( + user_defined_process_id=user_defined_process_id, + process_graph=self.flat_graph(), public=public, summary=summary, description=description, + returns=returns, categories=categories, examples=examples, links=links, + ) + + def execute(self, *, validate: Optional[bool] = None) -> dict: + """Executes the process graph.""" + return self._connection.execute(self.flat_graph(), validate=validate) + + @staticmethod + @deprecated(reason="Use :py:func:`openeo.udf.run_code.execute_local_udf` instead", version="0.7.0") + def execute_local_udf(udf: str, datacube: Union[str, 'xarray.DataArray', 'XarrayDataCube'] = None, fmt='netcdf'): + import openeo.udf.run_code + return openeo.udf.run_code.execute_local_udf(udf=udf, datacube=datacube, fmt=fmt) + + @openeo_process + def ard_normalized_radar_backscatter( + self, elevation_model: str = None, contributing_area=False, + ellipsoid_incidence_angle: bool = False, noise_removal: bool = True + ) -> DataCube: + """ + Computes CARD4L compliant backscatter (gamma0) from SAR input. + This method is a variant of :py:meth:`~openeo.rest.datacube.DataCube.sar_backscatter`, + with restricted parameters to generate backscatter according to CARD4L specifications. + + Note 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. + + :param elevation_model: The digital elevation model to use. Set to None (the default) to allow the back-end to choose, which will improve portability, but reduce reproducibility. + :param contributing_area: If set to `true`, a DEM-based local contributing area band named `contributing_area` + is added. The values are given in square meters. + :param ellipsoid_incidence_angle: If set to `True`, an ellipsoidal incidence angle band named `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `True`, which removes noise. + + :return: Backscatter values expressed as gamma0. The data returned is CARD4L compliant and contains metadata. By default, the backscatter values are given in linear scale. + """ + return self.process(process_id="ard_normalized_radar_backscatter", arguments={ + "data": THIS, + "elevation_model": elevation_model, + "contributing_area": contributing_area, + "ellipsoid_incidence_angle": ellipsoid_incidence_angle, + "noise_removal": noise_removal + }) + + @openeo_process + def sar_backscatter( + self, + coefficient: Union[str, None] = "gamma0-terrain", + elevation_model: Union[str, None] = None, + mask: bool = False, + contributing_area: bool = False, + local_incidence_angle: bool = False, + ellipsoid_incidence_angle: bool = False, + noise_removal: bool = True, + options: Optional[dict] = None + ) -> DataCube: + """ + Computes backscatter from SAR input. + + Note 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. + + :param coefficient: Select the radiometric correction coefficient. + The following options are available: + + - `"beta0"`: radar brightness + - `"sigma0-ellipsoid"`: ground area computed with ellipsoid earth model + - `"sigma0-terrain"`: ground area computed with terrain earth model + - `"gamma0-ellipsoid"`: ground area computed with ellipsoid earth model in sensor line of sight + - `"gamma0-terrain"`: ground area computed with terrain earth model in sensor line of sight (default) + - `None`: non-normalized backscatter + :param elevation_model: The digital elevation model to use. Set to `None` (the default) to allow + the back-end to choose, which will improve portability, but reduce reproducibility. + :param mask: 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). + :param contributing_area: If set to `true`, a DEM-based local contributing area band named `contributing_area` + is added. The values are given in square meters. + :param local_incidence_angle: If set to `true`, a DEM-based local incidence angle band named + `local_incidence_angle` is added. The values are given in degrees. + :param ellipsoid_incidence_angle: If set to `true`, an ellipsoidal incidence angle band named + `ellipsoid_incidence_angle` is added. The values are given in degrees. + :param noise_removal: If set to `false`, no noise removal is applied. Defaults to `true`, which removes noise. + :param options: dictionary with additional (backend-specific) options. + :return: + + .. versionadded:: 0.4.9 + .. versionchanged:: 0.4.10 replace `orthorectify` and `rtc` arguments with `coefficient`. + """ + coefficient_options = [ + "beta0", "sigma0-ellipsoid", "sigma0-terrain", "gamma0-ellipsoid", "gamma0-terrain", None + ] + if coefficient not in coefficient_options: + raise OpenEoClientException("Invalid `sar_backscatter` coefficient {c!r}. Should be one of {o}".format( + c=coefficient, o=coefficient_options + )) + arguments = { + "data": THIS, + "coefficient": coefficient, + "elevation_model": elevation_model, + "mask": mask, + "contributing_area": contributing_area, + "local_incidence_angle": local_incidence_angle, + "ellipsoid_incidence_angle": ellipsoid_incidence_angle, + "noise_removal": noise_removal, + } + if options: + arguments["options"] = options + return self.process(process_id="sar_backscatter", arguments=arguments) + + @openeo_process + def fit_curve(self, parameters: list, function: Union[str, PGNode, typing.Callable], dimension: str): + """ + Use non-linear least squares to fit a model function `y = f(x, parameters)` to data. + + The process throws an `InvalidValues` exception if invalid values are encountered. + Invalid values are finite numbers (see also ``is_valid()``). + + .. warning:: experimental process: not generally supported, API subject to change. + https://github.com/Open-EO/openeo-processes/pull/240 + + :param parameters: + :param function: "child callback" function, see :ref:`callbackfunctions` + :param dimension: + """ + # TODO: does this return a `DataCube`? Shouldn't it just return an array (wrapper)? + return self.process( + process_id="fit_curve", + arguments={ + "data": THIS, + "parameters": parameters, + "function": build_child_callback(function, parent_parameters=["x", "parameters"]), + "dimension": dimension, + }, + ) + + @openeo_process + def predict_curve( + self, parameters: list, function: Union[str, PGNode, typing.Callable], dimension: str, + labels=None + ): + """ + Predict values using a model function and pre-computed parameters. + + .. warning:: experimental process: not generally supported, API subject to change. + https://github.com/Open-EO/openeo-processes/pull/240 + + :param parameters: + :param function: "child callback" function, see :ref:`callbackfunctions` + :param dimension: + """ + return self.process( + process_id="predict_curve", + arguments={ + "data": THIS, + "parameters": parameters, + "function": build_child_callback(function, parent_parameters=["x", "parameters"]), + "dimension": dimension, + "labels": labels, + }, + ) + + @openeo_process(mode="reduce_dimension") + def predict_random_forest(self, model: Union[str, BatchJob, MlModel], dimension: str = "bands"): + """ + Apply ``reduce_dimension`` process with a ``predict_random_forest`` reducer. + + :param model: a reference to a trained model, one of + + - a :py:class:`~openeo.rest.mlmodel.MlModel` instance (e.g. loaded from :py:meth:`Connection.load_ml_model`) + - a :py:class:`~openeo.rest.job.BatchJob` instance of a batch job that saved a single random forest model + - a job id (``str``) of a batch job that saved a single random forest model + - a STAC item URL (``str``) to load the random forest from. + (The STAC Item must implement the `ml-model` extension.) + :param dimension: dimension along which to apply the ``reduce_dimension`` process. + + .. versionadded:: 0.10.0 + """ + if not isinstance(model, MlModel): + model = MlModel.load_ml_model(connection=self.connection, id=model) + reducer = PGNode( + process_id="predict_random_forest", data={"from_parameter": "data"}, model={"from_parameter": "context"} + ) + return self.reduce_dimension(dimension=dimension, reducer=reducer, context=model) + + @openeo_process + def dimension_labels(self, dimension: str) -> DataCube: + """ + Gives all labels for a dimension in the data cube. The labels have the same order as in the data cube. + + :param dimension: The name of the dimension to get the labels for. + """ + if self._do_metadata_normalization(): + dimension_names = self.metadata.dimension_names() + if dimension_names and dimension not in dimension_names: + raise ValueError(f"Invalid dimension name {dimension!r}, should be one of {dimension_names}") + return self.process(process_id="dimension_labels", arguments={"data": THIS, "dimension": dimension}) + + @openeo_process + def flatten_dimensions(self, dimensions: List[str], target_dimension: str, label_separator: Optional[str] = None): + """ + Combines multiple given dimensions into a single dimension by flattening the values + and merging the dimension labels with the given `label_separator`. Non-string dimension labels will + be converted to strings. This process is the opposite of the process :py:meth:`unflatten_dimension()` + but executing both processes subsequently doesn't necessarily create a data cube that + is equal to the original data cube. + + :param dimensions: The names of the dimension to combine. + :param target_dimension: The name of a target dimension with a single dimension label to replace. + :param label_separator: The string that will be used as a separator for the concatenated dimension labels. + :return: A data cube with the new shape. + + .. warning:: experimental process: not generally supported, API subject to change. + .. versionadded:: 0.10.0 + """ + return self.process( + process_id="flatten_dimensions", + arguments=dict_no_none( + data=THIS, + dimensions=dimensions, + target_dimension=target_dimension, + label_separator=label_separator, + ), + ) + + @openeo_process + def unflatten_dimension(self, dimension: str, target_dimensions: List[str], label_separator: Optional[str] = None): + """ + Splits a single dimension into multiple dimensions by systematically extracting values and splitting + the dimension labels by the given `label_separator`. + This process is the opposite of the process :py:meth:`flatten_dimensions()` but executing both processes + subsequently doesn't necessarily create a data cube that is equal to the original data cube. + + :param dimension: The name of the dimension to split. + :param target_dimensions: The names of the target dimensions. + :param label_separator: The string that will be used as a separator to split the dimension labels. + :return: A data cube with the new shape. + + .. warning:: experimental process: not generally supported, API subject to change. + .. versionadded:: 0.10.0 + """ + return self.process( + process_id="unflatten_dimension", + arguments=dict_no_none( + data=THIS, + dimension=dimension, + target_dimensions=target_dimensions, + label_separator=label_separator, + ), + ) diff --git a/lib/openeo/rest/graph_building.py b/lib/openeo/rest/graph_building.py new file mode 100644 index 000000000..d05eae930 --- /dev/null +++ b/lib/openeo/rest/graph_building.py @@ -0,0 +1,78 @@ +""" +Public openEO process graph building utilities +''''''''''''''''''''''''''''''''''''''''''''''' + +""" +from __future__ import annotations + +from typing import Optional + +from openeo.internal.graph_building import PGNode, _FromNodeMixin +from openeo.processes import ProcessBuilder + + +class CollectionProperty(_FromNodeMixin): + """ + Helper object to easily create simple collection metadata property filters + to be used with :py:meth:`Connection.load_collection() `. + + .. note:: This class should not be used directly by end user code. + Use the :py:func:`~openeo.rest.graph_building.collection_property` factory instead. + + .. warning:: this is an experimental feature, naming might change. + """ + + def __init__(self, name: str, _builder: Optional[ProcessBuilder] = None): + self.name = name + self._builder = _builder or ProcessBuilder(pgnode={"from_parameter": "value"}) + + def from_node(self) -> PGNode: + return self._builder.from_node() + + def __eq__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder == other) + + def __ne__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder != other) + + def __gt__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder > other) + + def __ge__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder >= other) + + def __lt__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder < other) + + def __le__(self, other) -> CollectionProperty: + return CollectionProperty(self.name, _builder=self._builder <= other) + + +def collection_property(name: str) -> CollectionProperty: + """ + Helper to easily create simple collection metadata property filters + to be used with :py:meth:`Connection.load_collection() `. + + Usage example: + + .. code-block:: python + + from openeo import collection_property + ... + + connection.load_collection( + ... + properties=[ + collection_property("eo:cloud_cover") <= 75, + collection_property("platform") == "Sentinel-2B", + ] + ) + + .. warning:: this is an experimental feature, naming might change. + + .. versionadded:: 0.26.0 + + :param name: name of the collection property to filter on + :return: an object that supports operators like ``<=``, ``==`` to easily build simple property filters. + """ + return CollectionProperty(name=name) diff --git a/lib/openeo/rest/job.py b/lib/openeo/rest/job.py new file mode 100644 index 000000000..a911b3482 --- /dev/null +++ b/lib/openeo/rest/job.py @@ -0,0 +1,531 @@ +from __future__ import annotations + +import datetime +import json +import logging +import time +import typing +from pathlib import Path +from typing import Dict, List, Optional, Union + +import requests + +from openeo.api.logs import LogEntry, log_level_name, normalize_log_level +from openeo.internal.documentation import openeo_endpoint +from openeo.internal.jupyter import ( + VisualDict, + VisualList, + render_component, + render_error, +) +from openeo.internal.warnings import deprecated, legacy_alias +from openeo.rest import JobFailedException, OpenEoApiError, OpenEoClientException, OpenEoApiPlainError +from openeo.util import ensure_dir + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + from openeo.rest.connection import Connection + +logger = logging.getLogger(__name__) + + +class BatchJob: + """ + Handle for an openEO batch job, allowing it to describe, start, cancel, inspect results, etc. + + .. versionadded:: 0.11.0 + This class originally had the more cryptic name :py:class:`RESTJob`, + which is still available as legacy alias, + but :py:class:`BatchJob` is recommended since version 0.11.0. + + """ + + # TODO #425 method to bootstrap `load_stac` directly from a BatchJob object + + def __init__(self, job_id: str, connection: Connection): + self.job_id = job_id + """Unique identifier of the batch job (string).""" + + self.connection = connection + + def __repr__(self): + return '<{c} job_id={i!r}>'.format(c=self.__class__.__name__, i=self.job_id) + + def _repr_html_(self): + data = self.describe() + currency = self.connection.capabilities().currency() + return render_component('job', data=data, parameters={'currency': currency}) + + @openeo_endpoint("GET /jobs/{job_id}") + def describe(self) -> dict: + """ + Get detailed metadata about a submitted batch job + (title, process graph, status, progress, ...). + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`describe_job`. + """ + return self.connection.get(f"/jobs/{self.job_id}", expected_status=200).json() + + describe_job = legacy_alias(describe, since="0.20.0", mode="soft") + + def status(self) -> str: + """ + Get the status of the batch job + + :return: batch job status, one of "created", "queued", "running", "canceled", "finished" or "error". + """ + return self.describe().get("status", "N/A") + + @openeo_endpoint("DELETE /jobs/{job_id}") + def delete(self): + """ + Delete this batch job. + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`delete_job`. + """ + self.connection.delete(f"/jobs/{self.job_id}", expected_status=204) + + delete_job = legacy_alias(delete, since="0.20.0", mode="soft") + + @openeo_endpoint("GET /jobs/{job_id}/estimate") + def estimate(self): + """Calculate time/cost estimate for a job.""" + data = self.connection.get( + f"/jobs/{self.job_id}/estimate", expected_status=200 + ).json() + currency = self.connection.capabilities().currency() + return VisualDict('job-estimate', data=data, parameters={'currency': currency}) + + estimate_job = legacy_alias(estimate, since="0.20.0", mode="soft") + + @openeo_endpoint("POST /jobs/{job_id}/results") + def start(self) -> BatchJob: + """ + Start this batch job. + + :return: Started batch job + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`start_job`. + """ + self.connection.post(f"/jobs/{self.job_id}/results", expected_status=202) + return self + + start_job = legacy_alias(start, since="0.20.0", mode="soft") + + @openeo_endpoint("DELETE /jobs/{job_id}/results") + def stop(self): + """ + Stop this batch job. + + .. versionadded:: 0.20.0 + This method was previously called :py:meth:`stop_job`. + """ + self.connection.delete(f"/jobs/{self.job_id}/results", expected_status=204) + + stop_job = legacy_alias(stop, since="0.20.0", mode="soft") + + def get_results_metadata_url(self, *, full: bool = False) -> str: + """Get results metadata URL""" + url = f"/jobs/{self.job_id}/results" + if full: + url = self.connection.build_url(url) + return url + + @deprecated("Use :py:meth:`~BatchJob.get_results` instead.", version="0.4.10") + def list_results(self) -> dict: + """Get batch job results metadata.""" + return self.get_results().get_metadata() + + def download_result(self, target: Union[str, Path] = None) -> Path: + """ + Download single job result to the target file path or into folder (current working dir by default). + + Fails if there are multiple result files. + + :param target: String or path where the file should be downloaded to. + """ + return self.get_results().download_file(target=target) + + @deprecated( + "Instead use :py:meth:`BatchJob.get_results` and the more flexible download functionality of :py:class:`JobResults`", + version="0.4.10") + def download_results(self, target: Union[str, Path] = None) -> Dict[Path, dict]: + """ + Download all job result files into given folder (current working dir by default). + + The names of the files are taken directly from the backend. + + :param target: String/path, folder where to put the result files. + :return: file_list: Dict containing the downloaded file path as value and asset metadata + """ + return self.get_result().download_files(target) + + @deprecated("Use :py:meth:`BatchJob.get_results` instead.", version="0.4.10") + def get_result(self): + return _Result(self) + + def get_results(self) -> JobResults: + """ + Get handle to batch job results for result metadata inspection or downloading resulting assets. + + .. versionadded:: 0.4.10 + """ + return JobResults(job=self) + + def logs( + self, offset: Optional[str] = None, level: Optional[Union[str, int]] = None + ) -> List[LogEntry]: + """Retrieve job logs. + + :param offset: The last identifier (property ``id`` of a LogEntry) the client has received. + + If provided, the back-ends only sends the entries that occurred after the specified identifier. + If not provided or empty, start with the first entry. + + Defaults to None. + + :param level: Minimum log level to retrieve. + + You can use either constants from Python's standard module ``logging`` + or their names (case-insensitive). + + For example: + ``logging.INFO``, ``"info"`` or ``"INFO"`` can all be used to show the messages + for level ``logging.INFO`` and above, i.e. also ``logging.WARNING`` and + ``logging.ERROR`` will be included. + + Default is to show all log levels, in other words ``logging.DEBUG``. + This is also the result when you explicitly pass log_level=None or log_level="". + + :return: A list containing the log entries for the batch job. + """ + url = f"/jobs/{self.job_id}/logs" + params = {} + if offset is not None: + params["offset"] = offset + if level is not None: + params["level"] = log_level_name(level) + response = self.connection.get(url, params=params, expected_status=200) + logs = response.json()["logs"] + + # Only filter logs when specified. + # We should still support client-side log_level filtering because not all backends + # support the minimum log level parameter. + if level is not None: + log_level = normalize_log_level(level) + logs = ( + log + for log in logs + if normalize_log_level(log.get("level")) >= log_level + ) + + entries = [LogEntry(log) for log in logs] + return VisualList("logs", data=entries) + + def run_synchronous( + self, outputfile: Union[str, Path, None] = None, + print=print, max_poll_interval=60, connection_retry_interval=30 + ) -> BatchJob: + """Start the job, wait for it to finish and download result""" + self.start_and_wait( + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + ) + # TODO #135 support multi file result sets too? + if outputfile is not None: + self.download_result(outputfile) + return self + + def start_and_wait( + self, print=print, max_poll_interval: int = 60, connection_retry_interval: int = 30, soft_error_max=10 + ) -> BatchJob: + """ + Start the batch job, poll its status and wait till it finishes (or fails) + + :param print: print/logging function to show progress/status + :param max_poll_interval: maximum number of seconds to sleep between status polls + :param connection_retry_interval: how long to wait when status poll failed due to connection issue + :param soft_error_max: maximum number of soft errors (e.g. temporary connection glitches) to allow + :return: + """ + # TODO rename `connection_retry_interval` to something more generic? + start_time = time.time() + + def elapsed() -> str: + return str(datetime.timedelta(seconds=time.time() - start_time)).rsplit(".")[0] + + def print_status(msg: str): + print("{t} Job {i!r}: {m}".format(t=elapsed(), i=self.job_id, m=msg)) + + # TODO: make `max_poll_interval`, `connection_retry_interval` class constants or instance properties? + print_status("send 'start'") + self.start() + + # TODO: also add `wait` method so you can track a job that already has started explicitly + # or just rename this method to `wait` and automatically do start if not started yet? + + # Start with fast polling. + poll_interval = min(5, max_poll_interval) + status = None + _soft_error_count = 0 + + def soft_error(message: str): + """Non breaking error (unless we had too much of them)""" + nonlocal _soft_error_count + _soft_error_count += 1 + if _soft_error_count > soft_error_max: + raise OpenEoClientException("Excessive soft errors") + print_status(message) + time.sleep(connection_retry_interval) + + while True: + # TODO: also allow a hard time limit on this infinite poll loop? + try: + job_info = self.describe() + except requests.ConnectionError as e: + soft_error("Connection error while polling job status: {e}".format(e=e)) + continue + except OpenEoApiPlainError as e: + if e.http_status_code in [502, 503]: + soft_error("Service availability error while polling job status: {e}".format(e=e)) + continue + else: + raise + + status = job_info.get("status", "N/A") + progress = '{p}%'.format(p=job_info["progress"]) if "progress" in job_info else "N/A" + print_status("{s} (progress {p})".format(s=status, p=progress)) + if status not in ('submitted', 'created', 'queued', 'running'): + break + + # Sleep for next poll (and adaptively make polling less frequent) + time.sleep(poll_interval) + poll_interval = min(1.25 * poll_interval, max_poll_interval) + + if status != "finished": + # TODO: allow to disable this printing logs (e.g. in non-interactive contexts)? + # TODO: render logs jupyter-aware in a notebook context? + print(f"Your batch job {self.job_id!r} failed. Error logs:") + print(self.logs(level=logging.ERROR)) + print( + f"Full logs can be inspected in an openEO (web) editor or with `connection.job({self.job_id!r}).logs()`." + ) + raise JobFailedException( + f"Batch job {self.job_id!r} didn't finish successfully. Status: {status} (after {elapsed()}).", + job=self, + ) + + return self + + +@deprecated(reason="Use :py:class:`BatchJob` instead", version="0.11.0") +class RESTJob(BatchJob): + """ + Legacy alias for :py:class:`BatchJob`. + """ + + +class ResultAsset: + """ + Result asset of a batch job (e.g. a GeoTIFF or JSON file) + + .. versionadded:: 0.4.10 + """ + + def __init__(self, job: BatchJob, name: str, href: str, metadata: dict): + self.job = job + + self.name = name + """Asset name as advertised by the backend.""" + + self.href = href + """Download URL of the asset.""" + + self.metadata = metadata + """Asset metadata provided by the backend, possibly containing keys "type" (for media type), "roles", "title", "description".""" + + def __repr__(self): + return "".format( + n=self.name, t=self.metadata.get("type", "unknown"), h=self.href + ) + + def download(self, target: Optional[Union[Path, str]] = None, chunk_size=None) -> Path: + """ + Download asset to given location + + :param target: download target path. Can be an existing folder + (in which case the filename advertised by backend will be used) + or full file name. By default, the working directory will be used. + """ + target = Path(target or Path.cwd()) + if target.is_dir(): + target = target / self.name + ensure_dir(target.parent) + logger.info("Downloading Job result asset {n!r} from {h!s} to {t!s}".format(n=self.name, h=self.href, t=target)) + with target.open("wb") as f: + response = self._get_response(stream=True) + for block in response.iter_content(chunk_size=chunk_size): + f.write(block) + return target + + def _get_response(self, stream=True) -> requests.Response: + return self.job.connection.get(self.href, stream=stream) + + def load_json(self) -> dict: + """Load asset in memory and parse as JSON.""" + if not (self.name.lower().endswith(".json") or self.metadata.get("type") == "application/json"): + logger.warning("Asset might not be JSON") + return self._get_response().json() + + def load_bytes(self) -> bytes: + """Load asset in memory as raw bytes.""" + return self._get_response().content + + # TODO: more `load` methods e.g.: load GTiff asset directly as numpy array + + +class MultipleAssetException(OpenEoClientException): + pass + + +class JobResults: + """ + Results of a batch job: listing of one or more output files (assets) + and some metadata. + + .. versionadded:: 0.4.10 + """ + + def __init__(self, job: BatchJob): + self._job = job + self._results = None + + def __repr__(self): + return "".format(j=self._job.job_id) + + def _repr_html_(self): + try: + response = self.get_metadata() + return render_component("batch-job-result", data = response) + except OpenEoApiError as error: + return render_error(error) + + def get_metadata(self, force=False) -> dict: + """Get batch job results metadata (parsed JSON)""" + if self._results is None or force: + self._results = self._job.connection.get( + self._job.get_results_metadata_url(), expected_status=200 + ).json() + return self._results + + # TODO: provide methods for `stac_version`, `id`, `geometry`, `properties`, `links`, ...? + + def get_assets(self) -> List[ResultAsset]: + """ + Get all assets from the job results. + """ + # TODO: add arguments to filter on metadata, e.g. to only get assets of type "image/tiff" + metadata = self.get_metadata() + # API 1.0 style: dictionary mapping filenames to metadata dict (with at least a "href" field) + assets = metadata.get("assets", {}) + if not assets: + logger.warning("No assets found in job result metadata.") + return [ + ResultAsset(job=self._job, name=name, href=asset["href"], metadata=asset) + for name, asset in assets.items() + ] + + def get_asset(self, name: str = None) -> ResultAsset: + """ + Get single asset by name or without name if there is only one. + """ + # TODO: also support getting a single asset by type or role? + assets = self.get_assets() + if len(assets) == 0: + raise OpenEoClientException("No assets in result.") + if name is None: + if len(assets) == 1: + return assets[0] + else: + raise MultipleAssetException("Multiple result assets for job {j}: {a}".format( + j=self._job.job_id, a=[a.name for a in assets] + )) + else: + try: + return next(a for a in assets if a.name == name) + except StopIteration: + raise OpenEoClientException( + "No asset {n!r} in: {a}".format(n=name, a=[a.name for a in assets]) + ) + + def download_file(self, target: Union[Path, str] = None, name: str = None) -> Path: + """ + Download single asset. Can be used when there is only one asset in the + :py:class:`JobResults`, or when the desired asset name is given explicitly. + + :param target: path to download to. Can be an existing directory + (in which case the filename advertised by backend will be used) + or full file name. By default, the working directory will be used. + :param name: asset name to download (not required when there is only one asset) + :return: path of downloaded asset + """ + try: + return self.get_asset(name=name).download(target=target) + except MultipleAssetException: + raise OpenEoClientException( + "Can not use `download_file` with multiple assets. Use `download_files` instead.") + + def download_files(self, target: Union[Path, str] = None, include_stac_metadata: bool = True) -> List[Path]: + """ + Download all assets to given folder. + + :param target: path to folder to download to (must be a folder if it already exists) + :param include_stac_metadata: whether to download the job result metadata as a STAC (JSON) file. + :return: list of paths to the downloaded assets. + """ + target = Path(target or Path.cwd()) + if target.exists() and not target.is_dir(): + raise OpenEoClientException(f"Target argument {target} exists but isn't a folder.") + ensure_dir(target) + + downloaded = [a.download(target) for a in self.get_assets()] + + if include_stac_metadata: + # TODO #184: convention for metadata file name? + metadata_file = target / "job-results.json" + # TODO #184: rewrite references to locally downloaded assets? + metadata_file.write_text(json.dumps(self.get_metadata())) + downloaded.append(metadata_file) + + return downloaded + + +@deprecated(reason="Use :py:class:`JobResults` instead", version="0.4.10") +class _Result: + """ + Wrapper around `JobResults` to adapt old deprecated "Result" API. + + .. deprecated:: 0.4.10 + """ + + # TODO: deprecated: remove this + + def __init__(self, job): + self.results = JobResults(job=job) + + def download_file(self, target: Union[str, Path] = None) -> Path: + return self.results.download_file(target=target) + + def download_files(self, target: Union[str, Path] = None) -> Dict[Path, dict]: + target = Path(target or Path.cwd()) + if target.exists() and not target.is_dir(): + raise OpenEoClientException(f"Target argument {target} exists but isn't a folder.") + return {a.download(target): a.metadata for a in self.results.get_assets()} + + def load_json(self) -> dict: + return self.results.get_asset().load_json() + + def load_bytes(self) -> bytes: + return self.results.get_asset().load_bytes() diff --git a/lib/openeo/rest/mlmodel.py b/lib/openeo/rest/mlmodel.py new file mode 100644 index 000000000..b2e012ab8 --- /dev/null +++ b/lib/openeo/rest/mlmodel.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +import logging +import pathlib +import typing +from typing import Optional, Union + +from openeo.internal.documentation import openeo_process +from openeo.internal.graph_building import PGNode +from openeo.rest._datacube import _ProcessGraphAbstraction +from openeo.rest.job import BatchJob + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + from openeo import Connection + +_log = logging.getLogger(__name__) + + +class MlModel(_ProcessGraphAbstraction): + """ + A machine learning model. + + It is the result of a training procedure, e.g. output of a ``fit_...`` process, + and can be used for prediction (classification or regression) with the corresponding ``predict_...`` process. + + .. versionadded:: 0.10.0 + """ + + def __init__(self, graph: PGNode, connection: Connection): + super().__init__(pgnode=graph, connection=connection) + + def save_ml_model(self, options: Optional[dict] = None): + """ + Saves a machine learning model as part of a batch job. + + :param options: Additional parameters to create the file(s). + """ + pgnode = PGNode( + process_id="save_ml_model", + arguments={"data": self, "options": options or {}} + ) + return MlModel(graph=pgnode, connection=self._connection) + + @staticmethod + @openeo_process + def load_ml_model(connection: Connection, id: Union[str, BatchJob]) -> MlModel: + """ + Loads a machine learning model from a STAC Item. + + :param connection: connection object + :param id: STAC item reference, as URL, batch job (id) or user-uploaded file + :return: + + .. versionadded:: 0.10.0 + """ + if isinstance(id, BatchJob): + id = id.job_id + return MlModel(graph=PGNode(process_id="load_ml_model", id=id), connection=connection) + + def execute_batch( + self, + outputfile: Union[str, pathlib.Path], + print=print, max_poll_interval=60, connection_retry_interval=30, + job_options=None, + ) -> BatchJob: + """ + Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. + This method is mostly recommended if the batch job is expected to run in a reasonable amount of time. + + For very long running jobs, you probably do not want to keep the client running. + + :param job_options: + :param outputfile: The path of a file to which a result can be written + :param out_format: (optional) Format of the job result. + :param format_options: String Parameters for the job result format + """ + job = self.create_job(job_options=job_options) + return job.run_synchronous( + # TODO #135 support multi file result sets too + outputfile=outputfile, + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + ) + + def create_job( + self, + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + job_options: Optional[dict] = None, + ) -> BatchJob: + """ + Sends a job to the backend and returns a ClientJob instance. + + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param job_options: A dictionary containing (custom) job options + :param format_options: String Parameters for the job result format + :return: Created job. + """ + # TODO: centralize `create_job` for `DataCube`, `VectorCube`, `MlModel`, ... + pg = self + if pg.result_node().process_id not in {"save_ml_model"}: + _log.warning("Process graph has no final `save_ml_model`. Adding it automatically.") + pg = pg.save_ml_model() + return self._connection.create_job( + process_graph=pg.flat_graph(), + title=title, + description=description, + plan=plan, + budget=budget, + additional=job_options, + ) diff --git a/lib/openeo/rest/rest_capabilities.py b/lib/openeo/rest/rest_capabilities.py new file mode 100644 index 000000000..00922c261 --- /dev/null +++ b/lib/openeo/rest/rest_capabilities.py @@ -0,0 +1,54 @@ +from typing import List, Optional + +from openeo.capabilities import Capabilities +from openeo.internal.jupyter import render_component +from openeo.util import deep_get + + +class RESTCapabilities(Capabilities): + """Represents REST capabilities of a connection / back end.""" + + def __init__(self, data: dict, url: str = None): + super(RESTCapabilities, self).__init__(data) + self.capabilities = data + self.url = url + + def get(self, key: str, default=None): + return self.capabilities.get(key, default) + + def deep_get(self, *keys, default=None): + return deep_get(self.capabilities, *keys, default=default) + + def api_version(self) -> str: + """ Get openEO version.""" + if 'api_version' in self.capabilities: + return self.capabilities.get('api_version') + else: + # Legacy/deprecated + return self.capabilities.get('version') + + def list_features(self): + """ List all supported features / endpoints.""" + return self.capabilities.get('endpoints') + + def has_features(self, method_name): + """ Check whether a feature / endpoint is supported.""" + # Field: endpoints > ... TODO + pass + + def supports_endpoint(self, path: str, method="GET"): + return any( + endpoint.get("path") == path and method.upper() in endpoint.get("methods", []) + for endpoint in self.capabilities.get("endpoints", []) + ) + + def currency(self) -> Optional[str]: + """Get default billing currency.""" + return self.deep_get("billing", "currency", default=None) + + def list_plans(self) -> List[dict]: + """List all billing plans.""" + return self.deep_get("billing", "plans", default=[]) + + def _repr_html_(self): + return render_component("capabilities", data = self.capabilities, parameters = {"url": self.url}) diff --git a/lib/openeo/rest/service.py b/lib/openeo/rest/service.py new file mode 100644 index 000000000..a12383695 --- /dev/null +++ b/lib/openeo/rest/service.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import typing +from typing import List, Optional, Union + +from openeo.api.logs import LogEntry, log_level_name +from openeo.internal.jupyter import VisualDict, VisualList + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + from openeo.rest.connection import Connection + + +class Service: + """Represents a secondary web service in openeo.""" + + def __init__(self, service_id: str, connection: Connection): + # Unique identifier of the secondary web service (string) + self.service_id = service_id + self.connection = connection + + def __repr__(self): + return '<{c} service_id={i!r}>'.format(c=self.__class__.__name__, i=self.service_id) + + def _repr_html_(self): + data = self.describe_service() + currency = self.connection.capabilities().currency() + return VisualDict('service', data = data, parameters = {'currency': currency}) + + def describe_service(self): + """ Get all information about a secondary web service.""" + # GET /services/{service_id} + return self.connection.get("/services/{}".format(self.service_id), expected_status=200).json() + + def update_service(self, process_graph=None, title=None, description=None, enabled=None, configuration=None, plan=None, budget=None, additional=None): + """ Update a secondary web service.""" + # PATCH /services/{service_id} + raise NotImplementedError + + def delete_service(self): + """ Delete a secondary web service.""" + # DELETE /services/{service_id} + self.connection.delete("/services/{}".format(self.service_id), expected_status=204) + + def logs( + self, offset: Optional[str] = None, level: Optional[Union[str, int]] = None + ) -> List[LogEntry]: + """Retrieve service logs.""" + url = f"/service/{self.service_id}/logs" + params = {} + if offset is not None: + params["offset"] = offset + if level is not None: + params["level"] = log_level_name(level) + resp = self.connection.get(url, params=params, expected_status=200) + logs = resp.json()["logs"] + entries = [LogEntry(log) for log in logs] + return VisualList("logs", data=entries) diff --git a/lib/openeo/rest/udp.py b/lib/openeo/rest/udp.py new file mode 100644 index 000000000..5cac35347 --- /dev/null +++ b/lib/openeo/rest/udp.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import typing +from typing import List, Optional, Union + +from openeo.api.process import Parameter +from openeo.internal.graph_building import as_flat_graph, FlatGraphableMixin +from openeo.internal.jupyter import render_component +from openeo.internal.processes.builder import ProcessBuilderBase +from openeo.internal.warnings import deprecated +from openeo.util import dict_no_none + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + from openeo.rest.connection import Connection + + +def build_process_dict( + process_graph: Union[dict, FlatGraphableMixin], + process_id: Optional[str] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + parameters: Optional[List[Union[Parameter, dict]]] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, +) -> dict: + """ + Build a dictionary describing a process with metadaa (`process_graph`, `parameters`, `description`, ...) + + :param process_graph: dict or builder representing a process graph + :param process_id: identifier of the process + :param summary: short summary of what the process does + :param description: detailed description + :param parameters: list of process parameters (which have name, schema, default value, ...) + :param returns: description and schema of what the process returns + :param categories: list of categories + :param examples: list of examples, may be used for unit tests + :param links: list of links related to the process + :return: dictionary in openEO "process graph with metadata" format + """ + process = dict_no_none( + process_graph=as_flat_graph(process_graph), + id=process_id, + summary=summary, + description=description, + returns=returns, + categories=categories, + examples=examples, + links=links + ) + if parameters is not None: + process["parameters"] = [ + (p if isinstance(p, Parameter) else Parameter(**p)).to_dict() + for p in parameters + ] + return process + + +class RESTUserDefinedProcess: + """ + Wrapper for a user-defined process stored (or to be stored) on an openEO back-end + """ + + def __init__(self, user_defined_process_id: str, connection: Connection): + self.user_defined_process_id = user_defined_process_id + self._connection = connection + self._connection.assert_user_defined_process_support() + + def _repr_html_(self): + process = self.describe() + return render_component('process', data=process, parameters = {'show-graph': True, 'provide-download': False}) + + def store( + self, + process_graph: Union[dict, FlatGraphableMixin], + parameters: Optional[List[Union[Parameter, dict]]] = None, + public: bool = False, + summary: Optional[str] = None, + description: Optional[str] = None, + returns: Optional[dict] = None, + categories: Optional[List[str]] = None, + examples: Optional[List[dict]] = None, + links: Optional[List[dict]] = None, + ): + """Store a process graph and its metadata on the backend as a user-defined process""" + process = build_process_dict( + process_graph=process_graph, parameters=parameters, + summary=summary, description=description, returns=returns, + categories=categories, examples=examples, links=links, + ) + + # TODO: this "public" flag is not standardized yet EP-3609, https://github.com/Open-EO/openeo-api/issues/310 + process["public"] = public + + self._connection._preflight_validation(pg_with_metadata=process) + self._connection.put( + path="/process_graphs/{}".format(self.user_defined_process_id), json=process, expected_status=200 + ) + + @deprecated( + "Use `store` instead. Method `update` is misleading: OpenEO API does not provide (partial) updates" + " of user-defined processes, only fully overwriting 'store' operations.", + version="0.4.11") + def update( + self, process_graph: Union[dict, ProcessBuilderBase], parameters: List[Union[Parameter, dict]] = None, + public: bool = False, summary: str = None, description: str = None + ): + self.store(process_graph=process_graph, parameters=parameters, public=public, summary=summary, + description=description) + + def describe(self) -> dict: + """Get metadata of this user-defined process.""" + # TODO: parse the "parameters" to Parameter objects? + return self._connection.get(path="/process_graphs/{}".format(self.user_defined_process_id)).json() + + def delete(self) -> None: + """Remove user-defined process from back-end""" + self._connection.delete(path="/process_graphs/{}".format(self.user_defined_process_id), expected_status=204) + + def validate(self) -> None: + raise NotImplementedError diff --git a/lib/openeo/rest/userfile.py b/lib/openeo/rest/userfile.py new file mode 100644 index 000000000..0732c671c --- /dev/null +++ b/lib/openeo/rest/userfile.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +import typing +from pathlib import Path, PurePosixPath +from typing import Any, Dict, Optional, Union + +from openeo.util import ensure_dir + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + from openeo.rest.connection import Connection + + +class UserFile: + """ + Handle to a (user-uploaded) file in the user workspace on a openEO back-end. + """ + + def __init__( + self, + path: Union[str, PurePosixPath, None], + *, + connection: Connection, + metadata: Optional[dict] = None, + ): + if path: + pass + elif metadata and metadata.get("path"): + path = metadata.get("path") + else: + raise ValueError( + "File path should be specified through `path` or `metadata` argument." + ) + + self.path = PurePosixPath(path) + self.metadata = metadata or {"path": path} + self.connection = connection + + @classmethod + def from_metadata(cls, metadata: dict, connection: Connection) -> UserFile: + """Build :py:class:`UserFile` from a workspace file metadata dictionary.""" + return cls(path=None, connection=connection, metadata=metadata) + + def __repr__(self): + return "<{c} file={i!r}>".format(c=self.__class__.__name__, i=self.path) + + def _get_endpoint(self) -> str: + return f"/files/{self.path!s}" + + def download(self, target: Union[Path, str] = None) -> Path: + """ + Downloads a user-uploaded file from the user workspace on the back-end + locally to the given location. + + :param target: local download target path. Can be an existing folder + (in which case the file name advertised by backend will be used) + or full file name. By default, the working directory will be used. + """ + response = self.connection.get( + self._get_endpoint(), expected_status=200, stream=True + ) + + target = Path(target or Path.cwd()) + if target.is_dir(): + target = target / self.path.name + ensure_dir(target.parent) + + with target.open(mode="wb") as f: + for chunk in response.iter_content(chunk_size=None): + f.write(chunk) + + return target + + def upload(self, source: Union[Path, str]) -> UserFile: + """ + Uploads a local file to the path corresponding to this :py:class:`UserFile` in the user workspace + and returns new :py:class:`UserFile` of newly uploaded file. + + .. tip:: + Usually you'll just need + :py:meth:`Connection.upload_file() ` + instead of this :py:class:`UserFile` method. + + If the file exists in the user workspace it will be replaced. + + :param source: A path to a file on the local file system to upload. + :return: new :py:class:`UserFile` instance of the newly uploaded file + """ + return self.connection.upload_file(source, target=self.path) + + def delete(self): + """Delete the user-uploaded file from the user workspace on the back-end.""" + self.connection.delete(self._get_endpoint(), expected_status=204) + + def to_dict(self) -> Dict[str, Any]: + """Returns the provided metadata as dict.""" + # This is used in internal/jupyter.py to detect and get the original metadata. + # TODO: make this more explicit with an internal API? + return self.metadata diff --git a/lib/openeo/rest/vectorcube.py b/lib/openeo/rest/vectorcube.py new file mode 100644 index 000000000..6f4e7b0f5 --- /dev/null +++ b/lib/openeo/rest/vectorcube.py @@ -0,0 +1,552 @@ +from __future__ import annotations + +import json +import pathlib +import typing +from typing import Callable, List, Optional, Tuple, Union + +import shapely.geometry.base + +from openeo.api.process import Parameter +from openeo.internal.documentation import openeo_process +from openeo.internal.graph_building import PGNode +from openeo.internal.warnings import legacy_alias +from openeo.metadata import CollectionMetadata, Dimension +from openeo.rest._datacube import ( + THIS, + UDF, + _ProcessGraphAbstraction, + build_child_callback, +) +from openeo.rest.job import BatchJob +from openeo.rest.mlmodel import MlModel +from openeo.util import InvalidBBoxException, dict_no_none, guess_format, to_bbox_dict + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + from openeo import Connection + + +class VectorCube(_ProcessGraphAbstraction): + """ + A Vector Cube, or 'Vector Collection' is a data structure containing 'Features': + https://www.w3.org/TR/sdw-bp/#dfn-feature + + The features in this cube are restricted to have a geometry. Geometries can be points, lines, polygons etcetera. + A geometry is specified in a 'coordinate reference system'. https://www.w3.org/TR/sdw-bp/#dfn-coordinate-reference-system-(crs) + """ + + def __init__(self, graph: PGNode, connection: Connection, metadata: Optional[CollectionMetadata] = None): + super().__init__(pgnode=graph, connection=connection) + self.metadata = metadata + + @classmethod + def _build_metadata(cls, add_properties: bool = False) -> CollectionMetadata: + """Helper to build a (minimal) `CollectionMetadata` object.""" + # Vector cubes have at least a "geometry" dimension + dimensions = [Dimension(name="geometry", type="geometry")] + if add_properties: + dimensions.append(Dimension(name="properties", type="other")) + # TODO #464: use a more generic metadata container than "collection" metadata + return CollectionMetadata(metadata={}, dimensions=dimensions) + + def process( + self, + process_id: str, + arguments: dict = None, + metadata: Optional[CollectionMetadata] = None, + namespace: Optional[str] = None, + **kwargs, + ) -> VectorCube: + """ + Generic helper to create a new DataCube by applying a process. + + :param process_id: process id of the process. + :param args: argument dictionary for the process. + :return: new VectorCube instance + """ + pg = self._build_pgnode(process_id=process_id, arguments=arguments, namespace=namespace, **kwargs) + return VectorCube(graph=pg, connection=self._connection, metadata=metadata or self.metadata) + + @classmethod + @openeo_process + def load_geojson( + cls, + connection: Connection, + data: Union[dict, str, pathlib.Path, shapely.geometry.base.BaseGeometry, Parameter], + properties: Optional[List[str]] = None, + ) -> VectorCube: + """ + Converts GeoJSON data as defined by RFC 7946 into a vector data cube. + + :param connection: the connection to use to connect with the openEO back-end. + :param data: the geometry to load. One of: + + - GeoJSON-style data structure: e.g. a dictionary with ``"type": "Polygon"`` and ``"coordinates"`` fields + - a path to a local GeoJSON file + - a GeoJSON string + - a shapely geometry object + + :param properties: A list of properties from the GeoJSON file to construct an additional dimension from. + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + # TODO: unify with `DataCube._get_geometry_argument` + # TODO #457 also support client side fetching of GeoJSON from URL? + if isinstance(data, str) and data.strip().startswith("{"): + # Assume JSON dump + geometry = json.loads(data) + elif isinstance(data, (str, pathlib.Path)): + # Assume local file + with pathlib.Path(data).open(mode="r", encoding="utf-8") as f: + geometry = json.load(f) + assert isinstance(geometry, dict) + elif isinstance(data, shapely.geometry.base.BaseGeometry): + geometry = shapely.geometry.mapping(data) + elif isinstance(data, Parameter): + geometry = data + elif isinstance(data, dict): + geometry = data + else: + raise ValueError(data) + # TODO #457 client side verification of GeoJSON construct: valid type, valid structure, presence of CRS, ...? + + pg = PGNode(process_id="load_geojson", data=geometry, properties=properties or []) + # TODO #457 always a "properties" dimension? https://github.com/Open-EO/openeo-processes/issues/448 + metadata = cls._build_metadata(add_properties=True) + return cls(graph=pg, connection=connection, metadata=metadata) + + @classmethod + @openeo_process + def load_url(cls, connection: Connection, url: str, format: str, options: Optional[dict] = None) -> VectorCube: + """ + Loads a file from a URL + + :param connection: the connection to use to connect with the openEO back-end. + :param url: The URL to read from. Authentication details such as API keys or tokens may need to be included in the URL. + :param format: The file format to use when loading the data. + :param options: The file format parameters to use when reading the data. + Must correspond to the parameters that the server reports as supported parameters for the chosen ``format`` + :return: new VectorCube instance + + .. warning:: EXPERIMENTAL: this process is experimental with the potential for major things to change. + + .. versionadded:: 0.22.0 + """ + pg = PGNode(process_id="load_url", arguments=dict_no_none(url=url, format=format, options=options)) + # TODO #457 always a "properties" dimension? https://github.com/Open-EO/openeo-processes/issues/448 + metadata = cls._build_metadata(add_properties=True) + return cls(graph=pg, connection=connection, metadata=metadata) + + @openeo_process + def run_udf( + self, + udf: Union[str, UDF], + runtime: Optional[str] = None, + version: Optional[str] = None, + context: Optional[dict] = None, + ) -> VectorCube: + """ + Run a UDF on the vector cube. + + It is recommended to provide the UDF just as :py:class:`UDF ` instance. + (the other arguments could be used to override UDF parameters if necessary). + + :param udf: UDF code as a string or :py:class:`UDF ` instance + :param runtime: UDF runtime + :param version: UDF version + :param context: UDF context + + .. warning:: EXPERIMENTAL: not generally supported, API subject to change. + + .. versionadded:: 0.10.0 + + .. versionchanged:: 0.16.0 + Added support to pass self-contained :py:class:`UDF ` instance. + """ + if isinstance(udf, UDF): + # `UDF` instance is preferred usage pattern, but allow overriding. + version = version or udf.version + context = context or udf.context + runtime = runtime or udf.get_runtime(connection=self.connection) + udf = udf.code + else: + if not runtime: + raise ValueError("Argument `runtime` must be specified") + return self.process( + process_id="run_udf", + data=self, udf=udf, runtime=runtime, + arguments=dict_no_none({"version": version, "context": context}), + ) + + @openeo_process + def save_result(self, format: Union[str, None] = "GeoJSON", options: dict = None): + # TODO #401: guard against duplicate save_result nodes? + return self.process( + process_id="save_result", + arguments={ + "data": self, + "format": format or "GeoJSON", + "options": options or {}, + }, + ) + + def _ensure_save_result( + self, + format: Optional[str] = None, + options: Optional[dict] = None, + ) -> VectorCube: + """ + Make sure there is a (final) `save_result` node in the process graph. + If there is already one: check if it is consistent with the given format/options (if any) + and add a new one otherwise. + + :param format: (optional) desired `save_result` file format + :param options: (optional) desired `save_result` file format parameters + :return: + """ + # TODO #401 Unify with DataCube._ensure_save_result and move to generic data cube parent class + result_node = self.result_node() + if result_node.process_id == "save_result": + # There is already a `save_result` node: + # check if it is consistent with given format/options (if any) + args = result_node.arguments + if format is not None and format.lower() != args["format"].lower(): + raise ValueError(f"Existing `save_result` node with different format {args['format']!r} != {format!r}") + if options is not None and options != args["options"]: + raise ValueError( + f"Existing `save_result` node with different options {args['options']!r} != {options!r}" + ) + cube = self + else: + # No `save_result` node yet: automatically add it. + cube = self.save_result(format=format or "GeoJSON", options=options) + return cube + + def execute(self, *, validate: Optional[bool] = None) -> dict: + """Executes the process graph.""" + return self._connection.execute(self.flat_graph(), validate=validate) + + def download( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + format: Optional[str] = None, + options: Optional[dict] = None, + *, + validate: Optional[bool] = None, + ) -> Union[None, bytes]: + """ + Execute synchronously and download the vector cube. + + The result will be stored to the output path, when specified. + If no output path (or ``None``) is given, the raw download content will be returned as ``bytes`` object. + + :param outputfile: (optional) output file to store the result to + :param format: (optional) output format to use. + :param options: (optional) additional output format options. + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + .. versionchanged:: 0.21.0 + When not specified explicitly, output format is guessed from output file extension. + + """ + # TODO #401 make outputfile optional (See DataCube.download) + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + if format is None and outputfile: + format = guess_format(outputfile) + cube = self._ensure_save_result(format=format, options=options) + return self._connection.download(cube.flat_graph(), outputfile=outputfile, validate=validate) + + def execute_batch( + self, + outputfile: Optional[Union[str, pathlib.Path]] = None, + out_format: Optional[str] = None, + *, + print=print, + max_poll_interval: float = 60, + connection_retry_interval: float = 30, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + # TODO: avoid using kwargs as format options + **format_options, + ) -> BatchJob: + """ + Evaluate the process graph by creating a batch job, and retrieving the results when it is finished. + This method is mostly recommended if the batch job is expected to run in a reasonable amount of time. + + For very long running jobs, you probably do not want to keep the client running. + + :param job_options: + :param outputfile: The path of a file to which a result can be written + :param out_format: (optional) output format to use. + :param format_options: (optional) additional output format options + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + .. versionchanged:: 0.21.0 + When not specified explicitly, output format is guessed from output file extension. + """ + if out_format is None and outputfile: + # TODO #401/#449 don't guess/override format if there is already a save_result with format? + out_format = guess_format(outputfile) + + job = self.create_job(out_format, job_options=job_options, validate=validate, **format_options) + return job.run_synchronous( + # TODO #135 support multi file result sets too + outputfile=outputfile, + print=print, max_poll_interval=max_poll_interval, connection_retry_interval=connection_retry_interval + ) + + def create_job( + self, + out_format: Optional[str] = None, + *, + title: Optional[str] = None, + description: Optional[str] = None, + plan: Optional[str] = None, + budget: Optional[float] = None, + job_options: Optional[dict] = None, + validate: Optional[bool] = None, + **format_options, + ) -> BatchJob: + """ + Sends a job to the backend and returns a ClientJob instance. + + :param out_format: String Format of the job result. + :param title: job title + :param description: job description + :param plan: billing plan + :param budget: maximum cost the request is allowed to produce + :param job_options: A dictionary containing (custom) job options + :param format_options: String Parameters for the job result format + :param validate: Optional toggle to enable/prevent validation of the process graphs before execution + (overruling the connection's ``auto_validate`` setting). + + :return: Created job. + """ + # TODO: avoid using all kwargs as format_options + # TODO: centralize `create_job` for `DataCube`, `VectorCube`, `MlModel`, ... + cube = self._ensure_save_result(format=out_format, options=format_options or None) + return self._connection.create_job( + process_graph=cube.flat_graph(), + title=title, + description=description, + plan=plan, + budget=budget, + additional=job_options, + validate=validate, + ) + + send_job = legacy_alias(create_job, name="send_job", since="0.10.0") + + @openeo_process + def filter_bands(self, bands: List[str]) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + return self.process( + process_id="filter_bands", + arguments={"data": THIS, "bands": bands}, + ) + + @openeo_process + def filter_bbox( + self, + *, + west: Optional[float] = None, + south: Optional[float] = None, + east: Optional[float] = None, + north: Optional[float] = None, + extent: Optional[Union[dict, List[float], Tuple[float, float, float, float], Parameter]] = None, + crs: Optional[int] = None, + ) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + if any(c is not None for c in [west, south, east, north]): + if extent is not None: + raise InvalidBBoxException("Don't specify both west/south/east/north and extent") + extent = dict_no_none(west=west, south=south, east=east, north=north) + + if isinstance(extent, Parameter): + pass + else: + extent = to_bbox_dict(extent, crs=crs) + return self.process( + process_id="filter_bbox", + arguments={"data": THIS, "extent": extent}, + ) + + @openeo_process + def filter_labels( + self, condition: Union[PGNode, Callable], dimension: str, context: Optional[dict] = None + ) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + condition = build_child_callback(condition, parent_parameters=["value"]) + return self.process( + process_id="filter_labels", + arguments=dict_no_none(data=THIS, condition=condition, dimension=dimension, context=context), + ) + + @openeo_process + def filter_vector( + self, geometries: Union["VectorCube", shapely.geometry.base.BaseGeometry, dict], relation: str = "intersects" + ) -> VectorCube: + """ + .. versionadded:: 0.22.0 + """ + # TODO #459 docs + if not isinstance(geometries, (VectorCube, Parameter)): + geometries = self.load_geojson(connection=self.connection, data=geometries) + return self.process( + process_id="filter_vector", + arguments={"data": THIS, "geometries": geometries, "relation": relation}, + ) + + @openeo_process + def fit_class_random_forest( + self, + # TODO #279 #293: target type should be `VectorCube` (with adapters for GeoJSON FeatureCollection, GeoPandas, ...) + target: dict, + # TODO #293 max_variables officially has no default + max_variables: Optional[int] = None, + num_trees: int = 100, + seed: Optional[int] = None, + ) -> MlModel: + """ + Executes the fit of a random forest classification based on the user input of target and predictors. + The Random Forest classification model is based on the approach by Breiman (2001). + + .. warning:: EXPERIMENTAL: not generally supported, API subject to change. + + :param target: The training sites for the classification model as a vector data cube. This is associated with the target + variable for the Random Forest model. The geometry has to be associated with a value to predict (e.g. fractional + forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. Default value is `null`, which corresponds to the + number of predictors divided by 3. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. + + .. versionadded:: 0.16.0 + Originally added in version 0.10.0 as :py:class:`DataCube ` method, + but moved to :py:class:`VectorCube` in version 0.16.0. + """ + pgnode = PGNode( + process_id="fit_class_random_forest", + arguments=dict_no_none( + predictors=self, + # TODO #279 strictly per-spec, target should be a `vector-cube`, but due to lack of proper support we are limited to inline GeoJSON for now + target=target, + max_variables=max_variables, + num_trees=num_trees, + seed=seed, + ), + ) + model = MlModel(graph=pgnode, connection=self._connection) + return model + + @openeo_process + def fit_regr_random_forest( + self, + # TODO #279 #293: target type should be `VectorCube` (with adapters for GeoJSON FeatureCollection, GeoPandas, ...) + target: dict, + # TODO #293 max_variables officially has no default + max_variables: Optional[int] = None, + num_trees: int = 100, + seed: Optional[int] = None, + ) -> MlModel: + """ + Executes the fit of a random forest regression based on training data. + The Random Forest regression model is based on the approach by Breiman (2001). + + .. warning:: EXPERIMENTAL: not generally supported, API subject to change. + + :param target: The training sites for the regression model as a vector data cube. + This is associated with the target variable for the Random Forest model. + The geometry has to associated with a value to predict (e.g. fractional forest canopy cover). + :param max_variables: Specifies how many split variables will be used at a node. Default value is `null`, which corresponds to the + number of predictors divided by 3. + :param num_trees: The number of trees build within the Random Forest classification. + :param seed: A randomization seed to use for the random sampling in training. + + .. versionadded:: 0.16.0 + Originally added in version 0.10.0 as :py:class:`DataCube ` method, + but moved to :py:class:`VectorCube` in version 0.16.0. + """ + # TODO #279 #293: `fit_class_random_forest` should be defined on VectorCube instead of DataCube + pgnode = PGNode( + process_id="fit_regr_random_forest", + arguments=dict_no_none( + predictors=self, + # TODO #279 strictly per-spec, target should be a `vector-cube`, but due to lack of proper support we are limited to inline GeoJSON for now + target=target, + max_variables=max_variables, + num_trees=num_trees, + seed=seed, + ), + ) + model = MlModel(graph=pgnode, connection=self._connection) + return model + + @openeo_process + def apply_dimension( + self, + process: Union[str, typing.Callable, UDF, PGNode], + dimension: str, + target_dimension: Optional[str] = None, + context: Optional[dict] = None, + ) -> VectorCube: + """ + Applies a process to all values along a dimension of a data cube. + For example, if the temporal dimension is specified the process will work on the values of a time series. + + The process to apply is specified by providing a callback function in the `process` argument. + + :param process: the "child callback": + the name of a single process, + or a callback function as discussed in :ref:`callbackfunctions`, + or a :py:class:`UDF ` instance. + + The callback should correspond to a process that + receives an array of numerical values + and returns an array of numerical values. + For example: + + - ``"sort"`` (string) + - :py:func:`sort ` (:ref:`predefined openEO process function `) + - ``lambda data: data.concat([42, -3])`` (function or lambda) + + + :param dimension: The name of the source dimension to apply the process on. Fails with a DimensionNotAvailable error if the specified dimension does not exist. + :param target_dimension: The name of the target dimension or null (the default) to use the source dimension + specified in the parameter dimension. By 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. + :param context: Additional data to be passed to the process. + + :return: A datacube with the UDF applied to the given dimension. + :raises: DimensionNotAvailable + + .. versionadded:: 0.22.0 + """ + process = build_child_callback( + process=process, parent_parameters=["data", "context"], connection=self.connection + ) + arguments = dict_no_none( + { + "data": THIS, + "process": process, + "dimension": dimension, + "target_dimension": target_dimension, + "context": context, + } + ) + return self.process(process_id="apply_dimension", arguments=arguments) diff --git a/lib/openeo/udf/__init__.py b/lib/openeo/udf/__init__.py new file mode 100644 index 000000000..387b8bc3d --- /dev/null +++ b/lib/openeo/udf/__init__.py @@ -0,0 +1,13 @@ +from openeo import BaseOpenEoException + + +class OpenEoUdfException(BaseOpenEoException): + pass + + +from openeo.udf.debug import inspect +from openeo.udf.feature_collection import FeatureCollection +from openeo.udf.run_code import execute_local_udf, run_udf_code +from openeo.udf.structured_data import StructuredData +from openeo.udf.udf_data import UdfData +from openeo.udf.xarraydatacube import XarrayDataCube diff --git a/lib/openeo/udf/debug.py b/lib/openeo/udf/debug.py new file mode 100644 index 000000000..3cb408494 --- /dev/null +++ b/lib/openeo/udf/debug.py @@ -0,0 +1,30 @@ +""" +Debug utilities for UDFs +""" +import logging +import os +import sys + +_log = logging.getLogger(__name__) +_user_log = logging.getLogger(os.environ.get("OPENEO_UDF_USER_LOGGER", f"{__name__}.user")) + + +def inspect(data=None, message: str = "", code: str = "User", level: str = "info"): + """ + Implementation of the openEO `inspect` process for UDF contexts. + + Note that it is up to the back-end implementation to properly capture this logging + and include it in the batch job logs. + + :param data: data to log + :param message: message to send in addition to the data + :param code: A label to help identify one or more log entries + :param level: The severity level of this message. Allowed values: "error", "warning", "info", "debug" + + .. versionadded:: 0.10.1 + + .. seealso:: :ref:`udf_logging_with_inspect` + """ + extra = {"data": data, "code": code} + kwargs = {"stacklevel": 2} if sys.version_info >= (3, 8) else {} + _user_log.log(level=logging.getLevelName(level.upper()), msg=message, extra=extra, **kwargs) diff --git a/lib/openeo/udf/feature_collection.py b/lib/openeo/udf/feature_collection.py new file mode 100644 index 000000000..329c618cc --- /dev/null +++ b/lib/openeo/udf/feature_collection.py @@ -0,0 +1,110 @@ +""" + +""" + +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf) +from __future__ import annotations + +from typing import Any, List, Optional, Union + +import pandas +import shapely.geometry + +# Geopandas is optional dependency for now +try: + from geopandas import GeoDataFrame +except ImportError: + class GeoDataFrame: + pass + + +class FeatureCollection: + """ + A feature collection that represents a subset or a whole feature collection + where single vector features may have time stamps assigned. + """ + + def __init__( + self, + id: str, + data: GeoDataFrame, + start_times: Optional[Union[pandas.DatetimeIndex, List[str]]] = None, + end_times: Optional[Union[pandas.DatetimeIndex, List[str]]] = None + ): + """ + Constructor of the of a vector collection + + :param id: The unique id of the vector collection + :param data: A GeoDataFrame with geometry column and attribute data + :param start_times: The vector with start times for each spatial x,y slice + :param end_times: The pandas.DateTimeIndex vector with end times + for each spatial x,y slice, if no + end times are defined, then time instances are assumed not intervals + """ + # TODO #455 `id` is first and a required argument, but it's unclear what it can/should be used for. Can we eliminate it? + self.id = id + self._data = data + # TODO #455 why not include these datetimes directly in the dataframe? + self._start_times = self._as_datetimeindex(start_times, expected_length=len(self.data)) + self._end_times = self._as_datetimeindex(end_times, expected_length=len(self.data)) + + def __repr__(self): + return f"<{type(self).__name__} with {type(self._data).__name__}>" + + @staticmethod + def _as_datetimeindex(dates: Any, expected_length: int = None) -> Union[pandas.DatetimeIndex, None]: + if dates is None: + return dates + if not isinstance(dates, pandas.DatetimeIndex): + dates = pandas.DatetimeIndex(dates) + if expected_length is not None and expected_length != len(dates): + raise ValueError("Expected size {e} but got {a}: {d}".format(e=expected_length, a=len(dates), d=dates)) + return dates + + @property + def data(self) -> GeoDataFrame: + """ + Get the geopandas.GeoDataFrame that contains the geometry column and any number of attribute columns + + :return: A data frame that contains the geometry column and any number of attribute columns + """ + return self._data + + @property + def start_times(self) -> Union[pandas.DatetimeIndex, None]: + return self._start_times + + @property + def end_times(self) -> Union[pandas.DatetimeIndex, None]: + return self._end_times + + def to_dict(self) -> dict: + """ + Convert this FeatureCollection into a dictionary that can be converted into + a valid JSON representation + """ + data = { + "id": self.id, + "data": shapely.geometry.mapping(self.data), + } + if self.start_times is not None: + data["start_times"] = [t.isoformat() for t in self.start_times] + if self.end_times is not None: + data["end_times"] = [t.isoformat() for t in self.end_times] + return data + + @classmethod + def from_dict(cls, data: dict) -> FeatureCollection: + """ + Create a feature collection from a python dictionary that was created from + the JSON definition of the FeatureCollection + + :param data: The dictionary that contains the feature collection definition + :return: A new FeatureCollection object + """ + return cls( + id=data["id"], + data=GeoDataFrame.from_features(data["data"]), + start_times=data.get("start_times"), + end_times=data.get("end_times"), + ) diff --git a/lib/openeo/udf/run_code.py b/lib/openeo/udf/run_code.py new file mode 100644 index 000000000..3427532ae --- /dev/null +++ b/lib/openeo/udf/run_code.py @@ -0,0 +1,241 @@ +""" + +""" + +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf) + +import functools +import importlib +import inspect +import logging +import math +import pathlib +from typing import Callable, Union + +import numpy +import pandas +import shapely +import xarray +from pandas import Series + +import openeo +from openeo.udf import OpenEoUdfException +from openeo.udf.feature_collection import FeatureCollection +from openeo.udf.structured_data import StructuredData +from openeo.udf.udf_data import UdfData +from openeo.udf.xarraydatacube import XarrayDataCube + +_log = logging.getLogger(__name__) + + +def _build_default_execution_context(): + # TODO: is it really necessary to "pre-load" these modules? Isn't user going to import them explicitly in their script anyway? + context = { + "numpy": numpy, "np": numpy, + "xarray": xarray, + "pandas": pandas, "pd": pandas, + "shapely": shapely, + "math": math, + "UdfData": UdfData, + "XarrayDataCube": XarrayDataCube, + "DataCube": XarrayDataCube, # Legacy alias + "StructuredData": StructuredData, + "FeatureCollection": FeatureCollection, + # "SpatialExtent": SpatialExtent, # TODO? + # "MachineLearnModel": MachineLearnModelConfig, # TODO? + } + + + return context + + +@functools.lru_cache(maxsize=100) +def load_module_from_string(code: str) -> dict: + """ + Experimental: avoid loading same UDF module more than once, to make caching inside the udf work. + @param code: + @return: + """ + globals = _build_default_execution_context() + exec(code, globals) + return globals + + +def _get_annotation_str(annotation: Union[str, type]) -> str: + """Get parameter annotation as a string""" + if isinstance(annotation, str): + return annotation + elif isinstance(annotation, type): + mod = annotation.__module__ + return (mod + "." if mod != str.__module__ else "") + annotation.__name__ + else: + return str(annotation) + + +def _annotation_is_pandas_series(annotation) -> bool: + return annotation in {pandas.Series, _get_annotation_str(pandas.Series)} + + +def _annotation_is_udf_datacube(annotation) -> bool: + return annotation is XarrayDataCube or _get_annotation_str(annotation) in { + _get_annotation_str(XarrayDataCube), + 'openeo_udf.api.datacube.DataCube', # Legacy `openeo_udf` annotation + } + +def _annotation_is_data_array(annotation) -> bool: + return annotation is xarray.DataArray or _get_annotation_str(annotation) in { + _get_annotation_str(xarray.DataArray) + } + + +def _annotation_is_udf_data(annotation) -> bool: + return annotation is UdfData or _get_annotation_str(annotation) in { + _get_annotation_str(UdfData), + 'openeo_udf.api.udf_data.UdfData' # Legacy `openeo_udf` annotation + } + + +def _apply_timeseries_xarray(array: xarray.DataArray, callback: Callable[[Series], Series]) -> xarray.DataArray: + """ + Apply timeseries callback to given xarray data array + along its time dimension (named "t" or "time") + + :param array: array to transform + :param callback: function that transforms a timeseries in another (same size) + :return: transformed array + """ + # Make time dimension the last one, and flatten the rest + # to create a 1D sequence of input time series (also 1D). + [time_position] = [i for (i, d) in enumerate(array.dims) if d in ["t", "time"]] + input_series = numpy.moveaxis(array.values, time_position, -1) + orig_shape = input_series.shape + input_series = input_series.reshape((-1, input_series.shape[-1])) + + applied = numpy.asarray([callback(s) for s in input_series]) + + # Reshape to original shape + applied = applied.reshape(orig_shape) + applied = numpy.moveaxis(applied, -1, time_position) + assert applied.shape == array.shape + + return xarray.DataArray(applied, coords=array.coords, dims=array.dims, name=array.name) + + +def apply_timeseries_generic( + udf_data: UdfData, + callback: Callable[[Series, dict], Series] +) -> UdfData: + """ + Implements the UDF contract by calling a user provided time series transformation function. + + :param udf_data: + :param callback: callable that takes a pandas Series and context dict and returns a pandas Series. + See template :py:func:`openeo.udf.udf_signatures.apply_timeseries` + :return: + """ + callback = functools.partial(callback, context=udf_data.user_context) + datacubes = [ + XarrayDataCube(_apply_timeseries_xarray(array=cube.array, callback=callback)) + for cube in udf_data.get_datacube_list() + ] + # Insert the new tiles as list of raster collection tiles in the input object. The new tiles will + # replace the original input tiles. + udf_data.set_datacube_list(datacubes) + return udf_data + + +def run_udf_code(code: str, data: UdfData) -> UdfData: + # TODO: current implementation uses first match directly, first check for multiple matches? + module = load_module_from_string(code) + functions = ((k, v) for (k, v) in module.items() if callable(v)) + + for (fn_name, func) in functions: + try: + sig = inspect.signature(func) + except ValueError: + continue + params = sig.parameters + first_param = next(iter(params.values()), None) + + if ( + fn_name == 'apply_timeseries' + and 'series' in params and 'context' in params + and _annotation_is_pandas_series(params["series"].annotation) + and _annotation_is_pandas_series(sig.return_annotation) + ): + _log.info("Found timeseries mapping UDF `{n}` {f!r}".format(n=fn_name, f=func)) + return apply_timeseries_generic(data, func) + elif ( + fn_name in ['apply_hypercube', 'apply_datacube'] + and 'cube' in params and 'context' in params + and _annotation_is_udf_datacube(params["cube"].annotation) + and _annotation_is_udf_datacube(sig.return_annotation) + ): + _log.info("Found datacube mapping UDF `{n}` {f!r}".format(n=fn_name, f=func)) + if len(data.get_datacube_list()) != 1: + raise ValueError("The provided UDF expects exactly one datacube, but {c} were provided.".format( + c=len(data.get_datacube_list()) + )) + # TODO: also support calls without user context? + result_cube = func(cube=data.get_datacube_list()[0], context=data.user_context) + data.set_datacube_list([result_cube]) + return data + elif ( + fn_name in ['apply_datacube'] + and 'cube' in params and 'context' in params + and _annotation_is_data_array(params["cube"].annotation) + and _annotation_is_data_array(sig.return_annotation) + ): + _log.info("Found datacube mapping UDF `{n}` {f!r}".format(n=fn_name, f=func)) + if len(data.get_datacube_list()) != 1: + raise ValueError("The provided UDF expects exactly one datacube, but {c} were provided.".format( + c=len(data.get_datacube_list()) + )) + # TODO: also support calls without user context? + result_cube: xarray.DataArray = func(cube=data.get_datacube_list()[0].get_array(), context=data.user_context) + data.set_datacube_list([XarrayDataCube(result_cube)]) + return data + elif len(params) == 1 and _annotation_is_udf_data(first_param.annotation): + _log.info("Found generic UDF `{n}` {f!r}".format(n=fn_name, f=func)) + func(data) + return data + + raise OpenEoUdfException("No UDF found.") + + +def execute_local_udf(udf: Union[str, openeo.UDF], datacube: Union[str, xarray.DataArray, XarrayDataCube], fmt='netcdf'): + """ + Locally executes an user defined function on a previously downloaded datacube. + + :param udf: the code of the user defined function + :param datacube: the path to the downloaded data in disk or a DataCube + :param fmt: format of the file if datacube is string + :return: the resulting DataCube + """ + if isinstance(udf, openeo.UDF): + udf = udf.code + + if isinstance(datacube, (str, pathlib.Path)): + d = XarrayDataCube.from_file(path=datacube, fmt=fmt) + elif isinstance(datacube, XarrayDataCube): + d = datacube + elif isinstance(datacube, xarray.DataArray): + d = XarrayDataCube(datacube) + else: + raise ValueError(datacube) + d_array = d.get_array() + expected_order = ("t", "bands", "y", "x") + dims = [d for d in expected_order if d in d_array.dims] + + # TODO: skip going through XarrayDataCube above, we only need xarray.DataArray here anyway. + # datacube's data is to be float and x,y not provided + d = XarrayDataCube(d_array.transpose(*dims).astype(numpy.float64).drop(labels="x").drop(labels="y")) + # wrap to udf_data + udf_data = UdfData(datacube_list=[d]) + + # TODO: enrich to other types like time series, vector data,... probalby by adding named arguments + # signature: UdfData(proj, datacube_list, feature_collection_list, structured_data_list, ml_model_list, metadata) + + # run the udf through the same routine as it would have been parsed in the backend + result = run_udf_code(udf, udf_data) + return result diff --git a/lib/openeo/udf/structured_data.py b/lib/openeo/udf/structured_data.py new file mode 100644 index 000000000..038bb37be --- /dev/null +++ b/lib/openeo/udf/structured_data.py @@ -0,0 +1,47 @@ +""" + +""" + +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf) + +from __future__ import annotations + +import builtins +from typing import Union + + +class StructuredData: + """ + This class represents structured data that is produced by an UDF and can not be represented + as a raster or vector data cube. For example: the result of a statistical + computation. + + Usage example:: + + >>> StructuredData([3, 5, 8, 13]) + >>> StructuredData({"mean": 5, "median": 8}) + >>> StructuredData([('col_1', 'col_2'), (1, 2), (2, 3)], type="table") + """ + + def __init__(self, data: Union[list, dict], description: str = None, type: str = None): + self.data = data + self.type = type or builtins.type(data).__name__ + self.description = description or self.type + + def __repr__(self): + return f"<{type(self).__name__} with {self.type}>" + + def to_dict(self) -> dict: + return dict( + data=self.data, + description=self.description, + type=self.type, + ) + + @classmethod + def from_dict(cls, data: dict) -> StructuredData: + return cls( + data=data["data"], + description=data.get("description"), + type=data.get("type") + ) diff --git a/lib/openeo/udf/udf_data.py b/lib/openeo/udf/udf_data.py new file mode 100644 index 000000000..e07ccdf8b --- /dev/null +++ b/lib/openeo/udf/udf_data.py @@ -0,0 +1,135 @@ +""" + +""" + +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf) + +from __future__ import annotations + +from typing import List, Optional, Union + +from openeo.udf.feature_collection import FeatureCollection +from openeo.udf.structured_data import StructuredData +from openeo.udf.xarraydatacube import XarrayDataCube + + +class UdfData: + """ + Container for data passed to a user defined function (UDF) + """ + + # TODO: original implementation in `openeo_udf` project had `get_datacube_by_id`, `get_feature_collection_by_id`: is it still useful to provide this? + # TODO: original implementation in `openeo_udf` project had `server_context`: is it still useful to provide this? + + def __init__( + self, + proj: dict = None, + datacube_list: Optional[List[XarrayDataCube]] = None, + feature_collection_list: Optional[List[FeatureCollection]] = None, + structured_data_list: Optional[List[StructuredData]] = None, + user_context: Optional[dict] = None, + ): + """ + The constructor of the UDF argument class that stores all data required by the + user defined function. + + :param proj: A dictionary of form {"proj type string": "projection description"} e.g. {"EPSG": 4326} + :param datacube_list: A list of data cube objects + :param feature_collection_list: A list of VectorTile objects + :param structured_data_list: A list of structured data objects + """ + self.datacube_list = datacube_list + self.feature_collection_list = feature_collection_list + self.structured_data_list = structured_data_list + self.proj = proj + self._user_context = user_context or {} + + def __repr__(self) -> str: + fields = " ".join( + f"{f}:{getattr(self, f)!r}" for f in + ["datacube_list", "feature_collection_list", "structured_data_list"] + ) + return f"<{type(self).__name__} {fields}>" + + @property + def user_context(self) -> dict: + """Return the user context that was passed to the run_udf function""" + return self._user_context + + def get_datacube_list(self) -> Union[List[XarrayDataCube], None]: + """Get the data cube list""" + return self._datacube_list + + def set_datacube_list(self, datacube_list: Union[List[XarrayDataCube], None]): + """ + Set the data cube list + + :param datacube_list: A list of data cubes + """ + self._datacube_list = datacube_list + + datacube_list = property(fget=get_datacube_list, fset=set_datacube_list) + + def get_feature_collection_list(self) -> Union[List[FeatureCollection], None]: + """get all feature collections as list""" + return self._feature_collection_list + + def set_feature_collection_list(self, feature_collection_list: Union[List[FeatureCollection], None]): + self._feature_collection_list = feature_collection_list + + feature_collection_list = property(fget=get_feature_collection_list, fset=set_feature_collection_list) + + def get_structured_data_list(self) -> Union[List[StructuredData], None]: + """ + Get all structured data entries + + :return: A list of StructuredData objects + """ + return self._structured_data_list + + def set_structured_data_list(self, structured_data_list: Union[List[StructuredData], None]): + """ + Set the list of structured data + + :param structured_data_list: A list of StructuredData objects + """ + self._structured_data_list = structured_data_list + + structured_data_list = property(fget=get_structured_data_list, fset=set_structured_data_list) + + def to_dict(self) -> dict: + """ + Convert this UdfData object into a dictionary that can be converted into + a valid JSON representation + """ + return { + "datacubes": [x.to_dict() for x in self.datacube_list] \ + if self.datacube_list else None, + "feature_collection_list": [x.to_dict() for x in self.feature_collection_list] \ + if self.feature_collection_list else None, + "structured_data_list": [x.to_dict() for x in self.structured_data_list] \ + if self.structured_data_list else None, + "proj": self.proj, + "user_context": self.user_context, + } + + @classmethod + def from_dict(cls, udf_dict: dict) -> UdfData: + """ + Create a udf data object from a python dictionary that was created from + the JSON definition of the UdfData class + + :param udf_dict: The dictionary that contains the udf data definition + """ + + datacubes = [XarrayDataCube.from_dict(x) for x in udf_dict.get("datacubes", [])] + feature_collection_list = [FeatureCollection.from_dict(x) for x in udf_dict.get("feature_collection_list", [])] + structured_data_list = [StructuredData.from_dict(x) for x in udf_dict.get("structured_data_list", [])] + udf_data = cls( + proj=udf_dict.get("proj"), + datacube_list=datacubes, + feature_collection_list=feature_collection_list, + structured_data_list=structured_data_list, + user_context=udf_dict.get("user_context") + ) + return udf_data diff --git a/lib/openeo/udf/udf_signatures.py b/lib/openeo/udf/udf_signatures.py new file mode 100644 index 000000000..395d17cc2 --- /dev/null +++ b/lib/openeo/udf/udf_signatures.py @@ -0,0 +1,87 @@ +""" +This module defines a number of function signatures that can be implemented by UDF's. +Both the name of the function and the argument types are/can be used by the backend to validate if the provided UDF +is compatible with the calling context of the process graph in which it is used. + +""" +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf) + +from pandas import Series + +from openeo.udf.udf_data import UdfData +from openeo.udf.xarraydatacube import XarrayDataCube +from openeo.metadata import CollectionMetadata + + +def apply_timeseries(series: Series, context: dict) -> Series: + """ + Process a timeseries of values, without changing the time instants. + + This can for instance be used for smoothing or gap-filling. + + :param series: A Pandas Series object with a date-time index. + :param context: A dictionary containing user context. + :return: A Pandas Series object with the same datetime index. + """ + # TODO: do we need geospatial coordinates for the series? + return series + + +def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube: + """ + Map a :py:class:`XarrayDataCube` to another :py:class:`XarrayDataCube`. + + Depending on the context in which this function is used, the :py:class:`XarrayDataCube` dimensions + have to be retained or can be chained. + For instance, in the context of a reducing operation along a dimension, + that dimension will have to be reduced to a single value. + In the context of a 1 to 1 mapping operation, all dimensions have to be retained. + + :param cube: input data cube + :param context: A dictionary containing user context. + :return: output data cube + """ + return cube + + +def apply_udf_data(data: UdfData): + """ + Generic UDF function that directly manipulates a :py:class:`UdfData` object + + :param data: :py:class:`UdfData` object to manipulate in-place + """ + pass + + +def apply_metadata(metadata: CollectionMetadata, context: dict) -> CollectionMetadata: + """ + .. warning:: + This signature is not yet fully standardized and subject to change. + + Returns the expected cube metadata, after applying this UDF, based on input metadata. + The provided metadata represents the whole raster or vector cube. This function does not need to be called for every data chunk. + + When this function is not implemented by the UDF, the backend may still be able to infer correct metadata by running the + UDF, but this can result in reduced performance or errors. + + This function does not need to be provided when using the UDF in combination with processes that by design have a clear + effect on cube metadata, such as :py:meth:`~openeo.rest.datacube.DataCube.reduce_dimension()` + + :param metadata: the collection metadata of the input data cube + :param context: A dictionary containing user context. + + :return: output metadata: the expected metadata of the cube, after applying the udf + + Examples + -------- + + An example for a UDF that is applied on the 'bands' dimension, and returns a new set of bands with different labels. + + >>> def apply_metadata(metadata: CollectionMetadata, context: dict) -> CollectionMetadata: + ... return metadata.rename_labels( + ... dimension="bands", + ... target=["computed_band_1", "computed_band_2"] + ... ) + + """ + pass diff --git a/lib/openeo/udf/xarraydatacube.py b/lib/openeo/udf/xarraydatacube.py new file mode 100644 index 000000000..ee789e465 --- /dev/null +++ b/lib/openeo/udf/xarraydatacube.py @@ -0,0 +1,379 @@ +""" + +""" + +# Note: this module was initially developed under the ``openeo-udf`` project (https://github.com/Open-EO/openeo-udf) + +from __future__ import annotations + +import collections +import json +import typing +from pathlib import Path +from typing import Optional, Union + +import numpy +import xarray + +from openeo.udf import OpenEoUdfException +from openeo.util import deep_get, dict_no_none + +if typing.TYPE_CHECKING: + # Imports for type checking only (circular import issue at runtime). + import matplotlib.colors + + +class XarrayDataCube: + """ + This is a thin wrapper around :py:class:`xarray.DataArray` + providing a basic "DataCube" interface for openEO UDF usage around multi-dimensional data. + """ + + def __init__(self, array: xarray.DataArray): + if not isinstance(array, xarray.DataArray): + raise OpenEoUdfException("Argument data must be of type xarray.DataArray") + self._array = array + + def __repr__(self): + return f"<{type(self).__name__} shape:{self._array.shape}>" + + def get_array(self) -> xarray.DataArray: + """ + Get the :py:class:`xarray.DataArray` that contains the data and dimension definition + """ + return self._array + + array = property(fget=get_array) + + @property + def id(self): + return self._array.name + + def to_dict(self) -> dict: + """ + Convert this hypercube into a dictionary that can be converted into + a valid JSON representation + + >>> example = { + ... "id": "test_data", + ... "data": [ + ... [[0.0, 0.1], [0.2, 0.3]], + ... [[0.0, 0.1], [0.2, 0.3]], + ... ], + ... "dimension": [ + ... {"name": "time", "coordinates": ["2001-01-01", "2001-01-02"]}, + ... {"name": "X", "coordinates": [50.0, 60.0]}, + ... {"name": "Y"}, + ... ], + ... } + """ + xd = self._array.to_dict() + return dict_no_none({ + "id": xd.get("name"), + "data": xd.get("data"), + "description": deep_get(xd, "attrs", "description", default=None), + "dimensions": [ + dict_no_none( + name=dim, + coordinates=deep_get(xd, "coords", dim, "data", default=None) + ) + for dim in xd.get("dims", []) + ] + }) + + @classmethod + def from_dict(cls, xdc_dict: dict) -> XarrayDataCube: + """ + Create a :py:class:`XarrayDataCube` from a Python dictionary that was created from + the JSON definition of the data cube + + :param data: The dictionary that contains the data cube definition + """ + + if "data" not in xdc_dict: + raise OpenEoUdfException("Missing data in dictionary") + + data = numpy.asarray(xdc_dict["data"]) + + if "dimensions" in xdc_dict: + dims = [dim["name"] for dim in xdc_dict["dimensions"]] + coords = {dim["name"]: dim["coordinates"] for dim in xdc_dict["dimensions"] if "coordinates" in dim} + else: + dims = None + coords = None + + x = xarray.DataArray(data, dims=dims, coords=coords, name=xdc_dict.get("id")) + + if "description" in xdc_dict: + x.attrs["description"] = xdc_dict["description"] + + return cls(array=x) + + @staticmethod + def _guess_format(path: Union[str, Path]) -> str: + """Guess file format from file name.""" + suffix = Path(path).suffix.lower() + if suffix in [".nc", ".netcdf"]: + return "netcdf" + elif suffix in [".json"]: + return "json" + else: + raise ValueError("Can not guess format of {p}".format(p=path)) + + @classmethod + def from_file(cls, path: Union[str, Path], fmt=None, **kwargs) -> XarrayDataCube: + """ + Load data file as :py:class:`XarrayDataCube` in memory + + :param path: the file on disk + :param fmt: format to load from, e.g. "netcdf" or "json" + (will be auto-detected when not specified) + + :return: loaded data cube + """ + fmt = fmt or cls._guess_format(path) + if fmt.lower() == 'netcdf': + return cls(array=XarrayIO.from_netcdf_file(path=path, **kwargs)) + elif fmt.lower() == 'json': + return cls(array=XarrayIO.from_json_file(path=path)) + else: + raise ValueError("invalid format {f}".format(f=fmt)) + + def save_to_file(self, path: Union[str, Path], fmt=None, **kwargs): + """ + Store :py:class:`XarrayDataCube` to file + + :param path: destination file on disk + :param fmt: format to save as, e.g. "netcdf" or "json" + (will be auto-detected when not specified) + """ + fmt = fmt or self._guess_format(path) + if fmt.lower() == 'netcdf': + XarrayIO.to_netcdf_file(array=self.get_array(), path=path, **kwargs) + elif fmt.lower() == 'json': + XarrayIO.to_json_file(array=self.get_array(), path=path) + else: + raise ValueError(fmt) + + def plot( + self, + title: str = None, + limits=None, + show_bandnames: bool = True, + show_dates: bool = True, + show_axeslabels: bool = False, + fontsize: float = 10., + oversample: float = 1, + cmap: Union[str, 'matplotlib.colors.Colormap'] = 'RdYlBu_r', + cbartext: str = None, + to_file: str = None, + to_show: bool = True + ): + """ + Visualize a :py:class:`XarrayDataCube` with matplotlib + + :param datacube: data to plot + :param title: title text drawn in the top left corner (default: nothing) + :param limits: range of the contour plot as a tuple(min,max) (default: None, in which case the min/max is computed from the data) + :param show_bandnames: whether to plot the column names (default: True) + :param show_dates: whether to show the dates for each row (default: True) + :param show_axeslabels: whether to show the labels on the axes (default: False) + :param fontsize: font size in pixels (default: 10) + :param oversample: one value is plotted into oversample x oversample number of pixels (default: 1 which means each value is plotted as a single pixel) + :param cmap: built-in matplotlib color map name or ColorMap object (default: RdYlBu_r which is a blue-yellow-red rainbow) + :param cbartext: text on top of the legend (default: nothing) + :param to_file: filename to save the image to (default: None, which means no file is generated) + :param to_show: whether to show the image in a matplotlib window (default: True) + + :return: None + """ + from matplotlib import pyplot + + data = self.get_array() + if limits is None: + vmin = data.min() + vmax = data.max() + else: + vmin = limits[0] + vmax = limits[1] + + # fill bands and t if missing + if 'bands' not in data.dims: + data = data.expand_dims(dim={'bands': ['band0']}) + if 't' not in data.dims: + data = data.expand_dims(dim={'t': [numpy.datetime64('today')]}) + if 'bands' not in data.coords: + data['bands'] = ['band0'] + if 't' not in data.coords: + data['t'] = [numpy.datetime64('today')] + + # align with plot + data = data.transpose('t', 'bands', 'y', 'x') + dpi = 100 + xres = len(data.x) / dpi + yres = len(data.y) / dpi + fs = fontsize / oversample + frame = 0.33 + + nrow = data.shape[0] + ncol = data.shape[1] + + fig = pyplot.figure(figsize=((ncol + frame) * xres * 1.1, (nrow + frame) * yres), dpi=int(dpi * oversample)) + gs = pyplot.GridSpec(nrow, ncol, wspace=0., hspace=0., top=nrow / (nrow + frame), bottom=0., + left=frame / (ncol + frame), right=1.) + + xmin = data.x.min() + xmax = data.x.max() + ymin = data.y.min() + ymax = data.y.max() + + # flip around if incorrect, this is in harmony with origin='lower' + if (data.x[0] > data.x[-1]): + data = data.reindex(x=list(reversed(data.x))) + if (data.y[0] > data.y[-1]): + data = data.reindex(y=list(reversed(data.y))) + + extent = (data.x[0], data.x[-1], data.y[0], data.y[-1]) + + for i in range(nrow): + for j in range(ncol): + im = data[i, j] + ax = pyplot.subplot(gs[i, j]) + ax.set_xlim(xmin, xmax) + ax.set_ylim(ymin, ymax) + img = ax.imshow(im, vmin=vmin, vmax=vmax, cmap=cmap, origin='lower', extent=extent) + ax.xaxis.set_tick_params(labelsize=fs) + ax.yaxis.set_tick_params(labelsize=fs) + if not show_axeslabels: + ax.set_axis_off() + ax.set_xticklabels([]) + ax.set_yticklabels([]) + if show_bandnames: + if i == 0: ax.text(0.5, 1.08, data.bands.values[j] + " (" + str(data.dtype) + ")", size=fs, + va="center", + ha="center", transform=ax.transAxes) + if show_dates: + if j == 0: ax.text(-0.08, 0.5, data.t.dt.strftime("%Y-%m-%d").values[i], size=fs, va="center", + ha="center", rotation=90, transform=ax.transAxes) + + if title is not None: + fig.text(0., 1., title.split('/')[-1], size=fs, va="top", ha="left", weight='bold') + + cbar_ax = fig.add_axes([0.01, 0.1, 0.04, 0.5]) + if cbartext is not None: + fig.text(0.06, 0.62, cbartext, size=fs, va="bottom", ha="center") + cbar = fig.colorbar(img, cax=cbar_ax) + cbar.ax.tick_params(labelsize=fs) + cbar.outline.set_visible(False) + cbar.ax.tick_params(size=0) + cbar.ax.yaxis.set_tick_params(pad=0) + + if to_file is not None: + pyplot.savefig(str(to_file)) + if to_show: + pyplot.show() + + pyplot.close() + + +class XarrayIO: + """ + Helpers to load/store :py:cass:`xarray.DataArray` objects, + with some conventions about expected dimensions/bands + """ + + @classmethod + def from_json_file(cls, path: Union[str, Path]) -> xarray.DataArray: + with Path(path).open() as f: + return cls.from_json(json.load(f)) + + @classmethod + def from_json(cls, d: dict) -> xarray.DataArray: + d['data'] = numpy.array(d['data'], dtype=numpy.dtype(d['attrs']['dtype'])) + for k, v in d['coords'].items(): + # prepare coordinate + d['coords'][k]['data'] = numpy.array(v['data'], dtype=v['attrs']['dtype']) + # remove dtype and shape, because that is included for helping the user + if d['coords'][k].get('attrs', None) is not None: + d['coords'][k]['attrs'].pop('dtype', None) + d['coords'][k]['attrs'].pop('shape', None) + + # remove dtype and shape, because that is included for helping the user + if d.get('attrs', None) is not None: + d['attrs'].pop('dtype', None) + d['attrs'].pop('shape', None) + # convert to xarray + r = xarray.DataArray.from_dict(d) + + # build dimension list in proper order + dims = list(filter(lambda i: i != 't' and i != 'bands' and i != 'x' and i != 'y', r.dims)) + if 't' in r.dims: dims += ['t'] + if 'bands' in r.dims: dims += ['bands'] + if 'x' in r.dims: dims += ['x'] + if 'y' in r.dims: dims += ['y'] + # return the resulting data array + return r.transpose(*dims) + + @classmethod + def from_netcdf_file(cls, path: Union[str, Path], engine: Optional[str] = None) -> xarray.DataArray: + # load the dataset and convert to data array + ds = xarray.open_dataset(path, engine=engine) + + # Skip non-numerical variables (like "crs") + band_vars = [k for k, v in ds.data_vars.items() if v.dtype.kind in {"b", "i", "u", "f"} and len(v.dims) > 0] + ds = ds[band_vars] + + r = ds.to_array(dim='bands') + + # Reorder dims to proper order (t-bands-x-y at the end) + expected_order = ("t", "bands", "x", "y") + dims = [d for d in r.dims if d not in expected_order] + [d for d in expected_order if d in r.dims] + + return r.transpose(*dims) + + @classmethod + def to_json_file(cls, array: xarray.DataArray, path: Union[str, Path]): + # to deserialized json + jsonarray = array.to_dict() + # add attributes that needed for re-creating xarray from json + jsonarray['attrs']['dtype'] = str(array.values.dtype) + jsonarray['attrs']['shape'] = list(array.values.shape) + for i in array.coords.values(): + jsonarray['coords'][i.name]['attrs']['dtype'] = str(i.dtype) + jsonarray['coords'][i.name]['attrs']['shape'] = list(i.shape) + # custom print so resulting json file is humanly easy to read + # TODO: make this human friendly JSON format optional and allow compact JSON too. + with Path(path).open("w") as f: + def custom_print(data_structure, indent=1): + f.write("{\n") + needs_comma = False + for key, value in data_structure.items(): + if needs_comma: + f.write(',\n') + needs_comma = True + f.write(' ' * indent + json.dumps(key) + ':') + if isinstance(value, dict): + custom_print(value, indent + 1) + else: + json.dump(value, f, default=str, separators=(',', ':')) + f.write('\n' + ' ' * (indent - 1) + "}") + + custom_print(jsonarray) + + @classmethod + def to_netcdf_file(cls, array: xarray.DataArray, path: Union[str, Path], engine: Optional[str] = None): + # temp reference to avoid modifying the original array + result = array + # rearrange in a basic way because older xarray versions have a bug and ellipsis don't work in xarray.transpose() + if result.dims[-2] == 'x' and result.dims[-1] == 'y': + l = list(result.dims[:-2]) + result = result.transpose(*(l + ['y', 'x'])) + # turn it into a dataset where each band becomes a variable + if not 'bands' in result.dims: + result = result.expand_dims(dim=collections.OrderedDict({'bands': ['band_0']})) + else: + if not 'bands' in result.coords: + labels = ['band_' + str(i) for i in range(result.shape[result.dims.index('bands')])] + result = result.assign_coords(bands=labels) + result = result.to_dataset('bands') + result.to_netcdf(path, engine=engine) diff --git a/lib/openeo/util.py b/lib/openeo/util.py new file mode 100644 index 000000000..762bf5f7c --- /dev/null +++ b/lib/openeo/util.py @@ -0,0 +1,686 @@ +""" +Various utilities and helpers. +""" + +# TODO #465 split this kitchen-sink in thematic submodules + +from __future__ import annotations + +import datetime as dt +import functools +import json +import logging +import re +import sys +import time +from collections import OrderedDict +from enum import Enum +from pathlib import Path +from typing import Any, Callable, List, Optional, Tuple, Union +from urllib.parse import urljoin + +import requests +import shapely.geometry.base +from deprecated import deprecated + +try: + # pyproj is an optional dependency + import pyproj +except ImportError: + pyproj = None + + +logger = logging.getLogger(__name__) + + +class Rfc3339: + """ + Formatter for dates according to RFC-3339. + + Parses date(time)-like input and formats according to RFC-3339. Some examples: + + >>> rfc3339.date("2020:03:17") + "2020-03-17" + >>> rfc3339.date(2020, 3, 17) + "2020-03-17" + >>> rfc3339.datetime("2020/03/17/12/34/56") + "2020-03-17T12:34:56Z" + >>> rfc3339.datetime([2020, 3, 17, 12, 34, 56]) + "2020-03-17T12:34:56Z" + >>> rfc3339.datetime(2020, 3, 17) + "2020-03-17T00:00:00Z" + >>> rfc3339.datetime(datetime(2020, 3, 17, 12, 34, 56)) + "2020-03-17T12:34:56Z" + + Or just normalize (automatically preserve date/datetime resolution): + + >>> rfc3339.normalize("2020/03/17") + "2020-03-17" + >>> rfc3339.normalize("2020-03-17-12-34-56") + "2020-03-17T12:34:56Z" + + Also see https://tools.ietf.org/html/rfc3339#section-5.6 + """ + # TODO: currently we hard code timezone 'Z' for simplicity. Add real time zone support? + _FMT_DATE = '%Y-%m-%d' + _FMT_TIME = '%H:%M:%SZ' + _FMT_DATETIME = _FMT_DATE + "T" + _FMT_TIME + + _regex_datetime = re.compile(r""" + ^(?P\d{4})[:/_-](?P\d{2})[:/_-](?P\d{2})[T :/_-]? + (?:(?P\d{2})[:/_-](?P\d{2})(?:[:/_-](?P\d{2}))?)?""", re.VERBOSE) + + def __init__(self, propagate_none: bool = False): + self._propagate_none = propagate_none + + def datetime(self, x: Any, *args) -> Union[str, None]: + """ + Format given date(time)-like object as RFC-3339 datetime string. + """ + if args: + return self.datetime((x,) + args) + elif isinstance(x, dt.datetime): + return self._format_datetime(x) + elif isinstance(x, dt.date): + return self._format_datetime(dt.datetime.combine(x, dt.time())) + elif isinstance(x, str): + return self._format_datetime(dt.datetime(*self._parse_datetime(x))) + elif isinstance(x, (tuple, list)): + return self._format_datetime(dt.datetime(*(int(v) for v in x))) + elif x is None and self._propagate_none: + return None + raise ValueError(x) + + def date(self, x: Any, *args) -> Union[str, None]: + """ + Format given date-like object as RFC-3339 date string. + """ + if args: + return self.date((x,) + args) + elif isinstance(x, (dt.date, dt.datetime)): + return self._format_date(x) + elif isinstance(x, str): + return self._format_date(dt.datetime(*self._parse_datetime(x))) + elif isinstance(x, (tuple, list)): + return self._format_date(dt.datetime(*(int(v) for v in x))) + elif x is None and self._propagate_none: + return None + raise ValueError(x) + + def normalize(self, x: Any, *args) -> Union[str, None]: + """ + Format given date(time)-like object as RFC-3339 date or date-time string depending on given resolution + + >>> rfc3339.normalize("2020/03/17") + "2020-03-17" + >>> rfc3339.normalize("2020/03/17/12/34/56") + "2020-03-17T12:34:56Z" + """ + if args: + return self.normalize((x,) + args) + elif isinstance(x, dt.datetime): + return self.datetime(x) + elif isinstance(x, dt.date): + return self.date(x) + elif isinstance(x, str): + x = self._parse_datetime(x) + return self.date(x) if len(x) <= 3 else self.datetime(x) + elif isinstance(x, (tuple, list)): + return self.date(x) if len(x) <= 3 else self.datetime(x) + elif x is None and self._propagate_none: + return None + raise ValueError(x) + + def parse_date(self, x: Union[str, None]) -> Union[dt.date, None]: + """Parse given string as RFC3339 date.""" + if isinstance(x, str): + return dt.datetime.strptime(x, "%Y-%m-%d").date() + elif x is None and self._propagate_none: + return None + raise ValueError(x) + + def parse_datetime( + self, x: Union[str, None], with_timezone: bool = False + ) -> Union[dt.datetime, None]: + """Parse given string as RFC3339 date-time.""" + if isinstance(x, str): + # TODO: Also support parsing other timezones than UTC (Z) + if re.search(r":\d+\.\d+", x): + res = dt.datetime.strptime(x, "%Y-%m-%dT%H:%M:%S.%fZ") + else: + res = dt.datetime.strptime(x, "%Y-%m-%dT%H:%M:%SZ") + if with_timezone: + res = res.replace(tzinfo=dt.timezone.utc) + return res + elif x is None and self._propagate_none: + return None + raise ValueError(x) + + def parse_date_or_datetime( + self, x: Union[str, None], with_timezone: bool = False + ) -> Union[dt.date, dt.datetime, None]: + """Parse given string as RFC3339 date or date-time.""" + if isinstance(x, str): + if len(x) > 10: + return self.parse_datetime(x, with_timezone=with_timezone) + else: + return self.parse_date(x) + elif x is None and self._propagate_none: + return None + raise ValueError(x) + + @classmethod + def _format_datetime(cls, d: dt.datetime) -> str: + """Format given datetime as RFC-3339 date-time string.""" + if d.tzinfo not in {None, dt.timezone.utc}: + # TODO: add support for non-UTC timezones? + raise ValueError(f"No support for non-UTC timezone {d.tzinfo}") + return d.strftime(cls._FMT_DATETIME) + + @classmethod + def _format_date(cls, d: dt.date) -> str: + """Format given datetime as RFC-3339 date-time string.""" + return d.strftime(cls._FMT_DATE) + + @classmethod + def _parse_datetime(cls, s: str) -> Tuple[int]: + """Try to parse string to a date(time) tuple""" + try: + return tuple(int(v) for v in cls._regex_datetime.match(s).groups() if v is not None) + except Exception: + raise ValueError("Can not parse as date: {s}".format(s=s)) + + def today(self) -> str: + """Today (date) in RFC3339 format""" + return self.date(dt.date.today()) + + def utcnow(self) -> str: + """Current UTC datetime in RFC3339 format.""" + # Current time in UTC timezone (instead of naive `datetime.datetime.utcnow()`, per `datetime` documentation) + now = dt.datetime.now(tz=dt.timezone.utc) + return self.datetime(now) + + +# Default RFC3339 date-time formatter +rfc3339 = Rfc3339() + + +@deprecated("Use `rfc3339.normalize`, `rfc3339.date` or `rfc3339.datetime` instead") +def date_to_rfc3339(d: Any) -> str: + """ + Convert date-like object to a RFC 3339 formatted date string + + see https://tools.ietf.org/html/rfc3339#section-5.6 + """ + return rfc3339.normalize(d) + + +def dict_no_none(*args, **kwargs) -> dict: + """ + Helper to build a dict containing given key-value pairs where the value is not None. + """ + return { + k: v + for k, v in dict(*args, **kwargs).items() + if v is not None + } + + +def first_not_none(*args): + """Return first item from given arguments that is not None.""" + for item in args: + if item is not None: + return item + raise ValueError("No not-None values given.") + + +def ensure_dir(path: Union[str, Path]) -> Path: + """Create directory if it doesn't exist.""" + path = Path(path) + if not path.exists(): + path.mkdir(parents=True, exist_ok=True) + assert path.is_dir() + return path + + +def ensure_list(x): + """Convert given data structure to a list.""" + try: + return list(x) + except TypeError: + return [x] + + +class ContextTimer: + """ + Context manager to measure the "wall clock" time (in seconds) inside/for a block of code. + + Usage example: + + with ContextTimer() as timer: + # Inside code block: currently elapsed time + print(timer.elapsed()) + + # Outside code block: elapsed time when block ended + print(timer.elapsed()) + + """ + + __slots__ = ["start", "end"] + + # Function that returns current time in seconds (overridable for unit tests) + _clock = time.time + + def __init__(self): + self.start = None + self.end = None + + def elapsed(self) -> float: + """Elapsed time (in seconds) inside or at the end of wrapped context.""" + if self.start is None: + raise RuntimeError("Timer not started.") + if self.end is not None: + # Elapsed time when exiting context. + return self.end - self.start + else: + # Currently elapsed inside context. + return self._clock() - self.start + + def __enter__(self) -> ContextTimer: + self.start = self._clock() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.end = self._clock() + + +class TimingLogger: + """ + Context manager for quick and easy logging of start time, end time and elapsed time of some block of code + + Usage example: + + >>> with TimingLogger("Doing batch job"): + ... do_batch_job() + + At start of the code block the current time will be logged + and at end of the code block the end time and elapsed time will be logged. + + Can also be used as a function/method decorator, for example: + + >>> @TimingLogger("Calculation going on") + ... def add(x, y): + ... return x + y + """ + + # Function that returns current datetime (overridable for unit tests) + _now = dt.datetime.now + + def __init__(self, title: str = "Timing", logger: Union[logging.Logger, str, Callable] = logger): + """ + :param title: the title to use in the logging + :param logger: how the timing should be logged. + Can be specified as a logging.Logger object (in which case the INFO log level will be used), + as a string (name of the logging.Logger object to construct), + or as callable (e.g. to use the `print` function, or the `.debug` method of an existing logger) + """ + self.title = title + if isinstance(logger, str): + logger = logging.getLogger(logger) + if isinstance(logger, (logging.Logger, logging.LoggerAdapter)): + self._log = logger.info + elif callable(logger): + self._log = logger + else: + raise ValueError("Invalid logger {l!r}".format(l=logger)) + + self.start_time = self.end_time = self.elapsed = None + + def __enter__(self): + self.start_time = self._now() + self._log("{t}: start {s}".format(t=self.title, s=self.start_time)) + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.end_time = self._now() + self.elapsed = self.end_time - self.start_time + self._log("{t}: {s} {e}, elapsed {d}".format( + t=self.title, + s="fail" if exc_type else "end", + e=self.end_time, d=self.elapsed + )) + + def __call__(self, f: Callable): + """ + Use TimingLogger as function/method decorator + """ + + @functools.wraps(f) + def wrapper(*args, **kwargs): + with self: + return f(*args, **kwargs) + + return wrapper + + +class DeepKeyError(LookupError): + def __init__(self, key, keys): + super(DeepKeyError, self).__init__("{k!r} (from deep key {s!r})".format(k=key, s=keys)) + + +# Sentinel object for `default` argument of `deep_get` +_deep_get_default_undefined = object() + + +def deep_get(data: dict, *keys, default=_deep_get_default_undefined): + """ + Get value deeply from nested dictionaries/lists/tuples + + :param data: nested data structure of dicts, lists, tuples + :param keys: sequence of keys/indexes to traverse + :param default: default value when a key is missing. + By default a DeepKeyError will be raised. + :return: + """ + for key in keys: + if isinstance(data, dict) and key in data: + data = data[key] + elif isinstance(data, (list, tuple)) and isinstance(key, int) and 0 <= key < len(data): + data = data[key] + else: + if default is _deep_get_default_undefined: + raise DeepKeyError(key, keys) + else: + return default + return data + + +def deep_set(data: dict, *keys, value): + """ + Set a value deeply in nested dictionary + + :param data: nested data structure of dicts, lists, tuples + :param keys: sequence of keys/indexes to traverse + :param value: value to set + """ + if len(keys) == 1: + data[keys[0]] = value + elif len(keys) > 1: + if isinstance(data, dict): + deep_set(data.setdefault(keys[0], OrderedDict()), *keys[1:], value=value) + elif isinstance(data, (list, tuple)): + deep_set(data[keys[0]], *keys[1:], value=value) + else: + ValueError(data) + else: + raise ValueError("No keys given") + + +def guess_format(filename: Union[str, Path]) -> str: + """ + Guess the output format from a given filename and return the corrected format. + Any names not in the dict get passed through. + """ + extension = str(filename).rsplit(".", 1)[-1].lower() + + format_map = { + "gtiff": "GTiff", + "geotiff": "GTiff", + "geotif": "GTiff", + "tiff": "GTiff", + "tif": "GTiff", + "nc": "netCDF", + "netcdf": "netCDF", + "geojson": "GeoJSON", + } + + return format_map.get(extension, extension.upper()) + + +def load_json(path: Union[Path, str]) -> dict: + with Path(path).open("r", encoding="utf-8") as f: + return json.load(f) + + +def load_json_resource(src: Union[str, Path]) -> dict: + """ + Helper to load some kind of JSON resource + + :param src: a JSON resource: a raw JSON string, + a path to (local) JSON file, or a URL to a remote JSON resource + :return: data structured parsed from JSON + """ + if isinstance(src, str) and src.strip().startswith("{"): + # Assume source is a raw JSON string + return json.loads(src) + elif isinstance(src, str) and re.match(r"^https?://", src, flags=re.I): + # URL to remote JSON resource + return requests.get(src).json() + elif isinstance(src, Path) or (isinstance(src, str) and src.endswith(".json")): + # Assume source is a local JSON file path + return load_json(src) + raise ValueError(src) + + +class LazyLoadCache: + """Simple cache that allows to (lazy) load on cache miss.""" + + def __init__(self): + self._cache = {} + + def get(self, key: Union[str, tuple], load: Callable[[], Any]): + if key not in self._cache: + self._cache[key] = load() + return self._cache[key] + + +def str_truncate(text: str, width: int = 64, ellipsis: str = "...") -> str: + """Shorten a string (with an ellipsis) if it is longer than certain length.""" + width = max(0, int(width)) + if len(text) <= width: + return text + if len(ellipsis) > width: + ellipsis = ellipsis[:width] + return text[:max(0, (width - len(ellipsis)))] + ellipsis + + +def repr_truncate(obj: Any, width: int = 64, ellipsis: str = "...") -> str: + """Do `repr` rendering of an object, but truncate string if it is too long .""" + if isinstance(obj, str) and width > len(ellipsis) + 2: + # Special case: put ellipsis inside quotes + return repr(str_truncate(text=obj, width=width - 2, ellipsis=ellipsis)) + else: + # General case: just put ellipsis at end + return str_truncate(text=repr(obj), width=width, ellipsis=ellipsis) + + +def in_interactive_mode() -> bool: + """Detect if we are running in interactive mode (Jupyter/IPython/repl)""" + # Based on https://stackoverflow.com/a/64523765 + return hasattr(sys, "ps1") + + +class InvalidBBoxException(ValueError): + pass + + +class BBoxDict(dict): + """ + Dictionary based helper to easily create/work with bounding box dictionaries + (having keys "west", "south", "east", "north", and optionally "crs"). + + :param crs: value describing the coordinate reference system. + Typically just an int (interpreted as EPSG code, e.g. ``4326``) + or a string (handled as authority string, e.g. ``"EPSG:4326"``). + See :py:func:`openeo.util.normalize_crs` for more details about additional normalization that is applied to this argument. + + .. versionadded:: 0.10.1 + """ + + def __init__(self, *, west: float, south: float, east: float, north: float, crs: Optional[Union[str, int]] = None): + super().__init__(west=west, south=south, east=east, north=north) + if crs is not None: + self.update(crs=normalize_crs(crs)) + + # TODO: provide west, south, east, north, crs as @properties? Read-only or read-write? + + @classmethod + def from_any(cls, x: Any, *, crs: Optional[str] = None) -> BBoxDict: + if isinstance(x, dict): + if crs and "crs" in x and crs != x["crs"]: + raise InvalidBBoxException(f"Two CRS values specified: {crs} and {x['crs']}") + return cls.from_dict({"crs": crs, **x}) + elif isinstance(x, (list, tuple)): + return cls.from_sequence(x, crs=crs) + elif isinstance(x, shapely.geometry.base.BaseGeometry): + return cls.from_sequence(x.bounds, crs=crs) + # TODO: support other input? E.g.: WKT string, GeoJson-style dictionary (Polygon, FeatureCollection, ...) + else: + raise InvalidBBoxException(f"Can not construct BBoxDict from {x!r}") + + @classmethod + def from_dict(cls, data: dict) -> BBoxDict: + """Build from dictionary with at least keys "west", "south", "east", and "north".""" + expected_fields = {"west", "south", "east", "north"} + # TODO: also support upper case fields? + # TODO: optional support for parameterized bbox fields? + missing = expected_fields.difference(data.keys()) + if missing: + raise InvalidBBoxException(f"Missing bbox fields {sorted(missing)}") + invalid = {k: data[k] for k in expected_fields if not isinstance(data[k], (int, float))} + if invalid: + raise InvalidBBoxException(f"Non-numerical bbox fields {invalid}.") + return cls(west=data["west"], south=data["south"], east=data["east"], north=data["north"], crs=data.get("crs")) + + @classmethod + def from_sequence(cls, seq: Union[list, tuple], crs: Optional[str] = None) -> BBoxDict: + """Build from sequence of 4 bounds (west, south, east and north).""" + if len(seq) != 4: + raise InvalidBBoxException(f"Expected sequence with 4 items, but got {len(seq)}.") + return cls(west=seq[0], south=seq[1], east=seq[2], north=seq[3], crs=crs) + + +def to_bbox_dict(x: Any, *, crs: Optional[Union[str, int]] = None) -> BBoxDict: + """ + Convert given data or object to a bounding box dictionary + (having keys "west", "south", "east", "north", and optionally "crs"). + + Supports various input types/formats: + + - list/tuple (assumed to be in west-south-east-north order) + + >>> to_bbox_dict([3, 50, 4, 51]) + {'west': 3, 'south': 50, 'east': 4, 'north': 51} + + - dictionary (unnecessary items will be stripped) + + >>> to_bbox_dict({ + ... "color": "red", "shape": "triangle", + ... "west": 1, "south": 2, "east": 3, "north": 4, "crs": "EPSG:4326", + ... }) + {'west': 1, 'south': 2, 'east': 3, 'north': 4, 'crs': 'EPSG:4326'} + + - a shapely geometry + + .. versionadded:: 0.10.1 + + :param x: input data that describes west-south-east-north bounds in some way, e.g. as a dictionary, + a list, a tuple, ashapely geometry, ... + :param crs: (optional) CRS field + :return: dictionary (subclass) with keys "west", "south", "east", "north", and optionally "crs". + """ + return BBoxDict.from_any(x=x, crs=crs) + + +def url_join(root_url: str, path: str): + """Join a base url and sub path properly.""" + return urljoin(root_url.rstrip("/") + "/", path.lstrip("/")) + + +def clip(x: float, min: float, max: float) -> float: + """Clip given value between minimum and maximum value""" + return min if x < min else (x if x < max else max) + + +class SimpleProgressBar: + """Simple ASCII-based progress bar helper.""" + + __slots__ = ["width", "bar", "fill", "left", "right"] + + def __init__(self, width: int = 40, *, bar: str = "#", fill: str = "-", left: str = "[", right: str = "]"): + self.width = int(width) + self.bar = bar[0] + self.fill = fill[0] + self.left = left + self.right = right + + def get(self, fraction: float) -> str: + width = self.width - len(self.left) - len(self.right) + bar = self.bar * int(round(width * clip(fraction, min=0, max=1))) + return f"{self.left}{bar:{self.fill}<{width}s}{self.right}" + + +def normalize_crs(crs: Any, *, use_pyproj: bool = True) -> Union[None, int, str]: + """ + Normalize the given value (describing a CRS or Coordinate Reference System) + to an openEO compatible EPSG code (int) or WKT2 CRS string. + + At minimum, the following input values are handled: + + - an integer value (e.g. ``4326``) is interpreted as an EPSG code + - a string that just contains an integer (e.g. ``"4326"``) + or with and additional ``"EPSG:"`` prefix (e.g. ``"EPSG:4326"``) + will also be interpreted as an EPSG value + + Additional support and behavior depends on the availability of the ``pyproj`` library: + + - When available, it will be used for parsing and validation: + everything supported by `pyproj.CRS.from_user_input `_ is allowed. + See the ``pyproj`` docs for more details. + - Otherwise, some best effort validation is done: + EPSG looking integer or string values will be parsed as such as discussed above. + Other strings will be assumed to be WKT2 already. + Other data structures will not be accepted. + + :param crs: value that encodes a coordinate reference system, typically just an int (EPSG code) or string (authority string). + If the ``pyproj`` library is available, everything supported by it is allowed. + + :param use_pyproj: whether ``pyproj`` should be leveraged at all + (mainly useful for testing the "no pyproj available" code path) + + :return: EPSG code as int, or WKT2 string. Or None if input was empty. + + :raises ValueError: + When the given CRS data can not be parsed/converted/normalized. + + """ + if crs in (None, "", {}): + return None + + if pyproj and use_pyproj: + try: + # (if available:) let pyproj do the validation/parsing + crs_obj = pyproj.CRS.from_user_input(crs) + # Convert back to EPSG int or WKT2 string + crs = crs_obj.to_epsg() or crs_obj.to_wkt() + except pyproj.ProjError as e: + raise ValueError(f"Failed to normalize CRS data with pyproj: {crs!r}") from e + else: + # Best effort simple validation/normalization + if isinstance(crs, int) and crs > 0: + # Assume int is already valid EPSG code + pass + elif isinstance(crs, str): + # Parse as EPSG int code if it looks like that, + # otherwise: leave it as-is, assuming it is a valid WKT2 CRS string + if re.match(r"^(epsg:)?\d+$", crs.strip(), flags=re.IGNORECASE): + crs = int(crs.split(":")[-1]) + elif "GEOGCRS[" in crs: + # Very simple WKT2 CRS detection heuristic + logger.warning(f"Assuming this is a valid WK2 CRS string: {repr_truncate(crs)}") + else: + raise ValueError(f"Can not normalize CRS string {repr_truncate(crs)}") + else: + raise ValueError(f"Can not normalize CRS data {type(crs)}") + + return crs diff --git a/machine_learning.html b/machine_learning.html new file mode 100644 index 000000000..851f13b93 --- /dev/null +++ b/machine_learning.html @@ -0,0 +1,242 @@ + + + + + + + + Machine Learning — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Machine Learning

    +
    +

    Warning

    +

    This API and documentation is experimental, +under heavy development and subject to change.

    +
    +
    +

    New in version 0.10.0.

    +
    +
    +

    Random Forest based Classification and Regression

    +

    openEO defines a couple of processes for random forest based machine learning +for Earth Observation applications:

    +
      +
    • fit_class_random_forest for training a random forest based classification model

    • +
    • fit_regr_random_forest for training a random forest based regression model

    • +
    • predict_random_forest for inference/prediction

    • +
    +

    The openEO Python Client library provides the necessary functionality to set up +and execute training and inference workflows.

    +
    +

    Training

    +

    Let’s focus on training a classification model, where we try to predict +a class like a land cover type or crop type based on predictors +we derive from EO data. +For example, assume we have a GeoJSON FeatureCollection +of sample points and a corresponding classification target value as follows:

    +
    feature_collection = {"type": "FeatureCollection", "features": [
    +    {
    +        "type": "Feature",
    +        "properties": {"id": "b3dw-wd23", "target": 3},
    +        "geometry": {"type": "Point", "coordinates": [3.4, 51.1]}
    +    },
    +    {
    +        "type": "Feature",
    +        "properties": {"id": "r8dh-3jkd", "target": 5},
    +        "geometry": {"type": "Point", "coordinates": [3.6, 51.2]}
    +    },
    +    ...
    +
    +
    +
    +

    Note

    +

    Confusingly, the concept “feature” has somewhat conflicting meanings +for different audiences. GIS/EO people use “feature” to refer to the “rows” +in this feature collection. +For the machine learning community however, the properties (the “columns”) +are the features. +To avoid confusion in this discussion we will avoid the term “feature” +and instead use “sample point” for the former and “predictor” for the latter.

    +
    +

    We first build a datacube of “predictor” bands. +For simplicity, we will just use the raw B02/B03/B04 band values here +and use the temporal mean to eliminate the time dimension:

    +
    cube = connection.load_collection(
    +    "SENTINEL2",
    +    temporal_extent=[start, end],
    +    spatial_extent=bbox,
    +    bands=["B02", "B03", "B04"]
    +)
    +cube = cube.reduce_dimension(dimension="t", reducer="mean")
    +
    +
    +

    We now use aggregate_spatial to sample this raster data cube at the sample points +and get a vector cube where we have the temporal mean of the B02/B03/B04 bands as predictor values:

    +
    predictors = cube.aggregate_spatial(feature_collection, reducer="mean")
    +
    +
    +

    We can now train a Random Forest model by calling the +fit_class_random_forest() method on the predictor vector cube +and passing the original target class data:

    +
    model = predictors.fit_class_random_forest(
    +    target=feature_collection,
    +)
    +# Save the model as a batch job result asset
    +# so that we can load it in another job.
    +model = model.save_ml_model()
    +
    +
    +

    Finally execute this whole training flow as a batch job:

    +
    training_job = model.create_job()
    +training_job.start_and_wait()
    +
    +
    +
    +
    +

    Inference

    +

    When the batch job finishes successfully, the trained model can then be used +with the predict_random_forest process on the raster data cube +(or another cube with the same band structure) to classify all the pixels.

    +

    Technically, the openEO predict_random_forest process has to be used as a reducer function +inside a reduce_dimension call, but the openEO Python client library makes it +a bit easier by providing a predict_random_forest() method +directly on the DataCube class, so that you can just do:

    +
    predicted = cube.predict_random_forest(
    +    model=training_job.job_id,
    +    dimension="bands"
    +)
    +
    +predicted.download("predicted.GTiff")
    +
    +
    +

    We specified the model here by batch job id (string), +but it can also be specified in other ways: +as BatchJob instance, +as URL to the corresponding STAC Item that implements the ml-model extension, +or as MlModel instance (e.g. loaded through +load_ml_model()).

    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..b71bd0b1ceb51a21a1b794d5e1ce348b7b79c19e GIT binary patch literal 6176 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 literal 0 HcmV?d00001 diff --git a/process_mapping.html b/process_mapping.html new file mode 100644 index 000000000..a56045559 --- /dev/null +++ b/process_mapping.html @@ -0,0 +1,607 @@ + + + + + + + + openEO Process Mapping — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    openEO Process Mapping

    +

    The table below maps openEO processes to the corresponding +method or function in the openEO Python Client Library.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    openEO process

    openEO Python Client Method

    absolute

    ProcessBuilder.absolute(), absolute()

    add

    ProcessBuilder.__add__(), ProcessBuilder.__radd__(), ProcessBuilder.add(), add(), DataCube.add(), DataCube.__add__(), DataCube.__radd__()

    add_dimension

    ProcessBuilder.add_dimension(), add_dimension(), DataCube.add_dimension()

    aggregate_spatial

    ProcessBuilder.aggregate_spatial(), aggregate_spatial(), DataCube.aggregate_spatial()

    aggregate_spatial_window

    ProcessBuilder.aggregate_spatial_window(), aggregate_spatial_window(), DataCube.aggregate_spatial_window()

    aggregate_temporal

    ProcessBuilder.aggregate_temporal(), aggregate_temporal(), DataCube.aggregate_temporal()

    aggregate_temporal_period

    ProcessBuilder.aggregate_temporal_period(), aggregate_temporal_period(), DataCube.aggregate_temporal_period()

    all

    ProcessBuilder.all(), all()

    and

    DataCube.logical_and(), DataCube.__and__()

    and_

    ProcessBuilder.and_(), and_()

    anomaly

    ProcessBuilder.anomaly(), anomaly()

    any

    ProcessBuilder.any(), any()

    apply

    ProcessBuilder.apply(), apply(), DataCube.apply()

    apply_dimension

    ProcessBuilder.apply_dimension(), apply_dimension(), DataCube.apply_dimension()

    apply_kernel

    ProcessBuilder.apply_kernel(), apply_kernel(), DataCube.apply_kernel()

    apply_neighborhood

    ProcessBuilder.apply_neighborhood(), apply_neighborhood(), DataCube.apply_neighborhood()

    arccos

    ProcessBuilder.arccos(), arccos()

    arcosh

    ProcessBuilder.arcosh(), arcosh()

    arcsin

    ProcessBuilder.arcsin(), arcsin()

    arctan

    ProcessBuilder.arctan(), arctan()

    arctan2

    ProcessBuilder.arctan2(), arctan2()

    ard_normalized_radar_backscatter

    ProcessBuilder.ard_normalized_radar_backscatter(), ard_normalized_radar_backscatter(), DataCube.ard_normalized_radar_backscatter()

    ard_surface_reflectance

    ProcessBuilder.ard_surface_reflectance(), ard_surface_reflectance(), DataCube.ard_surface_reflectance()

    array_append

    ProcessBuilder.array_append(), array_append()

    array_apply

    ProcessBuilder.array_apply(), array_apply()

    array_concat

    ProcessBuilder.array_concat(), array_concat()

    array_contains

    ProcessBuilder.array_contains(), array_contains()

    array_create

    ProcessBuilder.array_create(), array_create()

    array_create_labeled

    ProcessBuilder.array_create_labeled(), array_create_labeled()

    array_element

    ProcessBuilder.__getitem__(), ProcessBuilder.array_element(), array_element()

    array_filter

    ProcessBuilder.array_filter(), array_filter()

    array_find

    ProcessBuilder.array_find(), array_find()

    array_find_label

    ProcessBuilder.array_find_label(), array_find_label()

    array_interpolate_linear

    ProcessBuilder.array_interpolate_linear(), array_interpolate_linear()

    array_labels

    ProcessBuilder.array_labels(), array_labels()

    array_modify

    ProcessBuilder.array_modify(), array_modify()

    arsinh

    ProcessBuilder.arsinh(), arsinh()

    artanh

    ProcessBuilder.artanh(), artanh()

    atmospheric_correction

    ProcessBuilder.atmospheric_correction(), atmospheric_correction(), DataCube.atmospheric_correction()

    between

    ProcessBuilder.between(), between()

    ceil

    ProcessBuilder.ceil(), ceil()

    climatological_normal

    ProcessBuilder.climatological_normal(), climatological_normal()

    clip

    ProcessBuilder.clip(), clip()

    cloud_detection

    ProcessBuilder.cloud_detection(), cloud_detection()

    constant

    ProcessBuilder.constant(), constant()

    cos

    ProcessBuilder.cos(), cos()

    cosh

    ProcessBuilder.cosh(), cosh()

    count

    ProcessBuilder.count(), count(), DataCube.count_time()

    create_raster_cube

    ProcessBuilder.create_raster_cube(), create_raster_cube()

    cummax

    ProcessBuilder.cummax(), cummax()

    cummin

    ProcessBuilder.cummin(), cummin()

    cumproduct

    ProcessBuilder.cumproduct(), cumproduct()

    cumsum

    ProcessBuilder.cumsum(), cumsum()

    date_shift

    ProcessBuilder.date_shift(), date_shift()

    dimension_labels

    ProcessBuilder.dimension_labels(), dimension_labels(), DataCube.dimension_labels()

    divide

    ProcessBuilder.__truediv__(), ProcessBuilder.__rtruediv__(), ProcessBuilder.divide(), divide(), DataCube.divide(), DataCube.__truediv__(), DataCube.__rtruediv__()

    drop_dimension

    ProcessBuilder.drop_dimension(), drop_dimension(), DataCube.drop_dimension()

    e

    ProcessBuilder.e(), e()

    eq

    ProcessBuilder.__eq__(), ProcessBuilder.eq(), eq(), DataCube.__eq__()

    exp

    ProcessBuilder.exp(), exp()

    extrema

    ProcessBuilder.extrema(), extrema()

    filter_bands

    ProcessBuilder.filter_bands(), filter_bands(), DataCube.filter_bands()

    filter_bbox

    ProcessBuilder.filter_bbox(), filter_bbox(), DataCube.filter_bbox()

    filter_labels

    ProcessBuilder.filter_labels(), filter_labels()

    filter_spatial

    ProcessBuilder.filter_spatial(), filter_spatial(), DataCube.filter_spatial()

    filter_temporal

    ProcessBuilder.filter_temporal(), filter_temporal(), DataCube.filter_temporal()

    first

    ProcessBuilder.first(), first()

    fit_class_random_forest

    ProcessBuilder.fit_class_random_forest(), fit_class_random_forest(), VectorCube.fit_class_random_forest()

    fit_curve

    ProcessBuilder.fit_curve(), fit_curve(), DataCube.fit_curve()

    fit_regr_random_forest

    ProcessBuilder.fit_regr_random_forest(), fit_regr_random_forest(), VectorCube.fit_regr_random_forest()

    flatten_dimensions

    ProcessBuilder.flatten_dimensions(), flatten_dimensions(), DataCube.flatten_dimensions()

    floor

    ProcessBuilder.floor(), floor()

    ge

    ProcessBuilder.__ge__(), DataCube.__ge__()

    gt

    ProcessBuilder.__gt__(), ProcessBuilder.gt(), gt(), DataCube.__gt__()

    gte

    ProcessBuilder.gte(), gte()

    if_

    ProcessBuilder.if_(), if_()

    inspect

    ProcessBuilder.inspect(), inspect()

    int

    ProcessBuilder.int(), int()

    is_infinite

    ProcessBuilder.is_infinite(), is_infinite()

    is_nan

    ProcessBuilder.is_nan(), is_nan()

    is_nodata

    ProcessBuilder.is_nodata(), is_nodata()

    is_valid

    ProcessBuilder.is_valid(), is_valid()

    last

    ProcessBuilder.last(), last()

    le

    DataCube.__le__()

    linear_scale_range

    ProcessBuilder.linear_scale_range(), linear_scale_range(), DataCube.linear_scale_range()

    ln

    ProcessBuilder.ln(), ln(), DataCube.ln()

    load_collection

    ProcessBuilder.load_collection(), load_collection(), DataCube.load_collection(), Connection.load_collection()

    load_geojson

    VectorCube.load_geojson(), Connection.load_geojson()

    load_ml_model

    ProcessBuilder.load_ml_model(), load_ml_model(), MlModel.load_ml_model()

    load_result

    ProcessBuilder.load_result(), load_result(), Connection.load_result()

    load_stac

    Connection.load_stac()

    load_uploaded_files

    ProcessBuilder.load_uploaded_files(), load_uploaded_files()

    log

    ProcessBuilder.log(), log(), DataCube.logarithm(), DataCube.log2(), DataCube.log10()

    lt

    ProcessBuilder.__lt__(), ProcessBuilder.lt(), lt(), DataCube.__lt__()

    lte

    ProcessBuilder.__le__(), ProcessBuilder.lte(), lte()

    mask

    ProcessBuilder.mask(), mask(), DataCube.mask()

    mask_polygon

    ProcessBuilder.mask_polygon(), mask_polygon(), DataCube.mask_polygon()

    max

    ProcessBuilder.max(), max(), DataCube.max_time()

    mean

    ProcessBuilder.mean(), mean(), DataCube.mean_time()

    median

    ProcessBuilder.median(), median(), DataCube.median_time()

    merge_cubes

    ProcessBuilder.merge_cubes(), merge_cubes(), DataCube.merge_cubes()

    min

    ProcessBuilder.min(), min(), DataCube.min_time()

    mod

    ProcessBuilder.mod(), mod()

    multiply

    ProcessBuilder.__mul__(), ProcessBuilder.__rmul__(), ProcessBuilder.__neg__(), ProcessBuilder.multiply(), multiply(), DataCube.multiply(), DataCube.__neg__(), DataCube.__mul__(), DataCube.__rmul__()

    nan

    ProcessBuilder.nan(), nan()

    ndvi

    ProcessBuilder.ndvi(), ndvi(), DataCube.ndvi()

    neq

    ProcessBuilder.__ne__(), ProcessBuilder.neq(), neq(), DataCube.__ne__()

    normalized_difference

    ProcessBuilder.normalized_difference(), normalized_difference(), DataCube.normalized_difference()

    not

    DataCube.__invert__()

    not_

    ProcessBuilder.not_(), not_()

    or

    DataCube.logical_or(), DataCube.__or__()

    or_

    ProcessBuilder.or_(), or_()

    order

    ProcessBuilder.order(), order()

    pi

    ProcessBuilder.pi(), pi()

    power

    ProcessBuilder.__pow__(), ProcessBuilder.power(), power(), DataCube.__rpow__(), DataCube.__pow__(), DataCube.power()

    predict_curve

    ProcessBuilder.predict_curve(), predict_curve(), DataCube.predict_curve()

    predict_random_forest

    ProcessBuilder.predict_random_forest(), predict_random_forest(), DataCube.predict_random_forest()

    product

    ProcessBuilder.product(), product()

    quantiles

    ProcessBuilder.quantiles(), quantiles()

    rearrange

    ProcessBuilder.rearrange(), rearrange()

    reduce_dimension

    ProcessBuilder.reduce_dimension(), reduce_dimension(), DataCube.reduce_dimension()

    reduce_spatial

    ProcessBuilder.reduce_spatial(), reduce_spatial()

    rename_dimension

    ProcessBuilder.rename_dimension(), rename_dimension(), DataCube.rename_dimension()

    rename_labels

    ProcessBuilder.rename_labels(), rename_labels(), DataCube.rename_labels()

    resample_cube_spatial

    ProcessBuilder.resample_cube_spatial(), resample_cube_spatial()

    resample_cube_temporal

    ProcessBuilder.resample_cube_temporal(), resample_cube_temporal(), DataCube.resample_cube_temporal()

    resample_spatial

    ProcessBuilder.resample_spatial(), resample_spatial(), DataCube.resample_spatial()

    resolution_merge

    DataCube.resolution_merge()

    round

    ProcessBuilder.round(), round()

    run_udf

    ProcessBuilder.run_udf(), run_udf(), VectorCube.run_udf()

    run_udf_externally

    ProcessBuilder.run_udf_externally(), run_udf_externally()

    sar_backscatter

    ProcessBuilder.sar_backscatter(), sar_backscatter(), DataCube.sar_backscatter()

    save_ml_model

    ProcessBuilder.save_ml_model(), save_ml_model()

    save_result

    ProcessBuilder.save_result(), save_result(), VectorCube.save_result(), DataCube.save_result()

    sd

    ProcessBuilder.sd(), sd()

    sgn

    ProcessBuilder.sgn(), sgn()

    sin

    ProcessBuilder.sin(), sin()

    sinh

    ProcessBuilder.sinh(), sinh()

    sort

    ProcessBuilder.sort(), sort()

    sqrt

    ProcessBuilder.sqrt(), sqrt()

    subtract

    ProcessBuilder.__sub__(), ProcessBuilder.__rsub__(), ProcessBuilder.subtract(), subtract(), DataCube.subtract(), DataCube.__sub__(), DataCube.__rsub__()

    sum

    ProcessBuilder.sum(), sum()

    tan

    ProcessBuilder.tan(), tan()

    tanh

    ProcessBuilder.tanh(), tanh()

    text_begins

    ProcessBuilder.text_begins(), text_begins()

    text_concat

    ProcessBuilder.text_concat(), text_concat()

    text_contains

    ProcessBuilder.text_contains(), text_contains()

    text_ends

    ProcessBuilder.text_ends(), text_ends()

    trim_cube

    ProcessBuilder.trim_cube(), trim_cube()

    unflatten_dimension

    ProcessBuilder.unflatten_dimension(), unflatten_dimension(), DataCube.unflatten_dimension()

    variance

    ProcessBuilder.variance(), variance()

    vector_buffer

    ProcessBuilder.vector_buffer(), vector_buffer()

    vector_to_random_points

    ProcessBuilder.vector_to_random_points(), vector_to_random_points()

    vector_to_regular_points

    ProcessBuilder.vector_to_regular_points(), vector_to_regular_points()

    xor

    ProcessBuilder.xor(), xor()

    +

    (Table autogenerated on 2023-08-07)

    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/processes.html b/processes.html new file mode 100644 index 000000000..96089b2cc --- /dev/null +++ b/processes.html @@ -0,0 +1,537 @@ + + + + + + + + Working with processes — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    Working with processes

    +

    In openEO, a process is an operation that performs a specific task on +a set of parameters and returns a result. +For example, with the add process you can add two numbers, in openEO’s JSON notation:

    +
    {
    +    "process_id": "add",
    +    "arguments": {"x": 3, "y": 5}
    +}
    +
    +
    +

    A process is similar to a function in common programming languages, +and likewise, multiple processes can be combined or chained together +into new, more complex operations.

    +
    +

    A bit of terminology

    +

    A pre-defined process is a process provided out of the box by a given back-end. +These are often the centrally defined openEO processes, +such as common mathematical (sum, divide, sqrt, …), +statistical (mean, max, …) and +image processing (mask, apply_kernel, …) +operations. +Back-ends are expected to support most of these standard ones, +but are free to pre-define additional ones too.

    +

    Processes can be combined into a larger pipeline, parameterized +and stored on the back-end as a so called user-defined process. +This allows you to build a library of reusable building blocks +that can be be inserted easily in multiple other places. +See User-Defined Processes for more information.

    +

    How processes are combined into a larger unit +is internally represented by a so-called process graph. +It describes how the inputs and outputs of processes +should be linked together. +A user of the Python client should normally not worry about +the details of a process graph structure, as most of these aspects +are hidden behind regular Python functions, classes and methods.

    +
    +
    +

    Using common pre-defined processes

    +

    The listing of pre-defined processes provided by a back-end +can be inspected with list_processes(). +For example, to get a list of the process names (process ids):

    +
    >>> process_ids = [process["id"] for process in connection.list_processes()]
    +>>> print(process_ids[:16])
    +['arccos', 'arcosh', 'power', 'last', 'subtract', 'not', 'cosh', 'artanh',
    +'is_valid', 'first', 'median', 'eq', 'absolute', 'arctan2', 'divide','is_nan']
    +
    +
    +

    More information about the processes, like a description +or expected parameters, can be queried like that, +but it is often easier to look them up on the +official openEO process documentation

    +

    A single pre-defined process can be retrieved with +describe_process().

    +
    +

    Convenience methods

    +

    Most of the important pre-defined processes are covered directly by methods +on classes like DataCube or +VectorCube.

    +
    +

    See also

    +

    See openEO Process Mapping for a mapping of openEO processes +the corresponding methods in the openEO Python Client library.

    +
    +

    For example, to apply the filter_temporal process to a raster data cube:

    +
    cube = cube.filter_temporal("2020-02-20", "2020-06-06")
    +
    +
    +

    Being regular Python methods, you get usual function call features +you’re accustomed to: default values, keyword arguments, kwargs usage, … +For example, to use a bounding box dictionary with kwargs-expansion:

    +
    bbox = {
    +    "west": 5.05, "south": 51.20, "east": 5.10, "north": 51.23
    +}
    +cube = cube.filter_bbox(**bbox)
    +
    +
    +

    Note that some methods try to be more flexible and convenient to use +than how the official process definition prescribes. +For example, the filter_temporal process expects an extent array +with 2 items (the start and end date), +but you can call the corresponding client method in multiple equivalent ways:

    +
    cube.filter_temporal("2019-07-01", "2019-08-01")
    +cube.filter_temporal(["2019-07-01", "2019-08-01"])
    +cube.filter_temporal(extent=["2019-07-01", "2019-08-01"])
    +cube.filter_temporal(start_date="2019-07-01", end_date="2019-08-01"])
    +
    +
    +
    +
    +

    Advanced argument tweaking

    +
    +

    New in version 0.10.1.

    +
    +

    In some situations, you may want to finetune what the (convenience) methods generate. +For example, you want to play with non-standard, experimental arguments, +or there is a problem with a automatic argument handling/conversion feature.

    +

    You can tweak the arguments of your current result node as follows. +Say, we want to add some non-standard feature_flags argument to the load_collection process node. +We first get the current result node with result_node() and use update_arguments() to add an additional argument to it:

    +
    # `Connection.load_collection` does not support `feature_flags` argument
    +cube = connection.load_collection(...)
    +
    +# Add `feature_flag` argument `load_collection` process graph node
    +cube.result_node().update_arguments(feature_flags="rXPk")
    +
    +# The resulting process graph will now contain this non-standard argument:
    +#     {
    +#         "process_id": "load_collection",
    +#         "arguments": {
    +#             ...
    +#             "feature_flags": "rXPk",
    +
    +
    +
    +
    +
    +

    Generic API for adding processes

    +

    An openEO back-end may offer processes that are not part of the core API, +or the client may not (yet) have a corresponding method +for a process that you wish to use. +In that case, you can fall back to a more generic API +that allows you to add processes directly.

    +
    +

    Basics

    +

    To add a simple process to the graph, use +the process() method +on a DataCube. +You have to specify the process id and arguments +(as a single dictionary or through keyword arguments **kwargs). +It will return a new DataCube with the new process appended +to the internal process graph.

    +

    A very simple example using the mean process and a +literal list in an arguments dictionary:

    +
    arguments= {
    +    "data": [1, 3, -1]
    +}
    +res = cube.process("mean", arguments)
    +
    +
    +

    or equivalently, leveraging keyword arguments:

    +
    res = cube.process("mean", data=[1, 3, -1])
    +
    +
    +
    +
    +

    Passing data cube arguments

    +

    The example above is a bit convoluted however in the sense that +you start from a given data cube cube, you add a mean process +that works on a given data array, while completely ignoring the original cube. +In reality you typically want to apply the process on the cube. +This is possible by passing a data cube object directly as argument, +for example with the ndvi process that at least expects +a data cube as data argument

    +
    res = cube.process("ndvi", data=cube)
    +
    +
    +

    Note that you have to specify cube twice here: +a first time to call the method and a second time as argument. +Moreover, it requires you to define a Python variable for the data +cube, which is annoying if you want to use a chained expressions. +To solve these issues, you can use the THIS +constant as symbolic reference to the “current” cube:

    +
    from openeo.rest.datacube import THIS
    +
    +res = (
    +    cube
    +        .process("filter_bands", data=THIS)
    +        .process("mask", data=THIS, mask=mask)
    +        .process("ndvi", data=THIS)
    +)
    +
    +
    +
    +
    +

    Passing results from other process calls as arguments

    +

    Another use case of generically applying (custom) processes is +passing a process result as argument to another process working on a cube. +For example, assume we have a custom process load_my_vector_cube +to load a vector cube from an online resource. +We can use this vector cube as geometry for +DataCube.aggregate_spatial() +using openeo.processes.process() as follows:

    +
    from openeo.processes import process
    +
    +res = cube.aggregate_spatial(
    +    geometries=process("load_my_vector_cube", url="https://geo.example/features.db"),
    +    reducer="mean"
    +)
    +
    +
    +
    +
    +
    +

    Processes with child “callbacks”

    +

    Some openEO processes expect some kind of sub-process +to be invoked on a subset or slice of the datacube. +For example:

    +
      +
    • process apply requires a transformation that will be applied +to each pixel in the cube (separately), e.g. in pseudocode

      +
      cube.apply(
      +    given a pixel value
      +    => scale it with factor 0.01
      +)
      +
      +
      +
    • +
    • process reduce_dimension requires an aggregation function to convert +an array of pixel values (along a given dimension) to a single value, +e.g. in pseudocode

      +
      cube.reduce_dimension(
      +    given a pixel timeseries (array) for a (x,y)-location
      +    => temporal mean of that array
      +)
      +
      +
      +
    • +
    • process aggregate_spatial requires a function to aggregate the values +in one or more geometries

    • +
    +

    These transformation functions are usually called “callbacks” +because instead of being called explicitly by the user, +they are called and managed by their “parent” process +(the apply, reduce_dimension and aggregate_spatial in the examples)

    +

    The openEO Python Client Library currently provides a couple of DataCube methods +that expect such a callback, most commonly:

    + +

    The openEO Python Client Library supports several ways +to specify the desired callback for these functions:

    + +
    +

    Callback as string

    +

    The easiest way is passing a process name as a string, +for example:

    +
    # Take the absolute value of each pixel
    +cube.apply("absolute")
    +
    +# Reduce a cube along the temporal dimension by taking the maximum value
    +cube.reduce_dimension(reducer="max", dimension="t")
    +
    +
    +

    This approach is only possible if the desired transformation is available +as a single process. If not, use one of the methods below.

    +

    It’s also important to note that the “signature” of the provided callback process +should correspond properly with what the parent process expects. +For example: apply requires a callback process that receives a +number and returns one (like absolute or sqrt), +while reduce_dimension requires a callback process that receives +an array of numbers and returns a single number (like max or mean).

    +
    +
    +

    Callback as a callable

    +

    You can also specify the callback as a “callable”: +which is a fancy word for a Python object that can be called, +but just think of it like a function you can call.

    +

    You can use a regular Python function, like this:

    +
    def transform(x):
    +    return x * 2 + 3
    +
    +cube.apply(transform)
    +
    +
    +

    or, more compactly, a “lambda” +(a construct in Python to create anonymous inline functions):

    +
    cube.apply(lambda x: x * 2 + 3)
    +
    +
    +

    The openEO Python Client Library implements most of the official openEO processes as +functions in the “openeo.processes” module, +which can be used directly as callback:

    +
    from openeo.processes import absolute, max
    +
    +cube.apply(absolute)
    +cube.reduce_dimension(reducer=max, dimension="t")
    +
    +
    +

    The argument that will be passed to all these callback functions is +a ProcessBuilder instance. +This is a helper object with predefined methods for all standard openEO processes, +allowing to use an object oriented coding style to define the callback. +For example:

    +
    from openeo.processes import ProcessBuilder
    +
    +def avg(data: ProcessBuilder):
    +    return data.mean()
    +
    +cube.reduce_dimension(reducer=avg, dimension="t")
    +
    +
    +

    These methods also return ProcessBuilder objects, +which also allows writing callbacks in chained fashion:

    +
    cube.apply(
    +    lambda x: x.absolute().cos().add(y=1.23)
    +)
    +
    +
    +

    All this gives a lot of flexibility to define callbacks compactly +in a desired coding style. +The following examples result in the same callback:

    +
    from openeo.processes import ProcessBuilder, mean, cos, add
    +
    +# Chained methods
    +cube.reduce_dimension(
    +    lambda data: data.mean().cos().add(y=1.23),
    +    dimension="t"
    +)
    +
    +# Functions
    +cube.reduce_dimension(
    +    lambda data: add(x=cos(mean(data)), y=1.23),
    +    dimension="t"
    +)
    +
    +# Mixing methods, functions and operators
    +cube.reduce_dimension(
    +    lambda data: cos(data.mean())) + 1.23,
    +    dimension="t"
    +)
    +
    +
    +
    +

    Caveats

    +

    Specifying callbacks through Python functions (or lambdas) +looks intuitive and straightforward, but it should be noted +that not everything is allowed in these functions. +You should just limit yourself to calling +openeo.processes functions, +ProcessBuilder methods +and basic math operators. +Don’t call functions from other libraries like numpy or scipy. +Don’t use Python control flow statements like if/else constructs +or for loops.

    +

    The reason for this is that the openEO Python Client Library +does not translate the function source code itself +to an openEO process graph. +Instead, when building the openEO process graph, +it passes a special object to the function +and keeps track of which openeo.processes functions +were called to assemble the corresponding process graph. +If you use control flow statements or use numpy functions for example, +this procedure will incorrectly detect what you want to do in the callback.

    +

    For example, if you mistakenly use the Python builtin sum() function +in a callback instead of openeo.processes.sum(), you will run into trouble. +Luckily the openEO Python client Library should raise an error if it detects that:

    +
    >>> # Wrongly using builtin `sum` function
    +>>> cube.reduce_dimension(dimension="t", reducer=sum)
    +RuntimeError: Exceeded ProcessBuilder iteration limit.
    +Are you mistakenly using a builtin like `sum()` or `all()` in a callback
    +instead of the appropriate helpers from `openeo.processes`?
    +
    +>>> # Explicit usage of `openeo.processes.sum`
    +>>> import openeo.processes
    +>>> cube.reduce_dimension(dimension="t", reducer=openeo.processes.sum)
    +<openeo.rest.datacube.DataCube at 0x7f6505a40d00>
    +
    +
    +
    +
    +
    +

    Callback as PGNode

    +

    You can also pass a PGNode object as callback.

    +
    +

    Attention

    +

    This approach should generally not be used in normal use cases. +The other options discussed above should be preferred. +It’s mainly intended for internal use and an occasional, advanced use case. +It requires in-depth knowledge of the openEO API +and openEO Python Client Library to construct correctly.

    +
    +

    Some examples:

    +
    from openeo.internal.graph_building import PGNode
    +
    +cube.apply(PGNode(
    +    "add",
    +    x=PGNode(
    +        "cos",
    +        x=PGNode("absolute", x={"from_parameter": "x"})
    +    ),
    +    y=1.23
    +))
    +
    +cube.reduce_dimension(
    +    reducer=PGNode("max", data={"from_parameter": "data"}),
    +    dimension="bands"
    +)
    +
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 000000000..f9ae484ae --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,260 @@ + + + + + + + Python Module Index — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + + +

    Python Module Index

    + +
    + o +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    + o
    + openeo +
        + openeo.api.logs +
        + openeo.api.process +
        + openeo.extra.job_management +
        + openeo.extra.spectral_indices +
        + openeo.internal.graph_building +
        + openeo.metadata +
        + openeo.processes +
        + openeo.rest._datacube +
        + openeo.rest.connection +
        + openeo.rest.conversions +
        + openeo.rest.datacube +
        + openeo.rest.graph_building +
        + openeo.rest.job +
        + openeo.rest.mlmodel +
        + openeo.rest.udp +
        + openeo.rest.userfile +
        + openeo.rest.vectorcube +
        + openeo.udf.debug +
        + openeo.udf.run_code +
        + openeo.udf.structured_data +
        + openeo.udf.udf_data +
        + openeo.udf.udf_signatures +
        + openeo.udf.xarraydatacube +
        + openeo.util +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 000000000..563e321c7 --- /dev/null +++ b/search.html @@ -0,0 +1,144 @@ + + + + + + + Search — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Search

    + + + + +

    + Searching for multiple words only shows matches that contain + all words. +

    + + +
    + + + +
    + + + +
    + +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 000000000..e0f5fbde7 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["api", "api-processbuilder", "api-processes", "auth", "basics", "batch_jobs", "best_practices", "changelog", "configuration", "cookbook/ard", "cookbook/index", "cookbook/job_manager", "cookbook/localprocessing", "cookbook/sampling", "cookbook/spectral_indices", "cookbook/tricks", "cookbook/udp_sharing", "data_access", "datacube_construction", "development", "index", "installation", "machine_learning", "process_mapping", "processes", "udf", "udp"], "filenames": ["api.rst", "api-processbuilder.rst", "api-processes.rst", "auth.rst", "basics.rst", "batch_jobs.rst", "best_practices.rst", "changelog.md", "configuration.rst", "cookbook/ard.rst", "cookbook/index.rst", "cookbook/job_manager.rst", "cookbook/localprocessing.rst", "cookbook/sampling.rst", "cookbook/spectral_indices.rst", "cookbook/tricks.rst", "cookbook/udp_sharing.rst", "data_access.rst", "datacube_construction.rst", "development.rst", "index.rst", "installation.rst", "machine_learning.rst", "process_mapping.rst", "processes.rst", "udf.rst", "udp.rst"], "titles": ["API (General)", "<no title>", "API: openeo.processes", "Authentication and Account Management", "Getting Started", "Batch Jobs", "Best practices, coding style and general tips", "Changelog", "Configuration", "Analysis Ready Data generation", "openEO CookBook", "Multi Backend Job Manager", "Client-side (local) processing", "Dataset sampling", "Spectral Indices", "Miscellaneous tips and tricks", "Sharing of user-defined processes", "Finding and loading data", "DataCube construction", "Development and maintenance", "openEO Python Client", "Installation", "Machine Learning", "openEO Process Mapping", "Working with processes", "User-Defined Functions (UDF) explained", "User-Defined Processes"], "terms": {"The": [0, 1, 2, 3, 4, 5, 7, 8, 9, 11, 12, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26], "tri": [0, 4, 7, 19], "provid": [0, 2, 3, 4, 5, 7, 9, 11, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26], "an": [0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 18, 19, 20, 21, 24, 26], "opinion": [0, 6], "python": [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 15, 16, 17, 19, 21, 22, 23, 24, 25, 26], "interact": [0, 1, 2, 4, 5, 7, 8, 15, 20, 21, 25], "back": [0, 1, 2, 5, 7, 8, 12, 16, 17, 18, 20, 24, 25, 26], "end": [0, 1, 2, 5, 7, 8, 12, 16, 18, 19, 20, 22, 24, 25, 26], "It": [0, 2, 3, 4, 5, 6, 12, 13, 14, 16, 17, 18, 19, 20, 21, 24, 25, 26], "": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 24, 26], "aim": [0, 25], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26], "hide": [0, 7, 26], "some": [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 14, 16, 17, 19, 21, 24, 25, 26], "detail": [0, 2, 3, 4, 5, 6, 7, 8, 16, 17, 18, 21, 24, 25, 26], "us": [0, 1, 2, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 25], "web": [0, 3, 4, 5, 7, 9, 19, 26], "servic": [0, 2, 3, 7, 17, 26], "so": [0, 2, 3, 4, 5, 9, 13, 16, 19, 21, 22, 24, 25, 26], "user": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 17, 18, 19, 20, 24], "can": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26], "produc": [0, 18, 25], "concis": 0, "readabl": [0, 6, 7], "code": [0, 2, 4, 7, 12, 13, 20, 21, 24, 25], "want": [0, 1, 2, 3, 4, 5, 12, 13, 14, 17, 18, 19, 21, 24, 25, 26], "lower": [0, 2, 6, 15], "have": [0, 2, 3, 4, 5, 9, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 24, 25, 26], "more": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 24, 25], "control": [0, 2, 3, 5, 6, 8, 24, 25], "class": [0, 1, 4, 5, 6, 7, 11, 20, 22, 24, 26], "url": [0, 2, 4, 7, 8, 10, 12, 15, 17, 18, 20, 22, 24], "none": [0, 4, 7, 11, 14, 19, 26], "auth_typ": 0, "auth_opt": 0, "session": [0, 4, 7, 15], "default_timeout": [0, 7], "auto_valid": 0, "true": [0, 2, 3, 13, 15, 16, 18, 25, 26], "sourc": [0, 2, 3, 6, 7, 11, 14, 19, 20, 24, 25], "thi": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26], "method": [0, 1, 2, 4, 5, 6, 7, 9, 13, 15, 16, 17, 18, 20, 22, 23, 25, 26], "entri": [0, 2, 25], "point": [0, 2, 3, 4, 5, 13, 17, 18, 22, 26], "you": [0, 1, 2, 3, 4, 5, 6, 9, 11, 12, 13, 14, 15, 17, 18, 19, 21, 22, 24, 25, 26], "typic": [0, 3, 5, 11, 12, 14, 17, 18, 19, 24, 25], "creat": [0, 1, 2, 4, 7, 11, 14, 16, 20, 24, 25, 26], "one": [0, 2, 3, 4, 6, 7, 9, 12, 13, 18, 19, 21, 24, 25], "object": [0, 2, 3, 4, 7, 11, 12, 17, 18, 20, 24, 25, 26], "your": [0, 1, 2, 3, 4, 6, 7, 9, 12, 13, 14, 15, 17, 18, 19, 20, 21, 24, 25, 26], "script": [0, 2, 3, 4, 5, 6, 17, 19, 21, 26], "applic": [0, 2, 5, 14, 20, 21, 22, 26], "re": [0, 2, 3, 7, 19, 21, 24, 26], "all": [0, 2, 3, 4, 6, 7, 11, 13, 17, 18, 19, 22, 23, 24, 25, 26], "call": [0, 2, 3, 4, 5, 6, 7, 12, 13, 16, 17, 18, 21, 22, 25, 26], "backend": [0, 3, 4, 7, 10, 12, 13, 17, 20, 25], "If": [0, 2, 3, 4, 5, 12, 14, 19, 21, 24, 25, 26], "requir": [0, 2, 3, 4, 7, 9, 12, 13, 17, 19, 21, 24, 25, 26], "authent": [0, 7, 8, 20], "pass": [0, 2, 3, 7, 11, 15, 17, 19, 22, 25, 26], "data": [0, 1, 2, 3, 5, 7, 10, 11, 12, 13, 14, 18, 20, 22], "directli": [0, 1, 2, 3, 4, 6, 7, 10, 17, 18, 19, 20, 21, 22, 24, 25, 26], "function": [0, 1, 4, 6, 7, 8, 12, 14, 20, 21, 22, 23, 24], "could": [0, 2, 3, 5, 16, 25, 26], "easier": [0, 1, 2, 3, 5, 7, 22, 24, 25], "follow": [0, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 24, 25, 26], "For": [0, 1, 2, 3, 4, 5, 9, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26], "basic": [0, 2, 5, 7, 8, 9, 13, 16, 17, 20, 25, 26], "conn": 0, "authenticate_bas": [0, 3], "usernam": [0, 3], "john": [0, 3], "password": [0, 3], "foo": [0, 11], "openid": [0, 4, 7, 8, 20], "authenticate_oidc": [0, 3, 4, 7, 20, 25, 26], "client_id": [0, 3], "myclient": 0, "paramet": [0, 2, 7, 9, 11, 14, 16, 18, 20, 24, 25], "option": [0, 2, 4, 5, 7, 9, 14, 18, 19, 20, 24, 25], "str": [0, 11, 14], "http": [0, 2, 4, 5, 7, 9, 11, 12, 13, 15, 16, 17, 18, 19, 20, 24], "which": [0, 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 17, 18, 19, 21, 24, 25, 26], "oidc": [0, 4, 7, 8, 20], "dict": [0, 7, 12, 14, 25], "argument": [0, 1, 2, 3, 4, 5, 6, 7, 14, 15, 16, 17, 18, 25, 26], "specif": [0, 2, 3, 4, 7, 9, 12, 13, 17, 19, 24, 25, 26], "type": [0, 1, 2, 3, 4, 5, 7, 11, 14, 17, 18, 22, 25, 26], "int": [0, 2, 9, 11, 23, 25], "default": [0, 2, 5, 7, 8, 9, 11, 16, 17, 18, 20, 24, 25, 26], "timeout": [0, 3, 7], "second": [0, 2, 4, 5, 7, 24], "request": [0, 2, 3, 4, 5, 7, 17], "bool": [0, 14], "toggl": 0, "automat": [0, 2, 3, 4, 7, 8, 10, 15, 17, 19, 24], "valid": [0, 2, 3, 5, 7, 9, 12, 13, 18, 25], "befor": [0, 2, 3, 4, 5, 7, 17, 25, 26], "execut": [0, 1, 2, 3, 7, 10, 12, 16, 18, 19, 20, 22, 26], "return": [0, 1, 2, 3, 5, 7, 11, 12, 14, 24, 25], "new": [0, 1, 2, 3, 4, 7, 8, 11, 12, 14, 16, 19, 22, 24, 25], "version": [0, 2, 3, 5, 6, 7, 8, 9, 11, 14, 17, 19, 20, 21, 22, 24, 26], "0": [0, 2, 3, 4, 5, 8, 9, 11, 12, 14, 16, 17, 19, 20, 21, 22, 24, 26], "24": [0, 2, 20], "ad": [0, 2, 6, 14, 19, 20], "main": 0, "modul": [0, 2, 6, 7, 20, 21, 24, 26], "earth": [0, 2, 3, 4, 12, 14, 20, 22], "observ": [0, 3, 4, 14, 17, 20, 22], "easili": [0, 3, 4, 5, 7, 19, 21, 24, 25], "complex": [0, 3, 4, 14, 21, 24, 25, 26], "chain": [0, 24, 25, 26], "evalu": [0, 1, 2, 7, 16, 20, 25], "symbol": [0, 24, 26], "refer": [0, 2, 4, 5, 6, 10, 17, 22, 24, 25, 26], "current": [0, 2, 3, 4, 5, 7, 8, 9, 19, 24, 25], "cube": [0, 1, 2, 5, 7, 11, 13, 14, 15, 16, 18, 20, 22], "repres": [0, 17, 24, 25, 26], "raster": [0, 2, 5, 12, 13, 22, 24, 25], "its": [0, 2, 3, 4, 5, 6, 7, 12, 14, 16, 17, 21, 26], "correspond": [0, 1, 2, 4, 5, 18, 19, 22, 23, 24, 26], "grown": 0, "desir": [0, 2, 3, 4, 5, 7, 18, 24, 26], "workflow": [0, 3, 6, 19, 21, 22, 26], "appropri": [0, 17, 24], "__init__": 0, "add": [0, 1, 2, 3, 6, 7, 12, 15, 17, 18, 19, 23, 24], "other": [0, 2, 3, 4, 5, 7, 9, 11, 15, 16, 19, 21, 22, 25, 26], "revers": [0, 2, 7], "fals": [0, 2, 14, 25], "org": [0, 2, 5, 9, 17, 19], "document": [0, 2, 3, 5, 6, 7, 17, 20, 21, 22, 24, 25, 26], "add_dimens": [0, 2, 7, 23], "name": [0, 2, 3, 5, 7, 11, 12, 14, 17, 18, 19, 20, 21, 24, 26], "label": [0, 2, 25], "dimens": [0, 1, 2, 4, 7, 12, 22, 24, 25], "afterward": [0, 2], "referenc": 0, "specifi": [0, 2, 3, 4, 5, 7, 9, 11, 14, 17, 18, 22, 24, 25, 26], "exist": [0, 2, 3, 4, 5, 7, 8, 11, 14, 19, 25], "fail": [0, 2, 5, 7, 18], "dimensionexist": [0, 2], "error": [0, 5, 7, 11, 17, 21, 24, 25], "set": [0, 2, 3, 4, 5, 7, 8, 13, 16, 20, 22, 24, 25], "doe": [0, 2, 3, 4, 5, 7, 11, 17, 19, 24, 25], "modifi": [0, 2, 12], "place": [0, 4, 6, 8, 19, 24, 25], "addit": [0, 2, 3, 7, 8, 9, 14, 17, 18, 19, 24, 26], "allow": [0, 2, 3, 4, 5, 7, 8, 11, 12, 15, 16, 17, 19, 24, 25, 26], "valu": [0, 1, 2, 4, 5, 7, 8, 15, 17, 18, 20, 22, 24, 26], "spatial": [0, 2, 4, 12, 13, 20, 25, 26], "tempor": [0, 1, 2, 4, 5, 7, 12, 20, 22, 24, 25, 26], "band": [0, 2, 7, 9, 10, 12, 13, 17, 20, 22, 24, 25, 26], "newli": [0, 2, 5, 19], "ha": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 14, 17, 19, 22, 25], "exactli": [0, 2, 18, 25], "remain": [0, 2, 12, 25], "unchang": [0, 2, 25], "aggregate_spati": [0, 2, 4, 7, 17, 22, 23, 24, 26], "geometri": [0, 2, 4, 5, 7, 17, 22, 24, 26], "reduc": [0, 1, 2, 3, 4, 7, 12, 17, 22, 24, 26], "target_dimens": [0, 2, 7], "cr": [0, 7, 12, 26], "context": [0, 2, 7, 8, 11, 20, 25], "aggreg": [0, 2, 17, 20, 24, 26], "statist": [0, 2, 17, 20, 24, 25], "e": [0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 17, 19, 21, 22, 23, 24, 25, 26], "g": [0, 1, 2, 3, 4, 5, 6, 7, 13, 14, 17, 19, 21, 22, 24, 25, 26], "zonal": [0, 2, 4], "polygon": [0, 2, 4, 5, 13, 17, 26], "over": [0, 2, 4, 5, 6, 7, 25], "union": [0, 11], "basegeometri": 0, "path": [0, 2, 3, 7, 8, 11, 15, 18, 19, 25], "shape": [0, 2, 4, 7, 12, 19, 25], "geojson": [0, 2, 4, 13, 17, 22, 26], "style": [0, 4, 7, 8, 15, 19, 20, 24, 26], "dictionari": [0, 4, 7, 14, 17, 18, 24, 25], "file": [0, 2, 4, 5, 7, 11, 12, 13, 15, 17, 18, 20, 21, 25], "callabl": [0, 1, 2, 7, 11], "pgnode": [0, 2, 7], "child": [0, 1, 2, 4, 7, 20, 25], "callback": [0, 1, 2, 4, 7, 11, 20], "singl": [0, 2, 4, 7, 12, 13, 14, 15, 16, 18, 24, 25, 26], "discuss": [0, 1, 2, 3, 4, 5, 8, 16, 19, 22, 24, 26], "instanc": [0, 1, 2, 4, 5, 7, 17, 18, 22, 24, 25, 26], "should": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 17, 18, 19, 21, 24, 25, 26], "receiv": [0, 2, 3, 5, 24, 25], "arrai": [0, 1, 2, 7, 12, 18, 24, 25, 26], "numer": [0, 2], "exampl": [0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 21, 22, 24], "mean": [0, 1, 2, 3, 4, 17, 18, 22, 23, 24, 25, 26], "string": [0, 2, 4, 7, 15, 18, 19, 22, 25, 26], "absolut": [0, 2, 23, 24], "predefin": [0, 7, 24], "lambda": [0, 1, 2, 4, 7, 17, 20, 24, 25], "min": [0, 2, 23, 25], "store": [0, 2, 3, 5, 7, 8, 11, 13, 16, 18, 20, 24], "result": [0, 2, 3, 4, 7, 9, 11, 12, 13, 15, 17, 18, 19, 20, 22, 25, 26], "system": [0, 2, 3, 5, 7, 17, 19, 21], "By": [0, 2, 4, 16, 17], "longitud": [0, 17], "latitud": [0, 17], "epsg": [0, 2, 7, 12, 17], "4326": [0, 25], "assum": [0, 2, 3, 18, 19, 22, 24, 25], "see": [0, 2, 3, 4, 5, 8, 11, 12, 14, 16, 17, 24, 25, 26], "normalize_cr": 0, "about": [0, 2, 3, 4, 7, 17, 19, 21, 24, 25, 26], "normal": [0, 1, 2, 3, 4, 7, 8, 9, 14, 17, 19, 24], "appli": [0, 2, 7, 9, 13, 17, 18, 20, 23, 24], "non": [0, 2, 4, 7, 14, 19, 20, 24], "standard": [0, 2, 6, 7, 14, 15, 16, 17, 19, 24, 25], "experiment": [0, 2, 4, 7, 8, 11, 12, 14, 16, 17, 22, 24, 25], "featur": [0, 2, 3, 4, 7, 8, 9, 12, 13, 16, 17, 19, 22, 24, 25, 26], "onli": [0, 1, 2, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 24, 25, 26], "support": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 17, 20, 24, 25, 26], "github": [0, 3, 7, 9, 12, 16, 17, 19, 21], "com": [0, 3, 9, 12, 17, 19, 21], "open": [0, 2, 4, 6, 7, 12, 15, 16, 17, 19, 21, 26], "eo": [0, 1, 2, 4, 7, 12, 13, 16, 17, 18, 19, 21, 22], "issu": [0, 3, 7, 15, 19, 21, 24], "235": 0, "aggregate_spatial_window": [0, 2, 7, 23], "size": [0, 2, 3, 13, 25, 26], "boundari": [0, 2], "pad": [0, 2], "align": [0, 2, 7], "upper": [0, 2], "left": [0, 2, 7], "horizont": [0, 2, 6], "ax": [0, 2], "x": [0, 2, 4, 7, 12, 15, 16, 17, 18, 20, 24, 25, 26], "y": [0, 2, 4, 7, 12, 15, 16, 18, 24, 25, 26], "pixel": [0, 1, 2, 4, 20, 22, 24], "grid": [0, 2], "divid": [0, 2, 16, 18, 23, 24, 25, 26], "overlap": [0, 2, 17, 25], "window": [0, 2, 4, 7, 17, 20, 25, 26], "number": [0, 2, 4, 9, 11, 13, 16, 17, 18, 20, 21, 24, 25, 26], "multipl": [0, 2, 3, 5, 6, 7, 11, 13, 14, 17, 20, 24], "behavior": [0, 2, 6, 7], "each": [0, 1, 2, 3, 4, 5, 12, 19, 21, 24, 25], "comput": [0, 2, 7, 9, 12, 13, 14, 17, 20], "list": [0, 2, 4, 6, 7, 14, 16, 17, 19, 20, 24, 26], "along": [0, 1, 2, 4, 5, 24, 25], "first": [0, 2, 3, 4, 6, 7, 8, 9, 12, 15, 17, 19, 20, 21, 22, 23, 24], "axi": [0, 2, 25], "ar": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26], "null": [0, 2, 7, 26], "fit": [0, 2, 17], "trim": [0, 2], "corner": [0, 2], "extent": [0, 2, 4, 7, 9, 12, 20, 24, 26], "right": [0, 2, 3, 5, 17], "A": [0, 2, 3, 4, 5, 11, 13, 17, 20, 26], "same": [0, 2, 3, 4, 5, 7, 12, 17, 19, 21, 22, 24, 25, 26], "aggregate_tempor": [0, 2, 7, 23, 24], "interv": [0, 2, 3, 26], "base": [0, 2, 4, 5, 7, 9, 10, 17, 19, 20, 21, 25, 26], "date": [0, 2, 3, 4, 7, 19, 24, 25, 26], "time": [0, 1, 2, 3, 4, 5, 7, 9, 12, 16, 17, 18, 21, 22, 24, 25, 26], "calendar": [0, 2], "hierarchi": [0, 2, 7], "year": [0, 2, 7, 11], "month": [0, 2, 7, 12], "week": [0, 2], "etc": [0, 2, 3, 4, 5, 7, 14, 15, 19, 25, 26], "must": [0, 2, 8, 18, 25], "transform": [0, 2, 12, 20, 24, 26], "client": [0, 1, 2, 4, 5, 6, 7, 8, 10, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26], "through": [0, 2, 3, 4, 5, 7, 8, 10, 17, 18, 19, 22, 24, 25], "project": [0, 2, 6, 7, 12, 13, 14, 17, 19, 21, 26], "need": [0, 2, 3, 4, 5, 9, 11, 17, 19, 21, 25, 26], "equal": [0, 2, 7], "expect": [0, 2, 3, 12, 24, 25, 26], "close": [0, 2, 4, 6, 21, 26], "start": [0, 1, 2, 3, 7, 11, 12, 18, 19, 20, 21, 22, 24, 25, 26], "contain": [0, 2, 3, 4, 7, 8, 9, 11, 12, 14, 16, 17, 18, 19, 24, 25, 26], "group": [0, 2, 13], "Not": [0, 2, 6, 15, 26], "aggregate_temporal_period": [0, 2, 7, 23], "period": [0, 2, 3, 4, 5], "season": [0, 2], "pre": [0, 2, 7, 17, 20, 25, 26], "defin": [0, 2, 3, 4, 5, 7, 10, 11, 14, 17, 18, 19, 20, 22], "avail": [0, 2, 3, 4, 5, 7, 9, 13, 16, 17, 19, 21, 24, 25], "hour": [0, 2, 3, 4], "dai": [0, 2, 3, 17], "dekad": [0, 2], "ten": [0, 2], "count": [0, 2, 4, 7, 17, 23], "per": [0, 2, 13], "three": [0, 2], "1": [0, 1, 2, 3, 4, 5, 9, 11, 12, 14, 16, 18, 19, 20, 22, 24, 25, 26], "10": [0, 2, 3, 4, 8, 9, 12, 18, 20, 22, 24, 25, 26], "11": [0, 2, 5, 12, 20], "20": [0, 2, 4, 6, 20, 24], "21": [0, 2, 20, 26], "third": [0, 2, 12], "rang": [0, 2, 4, 14, 17, 25, 26], "from": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 19, 20, 21, 22], "8": [0, 2, 16, 18, 19, 20, 25, 26], "fourth": [0, 2], "feb": [0, 2], "decemb": [0, 2], "februari": [0, 2], "march": [0, 2, 17], "mai": [0, 2, 5, 7, 9, 13, 17, 24, 25], "june": [0, 2, 12], "august": [0, 2], "septemb": [0, 2], "novemb": [0, 2], "tropic": [0, 2], "six": [0, 2], "april": [0, 2, 17], "octob": [0, 2], "prolept": [0, 2], "decad": [0, 2], "9": [0, 2, 4, 12, 14, 18, 19, 20], "next": [0, 2, 3, 4, 7, 13, 17], "better": [0, 2, 3, 4, 6, 7], "anno": [0, 2], "domini": [0, 2], "era": [0, 2], "accept": [0, 1, 2, 25], "input": [0, 2, 4, 7, 9, 13, 14, 24, 25, 26], "median": [0, 2, 4, 12, 23, 24], "properti": [0, 2, 4, 5, 7, 12, 13, 16, 20, 22, 26], "resolut": [0, 2, 7, 12], "unari": 0, "local": [0, 2, 3, 4, 7, 10, 15, 18, 19, 20], "oper": [0, 1, 2, 3, 4, 7, 9, 13, 21, 24, 25, 26], "2": [0, 2, 3, 4, 5, 9, 11, 12, 13, 17, 18, 20, 22, 24, 25, 26], "3": [0, 2, 5, 7, 9, 12, 15, 17, 18, 21, 22, 24, 25, 26], "cardin": 0, "origin": [0, 2, 5, 7, 14, 19, 22, 24, 25], "apply_dimens": [0, 2, 7, 20, 23, 24], "runtim": [0, 2, 7, 25], "t": [0, 1, 2, 3, 4, 5, 7, 8, 12, 14, 17, 21, 22, 24, 25, 26], "work": [0, 3, 4, 5, 7, 8, 9, 13, 17, 19, 20, 21, 25, 26], "seri": [0, 2, 5, 11, 25], "either": [0, 2, 11], "case": [0, 2, 3, 5, 7, 9, 12, 13, 14, 15, 17, 18, 19, 20, 21, 24, 25, 26], "reduce_dimens": [0, 1, 2, 7, 12, 20, 22, 23, 24], "also": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26], "drop": [0, 2, 7, 19], "target": [0, 2, 22, 25], "otherwis": [0, 2, 3, 4, 5, 11], "get": [0, 2, 3, 5, 6, 7, 11, 15, 17, 19, 20, 22, 24, 25, 26], "replac": [0, 2, 7, 19], "preserv": [0, 2, 7, 25], "when": [0, 1, 2, 3, 4, 5, 7, 8, 9, 13, 14, 15, 16, 17, 18, 19, 22, 24, 25, 26], "increment": [0, 2, 18], "integ": [0, 2, 7, 25, 26], "zero": [0, 2], "chang": [0, 2, 4, 8, 11, 12, 14, 15, 16, 19, 20, 21, 22], "rename_label": [0, 2, 7, 23, 25], "deprec": [0, 2, 25, 26], "identifi": [0, 2, 3, 4, 5], "sort": [0, 2, 23], "concat": 0, "42": 0, "dimensionnotavail": [0, 2], "remov": [0, 2, 3, 19, 25], "doesn": [0, 2, 3, 5, 7], "yet": [0, 2, 3, 4, 5, 7, 9, 11, 24, 25], "given": [0, 2, 3, 5, 7, 14, 16, 17, 18, 24, 25, 26], "rais": [0, 2, 3, 5, 7, 24], "13": [0, 3, 20], "favor": [0, 7], "approach": [0, 3, 16, 17, 19, 24, 25], "usag": [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 24, 26], "background": [0, 3, 10, 20], "apply_kernel": [0, 2, 18, 23, 24], "kernel": [0, 2, 18, 26], "factor": [0, 2, 13, 24, 25], "border": [0, 2, 17, 25], "replace_invalid": [0, 2], "focal": 0, "weight": [0, 2], "determin": [0, 2, 13, 14, 17], "how": [0, 2, 3, 4, 5, 6, 17, 19, 21, 24, 25, 26], "extend": [0, 2], "fill": [0, 2, 14, 25], "constant": [0, 2, 7, 23, 24], "n": [0, 2, 5, 7, 12, 14, 19], "nnnnnn": [0, 2], "abcdefgh": [0, 2], "replic": [0, 2], "repeat": [0, 2, 25], "aaaaaa": [0, 2], "hhhhhh": [0, 2], "reflect": [0, 2, 4, 7, 25], "mirror": [0, 2], "fedcba": [0, 2], "hgfedc": [0, 2], "reflect_pixel": [0, 2], "center": [0, 2], "gfedcb": [0, 2], "wrap": [0, 2], "imag": [0, 2, 4, 5, 24, 25], "cdefgh": [0, 2], "abcdef": [0, 2], "ndarrai": [0, 12], "float": [0, 2, 25, 26], "mani": [0, 2, 4, 7, 17], "multipli": [0, 2, 18, 23], "shortcut": [0, 2, 7, 17], "explicitli": [0, 2, 3, 4, 5, 7, 14, 17, 24, 25], "often": [0, 2, 3, 13, 19, 24, 25, 26], "algorithm": [0, 2, 3, 4, 9, 25, 26], "gaussian": [0, 2], "blur": [0, 2], "infinit": [0, 2], "those": [0, 2, 17, 25], "apply_neighborhood": [0, 2, 7, 20, 23, 24], "neighbourhood": 0, "part": [0, 2, 3, 4, 7, 19, 24, 25], "output": [0, 2, 4, 7, 11, 13, 14, 15, 17, 19, 24, 25], "posit": [0, 2, 7], "slide": [0, 25], "move": [0, 7], "continu": 0, "includ": [0, 2, 3, 5, 7, 11, 13, 25], "kept": [0, 3], "small": [0, 4, 6, 17, 25], "enough": [0, 4, 14, 17, 19, 21], "avoid": [0, 2, 3, 6, 7, 13, 15, 17, 19, 21, 22], "run": [0, 2, 4, 7, 9, 11, 12, 13, 20, 21, 24, 25], "beyond": 0, "resourc": [0, 2, 4, 5, 18, 24], "too": [0, 3, 4, 5, 7, 17, 19, 24, 26], "larger": [0, 3, 4, 5, 19, 24], "invoc": 0, "slow": [0, 19], "down": [0, 2], "64": 0, "512": 0, "while": [0, 1, 2, 3, 4, 5, 6, 7, 17, 18, 19, 24, 25, 26], "32": [0, 2, 16, 26], "common": [0, 2, 3, 4, 6, 9, 14, 17, 20, 26], "entir": 0, "differ": [0, 2, 3, 4, 8, 9, 14, 16, 17, 19, 22, 25, 26], "special": [0, 7, 9, 12, 24, 26], "2d": 0, "convolut": [0, 2, 24], "recommend": [0, 2, 3, 4, 5, 7, 13, 17, 19, 20, 21, 25], "apply_polygon": [0, 7], "mask_valu": 0, "segment": [0, 19], "intersect": [0, 2], "simpl": [0, 1, 2, 3, 4, 5, 8, 12, 14, 17, 18, 19, 20, 24, 25, 26], "ogc": [0, 2], "collect": [0, 2, 3, 6, 7, 9, 10, 14, 18, 20, 22, 25, 26], "sub": [0, 2, 7, 18, 19, 24, 26], "geometriesoverlap": 0, "except": [0, 2, 3, 5, 7, 9, 11, 25], "thrown": [0, 2], "individu": [0, 2, 4, 13, 25], "subject": [0, 4, 8, 11, 12, 14, 15, 16, 22, 25], "outsid": [0, 3], "ard_normalized_radar_backscatt": [0, 2, 9, 23], "elevation_model": [0, 2], "contributing_area": [0, 2], "ellipsoid_incidence_angl": [0, 2], "noise_remov": [0, 2], "card4l": [0, 2, 9], "compliant": [0, 2, 9], "backscatt": [0, 2, 10], "gamma0": [0, 2], "sar": [0, 2, 10, 17], "variant": [0, 9], "sar_backscatt": [0, 2, 7, 9, 23], "restrict": [0, 2, 13], "accord": [0, 2], "note": [0, 1, 2, 3, 4, 5, 8, 9, 13, 16, 17, 18, 19, 24, 25, 26], "instrument": 0, "tightli": [0, 9], "coupl": [0, 3, 4, 5, 6, 9, 17, 22, 24, 25, 26], "product": [0, 2, 9, 17, 23], "As": [0, 1, 2, 4, 12, 16, 17, 18, 19, 26], "combin": [0, 2, 7, 13, 17, 24, 25], "load": [0, 2, 3, 7, 8, 9, 10, 12, 18, 20, 21, 22, 24, 25, 26], "digit": [0, 2, 4, 20, 25], "elev": [0, 2], "model": [0, 2, 7, 13, 22, 25], "choos": [0, 2, 17, 25], "improv": [0, 2, 6, 7, 17, 25], "portabl": [0, 2], "reproduc": [0, 2, 17], "dem": [0, 2], "contribut": [0, 2, 20, 21], "area": [0, 2, 13, 17], "squar": [0, 2], "meter": [0, 2, 4], "ellipsoid": [0, 2], "incid": [0, 2], "angl": [0, 2, 9], "degre": [0, 2, 16, 26], "nois": [0, 2], "express": [0, 1, 2, 4, 7, 17, 24, 25], "linear": [0, 2], "scale": [0, 2, 10, 24, 25], "ard_surface_reflect": [0, 2, 7, 9, 23], "atmospheric_correction_method": [0, 2], "cloud_detection_method": [0, 2], "atmospheric_correction_opt": [0, 2, 7], "cloud_detection_opt": [0, 2, 7], "surfac": [0, 2], "optic": [0, 2, 9, 17], "atmospher": [0, 2, 10], "correct": [0, 2, 10, 25], "cloud": [0, 2, 3, 5, 7, 8, 12, 17, 18, 20], "detect": [0, 2, 3, 7, 14, 24, 25], "leav": [0, 11], "empti": [0, 2, 19], "make": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 19, 21, 22, 25], "suitabl": [0, 2, 9, 17, 25], "choic": [0, 3, 6], "proprietari": [0, 2], "bottom": [0, 2], "disturb": [0, 2], "like": [0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 14, 15, 16, 17, 18, 21, 22, 24, 25, 26], "shadow": [0, 2, 7], "atmospheric_correct": [0, 2, 7, 9, 23], "convert": [0, 2, 4, 15, 24, 26], "top": [0, 1, 2, 3, 4, 26], "canopi": [0, 2, 4], "give": [0, 4, 5, 6, 9, 17, 20, 21, 24, 25], "To": [0, 1, 2, 3, 4, 9, 13, 14, 17, 19, 21, 22, 24, 25, 26], "filter": [0, 2, 4, 7, 9, 20], "out": [0, 3, 4, 5, 6, 8, 11, 17, 21, 24, 25, 26], "index": [0, 2, 4, 7, 14, 20, 25], "band_filt": 0, "sinc": [0, 2, 3, 4, 5, 13, 17, 21], "legaci": [0, 5, 7, 25, 26], "filter_band": [0, 2, 7, 17, 23, 24], "instead": [0, 1, 2, 3, 4, 7, 14, 15, 17, 18, 19, 22, 24, 25, 26], "chunk_polygon": [0, 7], "chunk": [0, 20], "cell": [0, 2, 4, 5, 6], "distinct": [0, 2, 7], "between": [0, 2, 3, 7, 9, 17, 18, 23, 25], "nodata": [0, 2, 12], "within": [0, 2, 7, 25], "due": [0, 2], "mask": [0, 2, 7, 17, 18, 20, 23, 24], "26": [0, 14, 17, 20], "count_tim": [0, 23], "dataset": [0, 2, 9, 10, 17, 20, 25], "classmethod": 0, "create_collect": 0, "cl": 0, "collection_id": [0, 7], "spatial_ext": [0, 2, 4, 6, 7, 9, 12, 17, 20, 22, 25, 26], "temporal_ext": [0, 2, 4, 6, 7, 9, 11, 12, 13, 17, 20, 22, 25, 26], "fetch_metadata": 0, "max_cloud_cov": [0, 7, 17], "4": [0, 4, 5, 6, 9, 17, 18, 20, 22, 25, 26], "6": [0, 4, 5, 12, 18, 20, 22, 25, 26], "load_collect": [0, 2, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15, 17, 20, 22, 23, 24, 25, 26], "create_job": [0, 5, 7, 11, 13, 15, 22], "out_format": [0, 5, 7, 13], "titl": [0, 4, 5, 7, 11, 12, 13, 15, 16, 19], "descript": [0, 2, 5, 7, 8, 12, 13, 16, 19, 24, 26], "plan": [0, 7, 19], "budget": [0, 7], "job_opt": [0, 25], "format_opt": 0, "send": [0, 2, 4, 5, 7, 19], "batch": [0, 1, 2, 7, 13, 20, 22, 25], "batchjob": [0, 5, 7, 11, 22], "just": [0, 2, 3, 4, 5, 6, 7, 14, 15, 17, 18, 19, 22, 24, 25, 26], "still": [0, 3, 5, 6, 7, 12, 13, 17, 21, 25], "track": [0, 1, 2, 4, 6, 11, 19, 21, 24], "execute_batch": [0, 5, 7, 9, 25], "take": [0, 1, 2, 3, 4, 5, 7, 18, 20, 24, 26], "care": [0, 2, 3], "manag": [0, 4, 5, 7, 8, 10, 20, 24], "format": [0, 2, 4, 5, 6, 7, 9, 13, 14, 15, 17, 18, 19, 25, 26], "bill": [0, 7], "maximum": [0, 2, 4, 7, 11, 17, 20, 24], "cost": [0, 4, 9, 13, 17, 25], "custom": [0, 3, 7, 8, 9, 11, 24, 26], "enabl": [0, 2, 3, 7, 19, 26], "prevent": [0, 7], "overrul": 0, "dimension_label": [0, 2, 7, 23], "order": [0, 2, 4, 5, 7, 8, 23, 25], "download": [0, 7, 9, 11, 15, 17, 19, 20, 22, 26], "outputfil": 0, "synchron": [0, 5, 7, 13, 20, 26], "geotiff": [0, 4, 5, 7, 9, 12, 17], "disk": [0, 5], "byte": 0, "decod": 0, "drop_dimens": [0, 2, 23], "dimensionlabelcountmismatch": 0, "print": [0, 3, 4, 7, 8, 15, 16, 19, 21, 24, 26], "built": [0, 3, 19], "max_poll_interv": 0, "60": [0, 11, 25], "connection_retry_interv": 0, "30": [0, 4, 12, 16, 20], "retriev": [0, 2, 7, 17, 24], "finish": [0, 3, 7, 11, 19, 22, 25], "mostli": [0, 3, 8], "reason": [0, 3, 6, 17, 24, 25], "amount": [0, 17], "veri": [0, 3, 4, 6, 7, 9, 16, 17, 24, 25, 26], "long": [0, 2, 5, 6, 17, 20], "probabl": [0, 2, 4, 25], "do": [0, 1, 2, 3, 4, 5, 7, 11, 12, 13, 15, 17, 19, 22, 24, 25, 26], "keep": [0, 1, 2, 3, 4, 5, 6, 7, 17, 19, 21, 24, 25], "written": 0, "static": 0, "execute_local_udf": [0, 7, 25], "fmt": [0, 25], "netcdf": [0, 4, 7, 12, 13, 17, 21, 25], "7": [0, 2, 4, 12, 20, 21, 26], "run_cod": [0, 25], "indic": [0, 2, 4, 7, 10, 13], "filter_bbox": [0, 2, 7, 9, 17, 23, 24], "arg": [0, 11], "west": [0, 4, 6, 7, 9, 12, 17, 20, 24, 25, 26], "south": [0, 4, 6, 7, 9, 12, 17, 20, 24, 25, 26], "east": [0, 4, 6, 7, 9, 12, 17, 20, 24, 25, 26], "north": [0, 4, 6, 7, 9, 12, 17, 20, 24, 25, 26], "height": [0, 2, 7], "bbox": [0, 5, 7, 22, 24, 26], "limit": [0, 2, 3, 4, 17, 24, 25], "bound": [0, 2, 12, 17, 24, 26], "box": [0, 2, 8, 17, 24, 26], "wai": [0, 3, 4, 5, 6, 17, 18, 19, 22, 24, 25, 26], "With": [0, 3, 5, 12, 25], "keyword": [0, 7, 24], "51": [0, 4, 5, 9, 17, 20, 22, 24, 25, 26], "52": [0, 2, 12], "tupl": [0, 7, 17], "necessari": [0, 3, 5, 7, 14, 19, 21, 22, 25], "bbox_param": 0, "my_bbox": 0, "schema": [0, 7, 18], "than": [0, 2, 3, 4, 7, 12, 13, 18, 24], "652000": 0, "672000": 0, "5161000": 0, "5181000": 0, "32632": [0, 12], "describ": [0, 2, 3, 5, 7, 11, 16, 19, 21, 24], "coordin": [0, 2, 4, 5, 12, 17, 22, 26], "interpret": 0, "handl": [0, 2, 3, 4, 5, 7, 11, 12, 14, 20, 24], "author": [0, 3, 7], "filter_spati": [0, 2, 7, 13, 23], "retain": [0, 17, 25], "least": [0, 2, 7, 18, 19, 21, 24, 25, 26], "consid": [0, 2, 3, 6, 19, 21], "closest": [0, 2], "line": [0, 2, 3, 7, 19, 20, 21, 25], "whose": [0, 2], "after": [0, 2, 3, 4, 5, 6, 19, 25], "insid": [0, 1, 2, 7, 16, 17, 22], "One": [0, 2, 17], "less": [0, 2, 7], "filter_tempor": [0, 2, 7, 9, 17, 18, 23, 24, 26], "start_dat": [0, 17, 24], "end_dat": [0, 17, 24], "certain": [0, 6, 9, 13, 17, 26], "sever": [0, 2, 24, 25], "2019": [0, 9, 12, 24], "07": [0, 3, 5, 9, 17, 20, 23, 24, 26], "01": [0, 2, 4, 5, 6, 11, 12, 13, 17, 18, 20, 24, 25, 26], "08": [0, 2, 17, 20, 23, 24], "shorthand": [0, 7], "notat": [0, 7, 24], "processbuilderbas": 0, "inclus": [0, 2], "exclus": [0, 2], "sequenc": [0, 2], "two": [0, 2, 3, 4, 7, 17, 24, 26], "item": [0, 2, 5, 7, 10, 18, 22, 24, 26], "23": [0, 1, 2, 5, 17, 20, 21, 24], "fit_curv": [0, 2, 7, 23], "f": [0, 4, 11, 15, 16, 26], "throw": [0, 2], "invalidvalu": 0, "invalid": [0, 2, 7, 15, 19], "encount": [0, 25, 26], "finit": [0, 7], "is_valid": [0, 2, 7, 23, 24], "pull": 0, "240": [0, 7], "flat_graph": [0, 15], "flat": [0, 7, 16, 18], "represent": [0, 2, 4, 7, 12, 15, 16, 18, 26], "rtype": 0, "mainli": [0, 5, 15, 24, 25], "intend": [0, 1, 2, 3, 15, 24], "to_json": [0, 4, 7, 15, 26], "print_json": [0, 7, 15, 26], "obtain": [0, 2, 3, 4, 19], "interoper": [0, 2, 7, 15], "json": [0, 3, 4, 5, 7, 10, 11, 12, 16, 19, 20, 24, 25, 26], "export": [0, 3, 7, 10, 13], "inform": [0, 2, 3, 4, 5, 7, 9, 11, 14, 16, 17, 19, 21, 24, 26], "flatten_dimens": [0, 2, 7, 23], "label_separ": [0, 2], "flatten": [0, 7], "merg": [0, 2, 6, 7, 19], "opposit": 0, "unflatten_dimens": [0, 2, 7, 23], "both": [0, 2, 9, 11, 19, 25], "subsequ": [0, 2, 3, 4], "necessarili": [0, 13], "separ": [0, 2, 3, 4, 5, 7, 9, 17, 19, 24, 25], "concaten": [0, 2], "graph_add_nod": 0, "process_id": [0, 4, 15, 16, 18, 24, 26], "namespac": [0, 7, 10], "kwarg": [0, 7, 11, 24], "linear_scale_rang": [0, 2, 7, 23], "input_min": [0, 7], "input_max": [0, 7], "output_min": [0, 7], "output_max": [0, 7], "perform": [0, 2, 4, 9, 10, 12, 17, 24, 25], "clip": [0, 2, 23], "inputmin": [0, 2], "inputmax": [0, 2], "underli": [0, 2, 9, 15], "formula": [0, 4, 14], "outputmax": [0, 2], "outputmin": [0, 2], "never": [0, 1, 2, 3], "ani": [0, 2, 3, 4, 5, 9, 11, 12, 17, 19, 23, 25], "greater": [0, 2, 7], "potenti": 0, "bit": [0, 4, 5, 17, 20, 22, 25], "255": 0, "channel": [0, 7, 19], "rgb": [0, 9, 25], "colour": 0, "calcul": [0, 2, 4, 14, 26], "percentag": 0, "100": [0, 2, 7, 18], "therefor": [0, 25], "propag": 0, "minimum": [0, 2, 7, 13, 17], "ln": [0, 2, 7, 23], "collectionproperti": 0, "predic": 0, "collection_properti": [0, 7, 17], "easi": [0, 8, 21, 26], "construct": [0, 2, 4, 7, 16, 17, 20, 24, 26], "cover": [0, 2, 4, 7, 12, 13, 17, 18, 22, 24, 25, 26], "cloud_cov": [0, 7, 12, 17], "load_disk_collect": [0, 7], "file_format": 0, "glob_pattern": 0, "load_disk_data": 0, "eventu": 0, "load_uploaded_fil": [0, 2, 7, 23], "gtiff": [0, 5, 9, 13, 22, 26], "glob": 0, "pattern": [0, 2, 4, 6, 7], "match": [0, 2, 17], "log10": [0, 7, 23], "log2": [0, 2, 7, 23], "logarithm": [0, 2, 7, 23], "logical_and": [0, 23], "element": [0, 2, 12, 25], "wise": 0, "logic": [0, 2, 7, 25], "logical_or": [0, 23], "vector": [0, 2, 4, 7, 13, 20, 22, 24, 25], "mask_polygon": [0, 2, 7, 23], "among": [0, 16], "compar": [0, 2, 9, 25], "boolean": [0, 2, 15, 26], "sr": 0, "behaviour": [0, 11], "invert": [0, 2], "max_tim": [0, 4, 20, 23], "find": [0, 2, 4, 19, 20, 21], "max": [0, 2, 4, 7, 20, 23, 24, 25], "mean_tim": [0, 23], "median_tim": [0, 23], "overlap_resolv": [0, 2], "merge_cub": [0, 2, 7, 23], "compat": [0, 25, 26], "without": [0, 2, 3, 4, 7, 8, 9, 12, 15, 18, 19, 25], "join": 0, "resolv": [0, 2], "b1": [0, 19], "b2": 0, "b3": 0, "b4": 0, "four": [0, 2], "There": [0, 2, 3, 9, 16, 19, 25, 26], "plu": 0, "been": [0, 2, 7, 9, 11, 14, 25], "anoth": [0, 2, 3, 5, 16, 17, 19, 22, 24, 25, 26], "step": [0, 3, 4, 5, 9, 12, 17, 18, 19, 25], "higher": [0, 2, 25], "dimension": [0, 2, 25], "spatiotempor": [0, 25], "reduct": [0, 2], "conflict": [0, 2, 6, 7, 21, 22], "consist": [0, 2, 6, 7, 12, 17, 26], "min_tim": [0, 23], "ndvi": [0, 2, 4, 5, 7, 12, 14, 20, 23, 24], "nir": [0, 2, 4, 12, 14, 18, 26], "red": [0, 2, 4, 12, 14, 18, 26], "target_band": [0, 2, 7], "veget": [0, 2, 4, 7, 14], "normalized_differ": [0, 2, 23], "polygonal_histogram_timeseri": [0, 7], "extract": [0, 2, 4, 13, 19, 26], "histogram": 0, "multi": [0, 2, 10, 20, 26], "Its": 0, "multipolygon": [0, 2], "polygonal_mean_timeseri": [0, 7], "polygonal_median_timeseri": [0, 7], "polygonal_standarddeviation_timeseri": [0, 7], "deviat": [0, 2, 14], "sd": [0, 2, 4, 23], "power": [0, 2, 23, 24], "p": [0, 2, 25], "predict_curv": [0, 2, 7, 23], "predict": [0, 2, 22, 25], "predict_random_forest": [0, 2, 7, 22, 23], "train": [0, 2, 7, 13], "load_ml_model": [0, 2, 7, 22, 23], "save": [0, 2, 3, 7, 11, 15, 16, 19, 22], "random": [0, 2, 20], "forest": [0, 2, 20], "id": [0, 1, 2, 3, 4, 5, 7, 12, 14, 16, 17, 18, 22, 24, 25, 26], "stac": [0, 2, 5, 7, 10, 17, 22], "implement": [0, 1, 2, 4, 7, 10, 11, 12, 18, 21, 22, 24, 25], "ml": [0, 2, 22], "extens": [0, 2, 7, 8, 22, 25], "preview": [0, 7, 21], "zoom": 0, "displai": [0, 7], "map": [0, 2, 7, 10, 18, 19, 20, 24, 25, 26], "widget": [0, 7], "xyz": [0, 7], "iter": [0, 5, 24], "ipyleaflet": 0, "19": [0, 4, 5, 17, 20], "indent": [0, 4, 6, 26], "dump": [0, 3, 5, 15, 26], "doc": [0, 2, 5, 7, 9, 19], "stream": 0, "sy": [0, 25], "stdout": 0, "Or": [0, 3, 15, 17, 19], "pathlib": [0, 15, 25], "write": [0, 4, 7, 11, 13, 15, 16, 21, 24], "kei": [0, 2, 25], "newlin": 0, "12": [0, 2, 4, 12, 17, 19, 20, 26], "helper": [0, 1, 4, 5, 7, 8, 14, 20, 24, 26], "collectionmetadata": [0, 7, 25], "overrid": 0, "process_with_nod": [0, 7], "pg": [0, 12, 26], "node": [0, 2, 7, 16, 24, 25, 26], "raster_to_vector": 0, "homogen": 0, "reduce_band": 0, "reduce_bands_udf": 0, "spectral": [0, 2, 4, 7, 10, 20, 26], "band_math_mod": 0, "reduce_spati": [0, 2, 7, 23], "reduce_tempor": 0, "reduce_temporal_simpl": [0, 7], "reduce_temporal_udf": 0, "latest": [0, 7, 9, 19, 21], "reduce_tiles_over_tim": 0, "rename_dimens": [0, 2, 23], "renam": [0, 2, 7, 14, 19], "thei": [0, 2, 5, 7, 15, 18, 24, 25], "resample_cube_spati": [0, 2, 4, 23], "resampl": [0, 2, 4], "regardless": 0, "resample_spati": [0, 2, 23], "resample_cube_tempor": [0, 2, 7, 23], "valid_within": [0, 2], "nearest": [0, 2], "neighbor": [0, 2], "simpli": [0, 2, 9, 17], "independ": [0, 2], "depend": [0, 1, 2, 3, 5, 7, 9, 13, 17, 19, 20], "lead": [0, 2, 3, 6, 15, 17], "being": [0, 2, 12, 24], "assign": [0, 2], "timestamp": [0, 2, 17], "around": [0, 7, 13, 25], "rare": [0, 19], "ti": 0, "earlier": [0, 3, 4, 7, 18], "resolution_merg": [0, 7, 23], "high_resolution_band": 0, "low_resolution_band": 0, "try": [0, 3, 7, 9, 18, 19, 21, 22, 24, 25], "sentinel": [0, 4, 9, 12, 13, 17], "20m": 0, "10m": 0, "extern": [0, 2], "pansharpen": 0, "explain": [0, 3, 4, 20, 26], "land": [0, 2, 7, 22], "phenologi": 0, "fuse": 0, "medium": 0, "coars": 0, "uniqu": [0, 2], "field": [0, 2, 4, 7, 26], "common_nam": [0, 2, 12], "prioriti": [0, 2], "These": [0, 2, 4, 9, 19, 24, 25], "unmodifi": 0, "increas": [0, 2, 17], "vari": 0, "select": [0, 2, 4, 9, 19, 20, 26], "result_nod": [0, 7, 24], "coeffici": [0, 2, 7], "terrain": [0, 2, 9], "local_incidence_angl": [0, 2], "radiometr": [0, 2], "beta0": [0, 2], "radar": [0, 2, 9], "bright": [0, 2], "sigma0": [0, 2, 9], "ground": [0, 2, 4], "sensor": [0, 2, 9], "sight": [0, 2], "orthorectifi": [0, 7], "rtc": [0, 7], "save_result": [0, 2, 5, 7, 23], "save_user_defined_process": [0, 16, 26], "user_defined_process_id": [0, 26], "summari": [0, 7], "categori": [0, 2, 7], "link": [0, 4, 7, 16, 17, 24], "visibl": [0, 2], "short": [0, 2, 3, 4, 25], "what": [0, 1, 2, 3, 5, 19, 24, 25, 26], "entiti": [0, 17], "commonmark": 0, "29": [0, 2, 17, 20], "syntax": [0, 7, 26], "rich": [0, 7], "text": [0, 2], "restuserdefinedprocess": [0, 16], "send_job": [0, 7], "subtract": [0, 2, 16, 18, 23, 24, 26], "split": [0, 2, 6, 25], "systemat": 0, "messag": [0, 2, 3, 5, 7, 19, 21, 25], "_datacub": 0, "_sourc": 0, "emb": [0, 17, 25], "them": [0, 2, 3, 5, 8, 9, 11, 14, 17, 19, 24, 25], "from_fil": [0, 25], "my": [0, 3, 15, 25], "py": [0, 7, 19, 25], "auto": [0, 7, 8, 20, 25], "anymor": [0, 25], "actual": [0, 1, 2, 4, 14, 17, 25], "simplifi": [0, 4, 7, 14, 26], "from_url": 0, "omit": 0, "get_run_udf_callback": 0, "data_paramet": 0, "run_udf": [0, 2, 7, 23, 25], "structur": [0, 2, 4, 7, 12, 18, 22, 24, 25], "www": [0, 2], "w3": 0, "tr": 0, "sdw": 0, "bp": 0, "dfn": 0, "etcetera": 0, "22": [0, 2, 20], "clientjob": 0, "raw": [0, 4, 7, 9, 10, 13, 17, 18, 22, 25, 26], "content": [0, 2, 7, 12], "guess": [0, 2, 7, 14], "filter_label": [0, 2, 7, 23], "condit": [0, 2, 7], "filter_vector": [0, 7], "relat": [0, 3, 4, 7, 19, 21], "fit_class_random_forest": [0, 2, 7, 22, 23], "max_vari": [0, 2], "num_tre": [0, 2], "seed": [0, 2], "classif": [0, 2, 4, 7, 20], "predictor": [0, 2, 22], "breiman": 0, "2001": 0, "site": [0, 2], "associ": [0, 2, 3, 19], "variabl": [0, 2, 4, 7, 8, 14, 24], "fraction": [0, 2, 7], "tree": [0, 2, 3], "sampl": [0, 2, 4, 10, 12, 17, 20, 22], "16": [0, 2, 4, 6, 20, 24], "fit_regr_random_forest": [0, 2, 7, 22, 23], "regress": [0, 2, 20], "load_geojson": [0, 7, 23], "rfc": [0, 2, 17], "7946": 0, "major": [0, 18, 25], "thing": [0, 3, 6], "load_url": [0, 7], "read": [0, 2, 6, 12, 17], "token": [0, 7, 20], "server": [0, 2, 19, 20], "report": [0, 2, 4, 19, 26], "chosen": [0, 2, 9], "self": [0, 2, 4], "machin": [0, 2, 3, 7, 20, 25], "learn": [0, 2, 7, 20], "procedur": [0, 3, 24], "fit_": 0, "predict_": 0, "upload": [0, 7, 17, 19], "save_ml_model": [0, 2, 22, 23], "banddimens": 0, "append_band": 0, "append": [0, 2, 14, 19, 24, 25], "band_index": 0, "band_nam": 0, "allow_common": 0, "subset": [0, 2, 19, 24], "wrapper": [0, 7, 25, 26], "deepli": 0, "nest": [0, 2, 7], "pars": [0, 12], "develop": [0, 2, 6, 7, 20, 22, 25, 26], "html": [0, 2, 7, 19], "partial": [0, 7], "older": [0, 25], "assert_valid_dimens": 0, "sure": [0, 3, 4, 5, 7, 9, 17, 19, 21, 25], "band_dimens": 0, "themat": 0, "param": 0, "dimension_nam": 0, "collaps": 0, "updat": [0, 2, 7, 20, 25], "spatialdimens": 0, "temporaldimens": 0, "item_schema": 0, "expand": [0, 2, 17], "subtyp": [0, 7, 26], "raster_cub": [0, 26], "to_dict": 0, "serial": 0, "logentri": [0, 7], "info": [0, 2, 5, 7, 8], "warn": [0, 5, 7, 16, 21, 25], "debug": [0, 5, 7, 25], "event": 0, "rfc3339": [0, 2, 7], "stack": [0, 12, 25], "trace": 0, "metric": 0, "cpu": 0, "memori": 0, "durat": 0, "network": [0, 3], "storag": [0, 3], "ones": [0, 2, 24], "unit": [0, 2, 7, 20, 21, 24, 25], "arbitrari": [0, 2], "purpos": [0, 12, 17, 25], "pleas": [0, 2, 12, 25, 26], "absenc": 0, "did": [0, 4, 7], "normalize_log_level": 0, "log_level": 0, "librari": [0, 3, 4, 5, 6, 7, 8, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26], "fallback": [0, 3], "unknown": [0, 11], "typeerror": 0, "persist": 0, "auth": [0, 4, 7, 8, 20], "auth_config": 0, "refresh_token_stor": 0, "slow_response_threshold": 0, "oidc_auth_renew": 0, "as_curl": [0, 7], "post": [0, 5, 7], "obfuscate_auth": 0, "curl": [0, 7], "command": [0, 3, 4, 7, 19, 25], "header": [0, 3, 7], "h": [0, 3, 19], "bearer": 0, "process_graph": [0, 4, 15, 18, 26], "flatgraphablemixin": 0, "someth": [0, 2, 18, 21, 25], "processbuild": [0, 1, 7, 20, 23, 24], "endpoint": [0, 7, 25], "don": [0, 2, 3, 4, 7, 8, 14, 17, 21, 24, 25, 26], "show": [0, 3, 4, 5, 7, 9, 17, 19], "assert_user_defined_process_support": 0, "capabl": [0, 4, 7], "verif": 0, "passphras": 0, "provider_id": [0, 3], "client_secret": [0, 3], "store_refresh_token": [0, 3], "use_pkc": 0, "max_poll_tim": [0, 7], "300": [0, 7], "In": [0, 2, 3, 4, 5, 12, 14, 17, 19, 24, 25, 26], "refresh": [0, 7, 19, 20], "fall": [0, 3, 7, 24, 25], "devic": [0, 4, 7, 20], "flow": [0, 7, 20, 22, 24], "possibl": [0, 2, 4, 5, 8, 9, 12, 13, 14, 16, 17, 18, 21, 24, 25, 26], "trigger": [0, 3, 4, 7, 19, 25], "client_credenti": [0, 3], "environ": [0, 5, 7, 8, 19, 21, 25], "up": [0, 2, 3, 5, 6, 7, 17, 22, 24, 25], "secret": [0, 3, 7, 8], "openeo_auth_method": [0, 3], "openeo_auth_client_id": [0, 3], "openeo_auth_client_secret": [0, 3], "dynam": [0, 20, 25], "poll": [0, 3, 5, 7], "success": [0, 3, 8], "17": [0, 4, 17, 20], "18": [0, 2, 3, 4, 17, 20], "credenti": [0, 7, 20], "authenticate_oidc_authorization_cod": [0, 3], "server_address": [0, 3], "webbrowser_open": 0, "pkce": [0, 7], "becaus": [0, 1, 2, 3, 4, 6, 9, 11, 13, 19, 24, 25, 26], "authenticate_oidc_devic": [0, 3], "authenticate_oidc_client_credenti": [0, 3, 7], "openeo_auth_provider_id": [0, 3, 7], "respect": [0, 2, 3, 26], "whether": [0, 2, 4], "attempt": [0, 3, 7], "best": [0, 4, 7, 17, 20], "mode": [0, 2, 7, 8, 19, 21], "wide": [0, 25], "5": [0, 2, 4, 5, 12, 15, 17, 18, 20, 22, 24, 25, 26], "authenticate_oidc_refresh_token": [0, 3], "refresh_token": [0, 3], "authenticate_oidc_resource_owner_password_credenti": [0, 3], "owner": 0, "restcap": 0, "collection_item": [0, 7], "wgs84": 0, "datetim": [0, 17, 25], "page": [0, 3, 4, 7, 19, 20, 21], "decid": [0, 9], "data_list": 0, "datacube_from_flat_graph": [0, 7], "under": [0, 3, 4, 5, 19, 22], "encod": [0, 4, 7, 15], "datacube_from_json": [0, 7, 16, 18], "src": 0, "datacube_from_process": [0, 7, 16, 18, 26], "awar": [0, 2, 17], "describe_account": [0, 3], "account": [0, 2, 4, 5, 20, 26], "describe_collect": [0, 4, 7, 17], "full": [0, 7, 9, 13, 25], "list_collection_id": [0, 4, 17], "describe_process": [0, 7, 24], "definit": [0, 2, 7, 24, 25], "binari": [0, 4, 19], "wait": [0, 4, 7, 19], "respons": [0, 5, 7, 17], "get_fil": 0, "workspac": [0, 2], "pureposixpath": 0, "imagecollect": [0, 7], "job_id": [0, 5, 7, 11, 22], "alreadi": [0, 2, 3, 5, 6, 7, 11, 17, 19, 26], "job_log": [0, 7], "offset": 0, "job_result": [0, 7], "get_result": [0, 5, 7, 9], "particular": [0, 3, 17, 19, 25], "list_collect": [0, 12, 17], "list_file_format": [0, 17], "list_file_typ": 0, "list_output_format": 0, "list_fil": [0, 7], "list_job": [0, 5, 7], "job_list": 0, "list_process": [0, 24], "processes_dict": 0, "list_service_typ": 0, "data_dict": 0, "list_servic": [0, 7], "list_udf_runtim": 0, "list_user_defined_process": 0, "load_result": [0, 2, 7, 23], "side": [0, 1, 2, 4, 5, 7, 10, 16, 20], "load_stac": [0, 7, 12, 23], "catalog": [0, 12, 17], "nodataavail": 0, "remark": 0, "nomin": 0, "would": [0, 2, 3, 7, 11, 25], "impli": [0, 16], "whole": [0, 2, 3, 19, 22, 25], "larg": [0, 2, 13, 20, 25], "optim": [0, 2, 13, 25], "consequ": [0, 25], "asset": [0, 7, 9, 13, 22], "itself": [0, 3, 7, 11, 19, 24], "usual": [0, 2, 3, 5, 8, 13, 17, 19, 24, 25, 26], "sign": 0, "canon": [0, 16], "fulli": [0, 2, 4, 5, 16, 19, 25], "featurecollect": [0, 2, 4, 22], "Be": [0, 2, 16], "unbound": [0, 2], "exclud": [0, 2], "alwai": [0, 2, 3, 7, 8, 17, 25], "later": [0, 4, 17], "temporalextentempti": 0, "AND": [0, 2], "pair": [0, 2, 17], "discoveri": [0, 2, 7, 20], "against": [0, 2, 7], "remove_servic": [0, 7], "service_id": 0, "stop": [0, 3, 4, 5, 7, 11, 25], "secondari": [0, 7], "delete_servic": [0, 7], "check_error": 0, "expected_statu": 0, "create_servic": [0, 7], "upload_fil": 0, "locat": [0, 3, 4, 13, 24], "folder": [0, 2, 5, 7, 8, 11, 12, 19], "filenam": [0, 7, 8], "user_defined_process": 0, "user_job": 0, "validate_process_graph": 0, "vectorcube_from_path": [0, 7, 17], "access": [0, 3, 7, 13, 16], "14": [0, 4, 11, 17, 20], "version_discoveri": 0, "well": [0, 1, 2, 4, 6, 7, 14, 21, 25, 26], "known": [0, 4, 17], "uri": 0, "strategi": 0, "initi": [0, 2, 3, 7, 20, 25], "root": [0, 2, 19, 21], "highest": 0, "version_info": [0, 7], "cancel": [0, 5], "inspect": [0, 2, 4, 5, 7, 23, 24, 25, 26], "had": [0, 2, 5, 19], "cryptic": [0, 5, 7], "restjob": [0, 5, 7], "alia": [0, 2, 5, 7], "delet": [0, 5, 7], "wa": [0, 2, 3, 5, 7, 17, 25], "previous": [0, 4, 6], "delete_job": 0, "submit": [0, 5, 26], "statu": [0, 4, 5, 7, 11, 16], "progress": [0, 4, 5, 7], "describe_job": [0, 7], "download_result": 0, "dir": 0, "where": [0, 1, 2, 3, 5, 6, 7, 8, 11, 13, 18, 19, 22], "taken": [0, 2], "put": [0, 2, 3, 4, 5, 6, 25], "file_list": 0, "flexibl": [0, 24], "jobresult": [0, 5, 7], "estim": [0, 7, 25], "estimate_job": 0, "get_results_metadata_url": [0, 7], "list_result": 0, "last": [0, 2, 4, 5, 17, 23, 24], "occur": [0, 2], "insensit": [0, 2], "abov": [0, 2, 3, 4, 5, 16, 17, 18, 19, 24, 25, 26], "word": [0, 24], "run_synchron": [0, 7], "start_job": [0, 7, 11], "start_and_wait": [0, 5, 7, 22], "soft_error_max": 0, "till": 0, "sleep": 0, "soft": [0, 7], "temporari": [0, 7, 19], "glitch": 0, "queu": [0, 5], "stop_job": 0, "download_fil": [0, 5, 7], "directori": [0, 3, 5, 8, 11], "advertis": [0, 5, 7, 17], "include_stac_metadata": 0, "get_asset": [0, 5, 9], "resultasset": [0, 5, 7], "get_metadata": [0, 5], "forc": [0, 9], "href": [0, 5, 16], "chunk_siz": 0, "load_byt": 0, "load_json": [0, 5], "possibli": 0, "media": 0, "role": [0, 19, 25], "ecosystem": [0, 13, 21], "invalidtimeseriesexcept": 0, "datacube_from_fil": 0, "xarraydatacub": [0, 7, 25], "datacube_plot": 0, "plot": [0, 7, 12, 21], "datacube_to_fil": 0, "save_to_fil": 0, "timeseries_json_to_panda": [0, 4], "timeseri": [0, 1, 2, 5, 20, 24], "auto_collaps": 0, "panda": [0, 4, 11, 25], "datafram": [0, 4, 11], "multilevel": 0, "column": [0, 4, 22], "plai": [0, 3, 6, 24, 25], "mislead": 0, "overwrit": [0, 6], "build_process_dict": [0, 7, 26], "metadaa": 0, "builder": 0, "test": [0, 2, 7, 9, 11, 12, 13, 17, 20, 21, 25], "from_metadata": 0, "ll": [0, 4, 25, 26], "udf_data": 0, "udfdata": [0, 25], "proj": [0, 2], "datacube_list": 0, "feature_collection_list": 0, "structured_data_list": 0, "user_context": 0, "from_dict": 0, "udf_dict": 0, "get_datacube_list": 0, "get_feature_collection_list": 0, "get_structured_data_list": 0, "structureddata": 0, "set_datacube_list": 0, "set_structured_data_list": 0, "thin": [0, 25], "xarrai": [0, 7, 12, 21, 25], "dataarrai": [0, 7, 12, 25], "xdc_dict": 0, "get_arrai": [0, 25], "show_bandnam": 0, "show_dat": 0, "show_axeslabel": 0, "fontsiz": 0, "oversampl": 0, "cmap": [0, 12], "rdylbu_r": 0, "cbartext": 0, "to_fil": 0, "to_show": 0, "visual": [0, 5, 7, 12, 17, 25], "matplotlib": [0, 21], "drawn": 0, "noth": 0, "contour": 0, "row": [0, 11, 22], "font": 0, "color": 0, "colormap": 0, "blue": [0, 4, 14, 18, 26], "yellow": 0, "rainbow": 0, "legend": 0, "destin": 0, "hypercub": 0, "test_data": 0, "02": [0, 2, 4, 5, 12, 20, 24], "50": [0, 5, 12], "sphinx_autodoc_typehints_typ": 0, "structured_data": 0, "col_1": 0, "col_2": 0, "tabl": [0, 23], "properli": [0, 3, 4, 5, 7, 14, 17, 19, 21, 24, 26], "captur": 0, "help": [0, 1, 2, 3, 5], "variou": [0, 3, 4, 6, 7, 8, 14, 17, 19, 25], "bboxdict": 0, "from_sequ": 0, "seq": 0, "load_json_resourc": 0, "kind": [0, 1, 2, 3, 18, 19, 21, 24, 25], "remot": [0, 2, 4, 12, 20], "use_pyproj": 0, "wkt2": [0, 2], "At": [0, 2, 4, 8, 16, 21], "prefix": 0, "pyproj": [0, 7], "everyth": [0, 4, 24], "from_user_input": 0, "effort": [0, 4, 7], "done": [0, 3, 5, 13, 17], "look": [0, 2, 4, 6, 12, 15, 16, 17, 24], "leverag": [0, 4, 14, 19, 24], "valueerror": [0, 7], "to_bbox_dict": [0, 7], "unnecessari": 0, "strip": 0, "triangl": 0, "ashap": 0, "subclass": [0, 7], "graph_build": [0, 24], "_builder": 0, "factori": [0, 7], "might": [0, 3, 6, 14, 17, 19, 21, 26], "import": [0, 1, 2, 3, 4, 5, 6, 8, 11, 12, 13, 16, 17, 18, 20, 21, 24, 25, 26], "75": [0, 17, 26], "platform": [0, 7, 12, 14, 19], "2b": 0, "abstract": [0, 4, 7, 19, 25], "manipul": [0, 2, 25], "mixin": 0, "essenti": [0, 17], "direct": [0, 5, 25], "acycl": 0, "practic": [0, 7, 20, 25], "equival": [0, 2, 17, 24], "indirectli": 0, "meant": [0, 2], "from_flat_graph": 0, "unflatten": [0, 7], "deep": 0, "copi": [0, 3, 25], "reus": [0, 3, 4, 15, 20], "dedupl": 0, "to_process_graph_argu": 0, "subprocess": 0, "update_argu": [0, 7, 24], "much": [1, 2, 3, 4, 17, 20, 25, 26], "openeo": [1, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 19, 21, 22, 24, 26], "process": [1, 4, 5, 7, 9, 10, 13, 17, 19, 20, 22], "On": [1, 2, 3, 7, 9, 26], "syntact": [1, 2, 4], "sugar": [1, 2, 4], "translat": [1, 2, 17, 24], "build": [1, 2, 4, 6, 7, 16, 18, 20, 22, 24, 25], "graph": [1, 2, 4, 5, 7, 10, 12, 16, 17, 18, 20, 24, 25, 26], "let": [1, 2, 3, 4, 12, 18, 19, 22, 26], "snippet": [1, 2, 3, 4, 12, 17, 25], "we": [1, 2, 3, 4, 9, 12, 13, 16, 17, 18, 19, 22, 24, 25, 26], "def": [1, 2, 7, 11, 24, 25], "my_reduc": [1, 2], "conceptu": [1, 2], "howev": [1, 2, 3, 4, 5, 8, 16, 19, 22, 24, 25], "understand": [1, 2, 3, 6, 17, 25], "job": [1, 2, 3, 7, 9, 10, 13, 15, 20, 22, 25, 26], "statement": [1, 2, 4, 5, 6, 24], "precis": [1, 2], "concret": [1, 2, 19], "virtual": [1, 2, 19, 21, 25], "placehold": [1, 2, 19], "hint": [1, 2], "discov": [1, 2, 17], "editor": [1, 2, 5, 25, 26], "mix": [1, 2, 7, 24], "co": [1, 2, 23, 24], "compactli": [1, 2, 24, 26], "anonym": [1, 2, 3, 24], "block": [2, 4, 19, 24, 25, 26], "rest": [2, 3, 4, 7, 11, 20, 24, 25, 26], "datacub": [2, 4, 5, 7, 9, 10, 13, 14, 15, 17, 20, 22, 23, 24, 26], "compil": [2, 19], "offici": [2, 4, 7, 19, 20, 24, 26], "fix": [2, 19, 25], "bug": [2, 6, 7, 19, 26], "touch": 2, "address": [2, 3, 4, 7, 19], "upstream": [2, 19], "repositori": [2, 12, 19], "intern": [2, 6, 7, 15, 19, 24], "tool": [2, 5, 6, 7, 8, 12, 15, 17, 19, 20, 21, 25], "gener": [2, 4, 5, 7, 8, 10, 12, 17, 20, 25, 26], "level": [2, 5, 7, 17, 19, 20], "regular": [2, 3, 17, 24, 26], "stabl": 2, "propos": [2, 7, 19], "state": [2, 11], "signatur": [2, 7, 20, 24], "parent": [2, 24], "summand": 2, "sum": [2, 7, 18, 23, 24, 25], "toomanydimens": 2, "implicitli": 2, "immedi": 2, "geometrycollect": 2, "thu": [2, 9, 25], "maxim": 2, "furthermor": 2, "compos": [2, 12], "favour": 2, "targetdimensionexist": 2, "total": 2, "deriv": [2, 22], "suffix": [2, 7, 19], "_meta": 2, "total_count": 2, "valid_count": 2, "rectangular": 2, "decreas": 2, "3339": [2, 17], "although": [2, 17], "prohibit": 2, "most": [2, 3, 4, 5, 9, 12, 14, 17, 18, 19, 24, 25, 26], "en": 2, "wikipedia": 2, "wiki": 2, "9_decad": 2, "0_decad": 2, "yyyi": [2, 17], "mm": [2, 17], "dd": [2, 17], "00": [2, 4, 5, 12, 17, 25], "001": 2, "365": [2, 7], "36": [2, 5], "djf": 2, "mam": 2, "jja": 2, "son": 2, "ndjfma": 2, "mjjaso": 2, "yyy0": 2, "yyy1": 2, "complet": [2, 3, 7, 17, 24], "begin": 2, "2020": [2, 3, 4, 6, 13, 17, 18, 19, 20, 24, 26], "31": [2, 4, 20, 25, 26], "002": 2, "contrast": 2, "05": [2, 3, 6, 12, 13, 17, 20, 24, 26], "005": 2, "ignore_nodata": 2, "ignor": [2, 7, 11, 24], "and_": [2, 23], "anomali": [2, 23], "climatologi": 2, "daili": [2, 3], "monthli": [2, 3], "yearli": 2, "climatological_norm": [2, 23], "length": [2, 20], "stai": 2, "below": [2, 3, 11, 19, 23, 24, 25], "latter": [2, 3, 8, 22], "unless": [2, 19], "undefin": 2, "inner": 2, "outer": 2, "uneven": 2, "kerneldimensionsuneven": 2, "neighborhood": [2, 25], "physic": [2, 4, 20, 25], "measur": [2, 3], "m": [2, 19], "overli": 2, "onc": [2, 3, 4, 5, 17, 19, 25], "effect": [2, 25], "arcco": [2, 23, 24], "invers": 2, "cosin": 2, "radian": 2, "arcosh": [2, 23, 24], "hyperbol": 2, "arcsin": [2, 23], "sine": 2, "arctan": [2, 23], "tangent": 2, "arctan2": [2, 23, 24], "dividend": 2, "divisor": 2, "nrb": 2, "metadata": [2, 4, 5, 7, 9, 11, 12, 14, 16, 17, 19, 20, 26], "toa": 2, "aerosol": 2, "haze": 2, "ozon": 2, "water": [2, 7, 9, 14], "vapour": [2, 14], "imageri": 2, "No": [2, 7, 18, 21], "acquisit": 2, "incomplet": 2, "satur": 2, "successfulli": [2, 3, 5, 7, 19, 22, 26], "saturation_": 2, "water_vapor": 2, "clear": [2, 7, 17, 25], "snow": 2, "ic": 2, "assess": 2, "azimuth": 2, "sun": [2, 9], "illumin": 2, "occlus": 2, "dure": [2, 3, 5, 19], "off": [2, 8], "nadir": 2, "view": [2, 6, 9], "array_append": [2, 23], "labelexist": 2, "array_appli": [2, 23], "array_concat": [2, 7, 23], "array1": 2, "array2": 2, "array_contain": [2, 23], "check": [2, 4, 5, 12, 21, 25, 26], "array_cr": [2, 4, 7, 23], "nativ": [2, 17], "repeatedli": 2, "array_create_label": [2, 23], "array_el": [2, 7, 23], "return_nodata": 2, "arraynotlabel": 2, "arrayelementnotavail": 2, "flag": [2, 7, 16, 19], "array_filt": [2, 23], "array_find": [2, 23], "found": [2, 25], "array_find_label": [2, 23], "array_interpolate_linear": [2, 23], "interpol": 2, "natur": [2, 25], "inher": 2, "accordingli": [2, 7], "array_label": [2, 23], "array_modifi": [2, 7, 23], "insert": [2, 24], "simpler": 2, "fewer": 2, "arsinh": [2, 23], "artanh": [2, 23, 24], "exclude_max": 2, "comparison": [2, 4, 7], "ceil": [2, 23], "round": [2, 23], "climatology_period": 2, "span": 2, "consecut": 2, "winter": 2, "januari": 2, "climat": 2, "averag": [2, 17], "frequenc": [2, 5], "1981": 2, "until": [2, 4, 5], "2010": 2, "cloud_detect": [2, 23], "cosh": [2, 23, 24], "create_raster_cub": [2, 23], "cummax": [2, 23], "cumul": 2, "maxima": 2, "cummin": [2, 23], "minima": 2, "cumproduct": [2, 23], "cumsum": [2, 23], "date_shift": [2, 23], "compon": [2, 4, 7], "00z": 2, "midnight": [2, 17], "utc": [2, 7, 17], "millisecond": 2, "neg": 2, "leap": 2, "minut": [2, 3, 4, 5, 7], "divis": 2, "euler": 2, "eq": [2, 7, 23, 24], "delta": 2, "case_sensit": 2, "operand": 2, "especi": [2, 3], "circumv": [2, 17], "problem": [2, 17, 19, 24], "inaccuraci": 2, "lte": [2, 23], "ab": 2, "minu": 2, "sensit": [2, 3], "disabl": [2, 19], "exp": [2, 23], "exponenti": 2, "expon": 2, "extrema": [2, 23], "wavelength": 2, "micromet": 2, "\u03bcm": 2, "vertic": 2, "onethird": 2, "sqrt": [2, 23, 24], "restor": [2, 19], "curv": 2, "abl": [2, 3, 4, 25], "unambigu": 2, "revert": 2, "floor": [2, 23], "gt": [2, 23], "strictli": 2, "gte": [2, 23], "if_": [2, 23], "reject": 2, "Then": [2, 19], "els": [2, 6, 18, 21, 24], "log": [2, 4, 7, 11, 20, 23], "modif": 2, "is_infinit": [2, 23], "is_nan": [2, 23, 24], "is_nodata": [2, 23], "altern": [2, 4, 7], "further": [2, 3, 4, 5, 13, 18, 26], "gdal": 2, "ogr": 2, "formatunsuit": 2, "lt": [2, 12, 23], "everi": [2, 9, 12, 25], "arithmet": 2, "cube1": 2, "cube2": 2, "regard": [2, 6, 7], "mod": [2, 23], "modulo": 2, "remaind": 2, "multiplicand": 2, "nan": [2, 23], "neq": [2, 7, 23], "not_": [2, 23], "or_": [2, 23], "OR": 2, "asc": 2, "permut": 2, "ascend": 2, "smallest": 2, "descend": 2, "miss": [2, 7, 26], "pi": [2, 23], "\u03c0": 2, "quantil": [2, 23], "q": 2, "rearrang": [2, 23], "old": [2, 7, 25], "longer": [2, 3, 4], "enumer": 2, "labelsnotenumer": 2, "labelnotavail": 2, "gdalwarp": 2, "program": [2, 6, 24], "cmdoption": 2, "r": [2, 14, 25, 26], "bilinear": 2, "cubic": 2, "cubicsplin": 2, "spline": 2, "lanczo": 2, "med": 2, "appear": 2, "neighbour": 2, "q1": 2, "quartil": 2, "q3": 2, "rm": [2, 19], "quadrat": 2, "dimensionmismatch": 2, "search": [2, 12, 20, 25], "15": [2, 4, 12, 17, 19, 20, 25, 26], "warp": 2, "registri": 2, "iso": 2, "19162": 2, "opengeospati": 2, "010r7": 2, "quickstart": 2, "onto": 2, "decim": 2, "hundr": 2, "udf": [2, 20, 26], "configur": [2, 3, 7, 19, 20], "run_udf_extern": [2, 23], "host": [2, 19], "principl": [2, 6, 17], "interfac": [2, 20], "parametr": [2, 9], "deliv": 2, "sgn": [2, 23], "signum": 2, "sin": [2, 23], "sinh": [2, 23], "minuend": 2, "subtrahend": 2, "tan": [2, 23], "tanh": [2, 23], "text_begin": [2, 23], "text_concat": [2, 23], "text_contain": [2, 23], "text_end": [2, 23], "trim_cub": [2, 23], "flawlessli": 2, "varianc": [2, 23], "vector_buff": [2, 23], "distanc": [2, 4], "buffer": 2, "outward": 2, "dilat": [2, 18], "shrink": 2, "inward": 2, "eros": 2, "vector_to_random_point": [2, 23], "geometry_count": 2, "overal": [2, 9], "countmismatch": 2, "multipoint": 2, "present": [2, 17, 25], "vector_to_regular_point": [2, 23], "centroid": 2, "enclos": 2, "walk": 2, "previou": [2, 4, 12, 17, 25], "reach": [2, 5, 21], "again": [2, 3, 4, 17, 19, 25, 26], "xor": [2, 23], "interest": [3, 4, 5, 17], "api": [3, 4, 5, 7, 9, 10, 11, 12, 16, 17, 19, 20, 22, 26], "regist": [3, 11], "straightforward": [3, 5, 18, 24, 26], "situat": [3, 5, 24, 26], "illustr": [3, 4, 16, 17, 20, 26], "form": [3, 7, 17], "easiest": [3, 5, 19, 24], "scheme": 3, "secur": [3, 4], "certainli": [3, 9], "caveat": [3, 17], "j0hn123": 3, "user_id": 3, "abbrevi": [3, 25, 26], "ident": 3, "layer": [3, 4], "oauth": 3, "protocol": [3, 7], "depth": [3, 4, 24], "architectur": 3, "u": [3, 4, 16, 19], "far": [3, 4], "here": [3, 4, 6, 12, 13, 16, 17, 18, 19, 22, 24, 25, 26], "central": [3, 4, 24, 25], "concept": [3, 4, 17, 22], "quit": 3, "decoupl": 3, "organ": [3, 21], "googl": [3, 17], "microsoft": 3, "academ": 3, "research": 3, "institut": [3, 12], "forward": 3, "relev": [3, 5], "profil": [3, 6, 7, 20], "email": 3, "privaci": 3, "challeng": 3, "registr": 3, "establish": [3, 4], "organis": [3, 4], "act": 3, "scope": [3, 7, 17, 21], "grant": [3, 7], "pick": [3, 6], "clearli": [3, 7], "section": [3, 4, 8, 9, 17, 19], "explic": 3, "gl": 3, "browser": [3, 4, 19], "nice": [3, 4, 12, 17, 19, 25], "even": [3, 4, 5, 6, 7, 19, 25, 26], "mobil": 3, "phone": 3, "visit": [3, 4, 19], "net": 3, "enter": [3, 4, 19], "dtny": 3, "klnx": 3, "slightli": 3, "user_cod": 3, "now": [3, 4, 5, 7, 12, 18, 19, 22, 24, 25, 26], "intention": [3, 19], "feasibl": 3, "past": [3, 19, 25], "shown": [3, 5, 7, 19, 25], "won": 3, "ask": 3, "meanwhil": 3, "activ": [3, 19], "commun": [3, 6, 21, 22], "failur": [3, 7], "lifetim": 3, "risk": [3, 6], "stolen": 3, "intercept": 3, "rel": [3, 16, 17], "privat": [3, 16], "home": [3, 8], "bootstrap": 3, "involv": [3, 7], "technic": [3, 4, 6, 17, 22], "consult": [3, 16, 26], "wors": 3, "commit": 3, "fetch": [3, 5], "protect": 3, "databas": 3, "linux": [3, 19, 25], "bash": [3, 19], "shell": [3, 21], "cl13n7s3cr3t": 3, "123": [3, 7], "oidcprovid": 3, "oidcbearerauth": 3, "switch": [3, 5], "autom": 3, "unattend": 3, "manner": [3, 17, 25], "That": 3, "ideal": [3, 25], "occasion": [3, 24], "expir": [3, 7], "eas": 3, "usabl": [3, 4, 7], "come": [3, 4, 5, 6, 17, 25], "safe": 3, "pry": 3, "ey": [3, 5, 17, 21], "bad": [3, 7], "hard": [3, 6, 9, 17], "responsibli": 3, "share": [3, 7, 10, 17, 20], "imposs": [3, 6, 9], "solut": [3, 17, 19], "cach": [3, 7, 8], "accident": 3, "instal": [3, 7, 10, 20, 25], "subcommand": 3, "verbos": [3, 7, 8], "exit": 3, "perm": 3, "0o600": 3, "1414b": 3, "846b": 3, "redact": 3, "24t13": 3, "40": [3, 12], "50z": 3, "press": 3, "likewis": [3, 24, 26], "issuer": 3, "d7393fba": 3, "q7znsy": 3, "handi": [3, 4, 17], "former": [3, 22], "edit": [3, 8, 19], "manual": [3, 5, 7, 8, 10, 19], "default_backend": [3, 8], "auto_authent": [3, 8], "ini": [3, 8], "live": [3, 19], "becom": 3, "unus": [3, 7, 25], "luckili": [3, 24], "expiri": 3, "te": 3, "basi": 3, "weekli": 3, "term": [3, 14, 22], "sai": [3, 24, 26], "suit": [3, 19], "heavili": [3, 4, 21], "cli": 3, "verifi": [3, 7, 19], "2022": [3, 5, 12, 17, 20, 25], "11t13": 3, "20z": 3, "person": [3, 6, 19], "peopl": [3, 6, 22], "publicli": [3, 4, 10, 26], "permiss": [3, 4, 7, 19], "suspect": 3, "culprit": 3, "know": [3, 5, 19, 25], "refreshtokenstor": [3, 7], "vito": [4, 9, 13, 16, 19, 20], "terrascop": [4, 13, 16], "gatewai": [4, 7], "monitor": [4, 5, 6], "hub": [4, 9, 17], "explor": 4, "fundament": 4, "satellit": [4, 7, 14], "preprocess": [4, 9, 17], "programmat": [4, 5, 17], "sentinel1_grd": [4, 9, 17], "sentinel2_l2a": [4, 14, 17, 25, 26], "stac_vers": 4, "congrat": 4, "real": [4, 18], "queri": [4, 17, 24], "jupyt": [4, 7, 12, 15, 17, 20, 21, 25], "notebook": [4, 5, 6, 7, 12, 17, 21, 25], "integr": [4, 7, 21], "graphic": [4, 5, 25], "render": [4, 7, 12, 15, 17, 25], "trivial": 4, "offer": [4, 6, 9, 17, 24], "fairli": [4, 25], "topic": 4, "streamlin": [4, 6, 19], "aai": 4, "egi": 4, "eu": [4, 9], "realm": 4, "sluo": 4, "bmud": 4, "goe": 4, "task": [4, 24], "ndwi": 4, "tutori": [4, 6], "go": [4, 16, 19], "enhanc": 4, "infrar": [4, 14], "spatio": [4, 5, 17], "slice": [4, 24, 25], "sentinel2_cub": [4, 26], "2021": [4, 5, 16, 17, 20, 26], "04": [4, 17, 20, 25], "b02": [4, 9, 12, 17, 22, 25, 26], "b04": [4, 9, 12, 13, 17, 22, 25, 26], "b08": [4, 12, 26], "region": [4, 5, 17], "earli": 4, "low": [4, 17], "chapter": 4, "fusion": 4, "highlight": [4, 6, 25], "encapsul": [4, 16, 18, 25, 26], "happen": [4, 21, 25], "pipelin": [4, 24], "rescal": [4, 14, 20], "0001": [4, 25, 26], "evi_cub": [4, 25], "our": [4, 12, 25, 26], "mathemat": [4, 24, 26], "compact": [4, 17], "peek": 4, "loadcollection1": [4, 15, 26], "multiply1": 4, "multiply3": 4, "from_nod": [4, 18, 26], "subtract1": [4, 26], "aspect": [4, 24, 25, 26], "deciph": 4, "assur": 4, "worri": [4, 24, 26], "behind": [4, 24], "scene": 4, "elimin": [4, 7, 22, 25], "evi_composit": 4, "conveni": [4, 13, 25], "composit": 4, "tiff": [4, 5, 20, 26], "impact": [4, 17, 25], "artefact": 4, "bare": 4, "quick": [4, 6, 25], "hit": [4, 8, 17], "constraint": [4, 20], "disconnect": 4, "reconnect": 4, "mention": [4, 18], "sen2cor": 4, "unwant": 4, "scl": [4, 12], "s2_scl": 4, "scl_band": 4, "mask_resampl": 4, "evi_cube_mask": [4, 25], "lot": [4, 17, 24, 25], "valuabl": 4, "analysi": [4, 7, 10, 17, 20], "1417": 4, "1785": 4, "1414": 4, "1772": 4, "1444": 4, "1768": 4, "1443": 4, "179": 4, "156": 4, "1892": 4, "155": [4, 7], "1855": 4, "163": 4, "1891": 4, "inlin": [4, 24, 25], "experi": [4, 12, 19], "evi_mask": 4, "evi_aggreg": [4, 26], "csv": [4, 11], "flesh": 4, "bear": 4, "mind": 4, "massag": 4, "pd": [4, 11], "convers": [4, 7, 20, 24, 26], "df": [4, 11], "to_datetim": 4, "dropna": 4, "b": [4, 14], "final": [4, 9, 17, 19, 22, 26], "06": [4, 5, 12, 13, 17, 20, 24, 26], "522499": 4, "300250": 4, "529591": 4, "288079": 4, "633011": 4, "327598": 4, "reli": [4, 12], "heavier": 5, "intens": 5, "enforc": [5, 7, 19], "life": 5, "cycl": 5, "prefer": [5, 19, 24, 25, 26], "feel": [5, 6, 19, 20, 21], "free": [5, 17, 21, 24], "tab": [5, 7], "action": [5, 7, 19], "button": [5, 19], "explicit": [5, 8, 21, 24, 25], "connect": [5, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 26], "d5b8b8f2": 5, "74ce": 5, "4c2e": 5, "b06d": 5, "bff6f9b14b8d": 5, "5d806224": 5, "fe79": 5, "4a54": 5, "be04": 5, "90757893795b": 5, "overview": [5, 19], "08t08": 5, "58": 5, "11z": 5, "4e720e70": 5, "88bd": 5, "40bc": 5, "92db": 5, "a366985ebd67": 5, "04t14": 5, "46": [5, 12], "06z": 5, "pretti": 5, "didn": 5, "reliabl": 5, "loop": [5, 7, 24], "b0e8adcf": 5, "087f": 5, "41de": 5, "afe6": 5, "b3c0ea88ff38": 5, "35": 5, "03": [5, 9, 17, 20, 25, 26], "28": 5, "creation": [5, 7, 13], "f9f4e3d3": 5, "bc13": 5, "441b": 5, "b76a": 5, "b7bfd3b59669": 5, "tune": [5, 7, 14, 18, 19, 26], "stat": [5, 25], "moreov": [5, 24, 25], "own": [5, 6, 25, 26], "log001": 5, "worker": [5, 25], "log002": 5, "5x3x6": 5, "tile": 5, "log003": 5, "corrupt": 5, "j9a7k2": 5, "instruct": [5, 25], "investig": 5, "68caccff": 5, "54ee": 5, "470f": 5, "abaa": 5, "559ed2d4e53c": 5, "57da31da": 5, "7fd4": 5, "463a": 5, "9d7d": 5, "c9c51646b6a4": 5, "fact": [5, 6, 15, 17, 25], "res001": 5, "432f3b3ef3a": 5, "res002": 5, "plural": 5, "singular": 5, "startswith": 5, "v2": 5, "skip": [5, 7, 17, 19], "24t10": 5, "59": 5, "23z": 5, "guidelin": [6, 25], "demo": [6, 12], "softwar": 6, "engin": [6, 7], "secondli": 6, "wider": 6, "audienc": [6, 21, 22], "invit": 6, "irrelev": 6, "settl": 6, "convent": [6, 12, 14, 17, 19], "alon": 6, "bar": [6, 7, 11], "faster": 6, "someon": 6, "apart": [6, 17], "tast": 6, "rule": [6, 19, 25], "human": 6, "minim": [6, 7, 26], "languag": [6, 17, 24], "strong": 6, "focu": [6, 22, 25], "design": [6, 17, 25], "strongli": 6, "gravit": 6, "strict": [6, 7], "pep8": 6, "mother": 6, "guid": [6, 14], "black": 6, "traction": 6, "popular": 6, "high": [6, 20], "orient": [6, 24], "space": [6, 9, 17], "star": 6, "seem": 6, "bunch": 6, "reader": 6, "figur": [6, 25], "strang": 6, "silent": 6, "desktop": 6, "plenti": 6, "nowadai": 6, "screen": 6, "tight": 6, "viewport": 6, "scroll": 6, "annoi": [6, 24], "unnecessarili": [6, 7, 17], "notori": 6, "parenthesi": 6, "hoc": [6, 19], "s2_fapar": 6, "terrascope_s2_fapar_v2": 6, "138916": 6, "524124": 6, "48": 6, "1386": 6, "320647": 6, "client_vers": [6, 21], "notabl": [7, 18], "adher": 7, "semant": [7, 19], "apply_datacub": [7, 25], "310": [7, 16], "331": 7, "424": 7, "awesom": [7, 14], "sentinel2": [7, 13, 14, 22, 25], "landsat8": [7, 14], "lack": 7, "485": 7, "501": 7, "401": 7, "tokeninvalid": 7, "403": 7, "508": 7, "ndgi": 7, "ndmi": [7, 14], "s2wi": 7, "extra": [7, 11, 14, 19, 21], "were": [7, 24, 25], "introduc": [7, 19, 21, 25], "openeoapiplainerror": 7, "openeoapierror": 7, "491": 7, "localconnect": [7, 12], "493": 7, "404": 7, "sentinel1": 7, "484": 7, "421": 7, "parameter": [7, 24], "471": 7, "udp": [7, 10, 20, 25], "unhelp": 7, "anywai": 7, "442": 7, "bump": [7, 19], "460": 7, "470": 7, "harder": 7, "259": 7, "vectorcub": [7, 15, 20, 23, 24], "driver": [7, 25], "197": 7, "425": 7, "459": 7, "454": 7, "multibackendjobmanag": [7, 10, 11], "452": 7, "localprocess": [7, 12], "451": 7, "vectocub": 7, "449": 7, "dask": [7, 12], "io": 7, "cookbook": [7, 20], "doubl": [7, 15, 17, 21], "448": 7, "renew": 7, "436": 7, "alias": 7, "280": 7, "spectral_indic": [7, 14], "v0": [7, 19], "env": [7, 19], "var": 7, "419": 7, "oidcdevicecodepolltimeout": 7, "demand": [7, 21], "433": 7, "ensur": [7, 25], "443": 7, "431": 7, "237": 7, "parse_datetim": 7, "418": 7, "377": 7, "openeo_processes_dask": 7, "packag": [7, 19, 21, 25], "338": 7, "userfil": [7, 20], "386": 7, "390": 7, "clariti": 7, "412": 7, "170": 7, "134": 7, "imagecollectioncli": 7, "leftov": 7, "reinstat": 7, "privatejsonfil": 7, "permissionerror": 7, "387": 7, "mlmodel": [7, 20, 22, 23], "robust": 7, "currenc": 7, "414": 7, "blindli": [7, 25], "conda": [7, 19], "forg": [7, 19, 21], "176": 7, "332": 7, "timezon": 7, "util": [7, 20], "todai": 7, "utcnow": 7, "fine": [7, 14, 18, 19, 26], "repr": [7, 15], "336": 7, "346": 7, "335": 7, "361": 7, "resili": 7, "502": 7, "352": 7, "math": [7, 20, 24, 25, 26], "oschmod": 7, "198": 7, "broken": 7, "350": 7, "328": 7, "hidden": [7, 24], "rework": 7, "312": 7, "autodetect": 7, "from_paramet": [7, 18, 24, 25, 26], "distutil": 7, "loosevers": 7, "316": 7, "oidc_auth_user_id_token_as_bear": 7, "workaround": 7, "326": 7, "323": 7, "324": 7, "dimensionalreadyexistsexcept": 7, "geopyspark": 7, "205": 7, "caus": [7, 17], "209": 7, "317": 7, "friendli": [7, 17], "tweak": [7, 19], "285": 7, "286": 7, "308": 7, "309": 7, "hardcod": [7, 18, 26], "h5netcdf": [7, 21], "xarrayio": 7, "from_netcdf_fil": 7, "to_netcdf_fil": 7, "314": 7, "confus": [7, 19, 22, 25, 26], "291": 7, "293": 7, "advanc": [7, 17], "_pg": 7, "hack": 7, "184": 7, "298": 7, "302": 7, "304": 7, "zonal_statist": 7, "144": 7, "279": 7, "284": 7, "288": 7, "264": 7, "187": 7, "mortem": 7, "date_range_filt": 7, "bbox_filt": 7, "278": 7, "276": 7, "autogener": [7, 23], "draft": [7, 26], "e4df8648": 7, "274": 7, "275": 7, "287": 7, "openeo_basemap_url": 7, "templat": 7, "basemap": 7, "vue": 7, "openeo_basemap_attribut": 7, "attribut": [7, 12], "260": 7, "feder": 7, "mistakenli": [7, 24], "builtin": [7, 24, 25], "forum": [7, 19, 21], "113": 7, "91": 7, "242": 7, "urban": [7, 14], "unavail": 7, "96": 7, "nor": 7, "225": 7, "410": 7, "ep": 7, "4008": 7, "proper": [7, 25], "229": 7, "228": 7, "4011": 7, "4012": 7, "233": 7, "processgraphvisitexcept": [7, 18], "processgraphvisitor": 7, "resolve_from_nod": 7, "invok": [7, 9, 11, 24, 25, 26], "nicer": 7, "247": 7, "outdat": 7, "restfil": 7, "115": 7, "minor": [7, 19], "processgraphunflatten": 7, "pgnodegraphunflatten": 7, "3609": 7, "op": 7, "plain": [7, 25], "migrat": 7, "travi": 7, "ci": 7, "178": 7, "3645": 7, "210": 7, "204": 7, "3846": 7, "comparablevers": 7, "parse_d": 7, "parse_date_or_datetim": 7, "disallow": 7, "redirect": 7, "200": 7, "3889": 7, "joblogentri": 7, "got": 7, "tiled_viewing_servic": 7, "159": 7, "190": 7, "3578": 7, "192": 7, "366": 7, "373": 7, "openeo_udf": 7, "domain": 7, "201": 7, "o": [7, 17], "chmod": 7, "191": 7, "3700": 7, "friendlier": 7, "202": 7, "break": [7, 16], "182": 7, "pagin": 7, "lookup": 7, "3670": 7, "microsecond": 7, "solv": [7, 24], "slower": 7, "grain": 7, "3739": 7, "mark": [7, 19], "spec": [7, 12, 19, 26], "mainten": [7, 20, 21, 25], "overhead": 7, "136": 7, "3698": 7, "3687": 7, "221": 7, "3612": 7, "decompress": 7, "175": 7, "lazili": 7, "157": 7, "158": 7, "clone": [7, 12, 19], "3359": 7, "duplic": 7, "list_processgraph": 7, "3617": 7, "authconfig": 7, "config": [7, 8, 19, 20], "stretch_color": 7, "dereference_from_node_argu": 7, "3509": 7, "3544": 7, "147": 7, "3585": 7, "assembl": [7, 24], "3555": 7, "153": 7, "3456": 7, "3485": 7, "timinglogg": 7, "decor": 7, "3377": 7, "3493": 7, "3496": 7, "focuss": [8, 26], "uncommon": 8, "sens": [8, 17, 20, 24], "moment": [8, 19, 25], "maintain": [8, 19, 25], "comment": 8, "probe": 8, "openeo_client_config": 8, "openeo_config_hom": 8, "xdg_config_hom": 8, "suffici": [9, 25], "few": 9, "scenario": 9, "ceo": 9, "ard": 9, "computation": 9, "expens": [9, 25], "affect": 9, "henc": [9, 17], "decis": 9, "l1c": 9, "varieti": 9, "uncorrect": 9, "brdf": 9, "v1": [9, 12], "toolbox": 9, "davidfrantz": 9, "icor": 9, "smac": 9, "atmoshper": 9, "remotesens": 9, "olivierhagol": 9, "sentinel2_l1c_sentinelhub": 9, "758216409030558": 9, "087806252": 9, "291835566": 9, "3927399": 9, "2017": 9, "b03": [9, 12, 17, 22, 25], "b09": 9, "b8a": 9, "b11": 9, "sunazimuthangl": 9, "sunzenithangl": 9, "viewazimuthmean": 9, "viewzenithmean": 9, "synthet": 9, "apertur": 9, "signific": 9, "calibr": [9, 13], "grd": 9, "esa": 9, "sentinelhub": 9, "s1grd": 9, "vh": 9, "vv": 9, "59003": 9, "8949": 9, "2206": 9, "069": 9, "orfeo": 9, "readi": [10, 20], "scalabl": 10, "publish": [10, 18, 19], "public": [10, 12, 13, 17], "append_and_rescale_indic": [10, 14], "append_index": [10, 14], "append_indic": [10, 14], "compute_and_rescale_indic": [10, 14], "compute_index": [10, 14], "compute_indic": [10, 14], "list_indic": [10, 14], "add_backend": [10, 11], "ensure_job_dir_exist": [10, 11], "get_error_log_path": [10, 11], "get_job_dir": [10, 11], "get_job_metadata_path": [10, 11], "on_job_don": [10, 11], "on_job_error": [10, 11], "run_job": [10, 11], "ignore_connection_error": [10, 11], "miscellan": [10, 20], "tip": [10, 20, 21], "trick": [10, 20], "job_manag": 11, "poll_sleep": 11, "root_dir": 11, "tracker": [11, 21], "jobs_df": 11, "output_fil": 11, "parallel_job": 11, "getter": 11, "parallel": 11, "overridden": 11, "status": 11, "amongst": 11, "connection_provid": 11, "rememb": [11, 13], "parser": 12, "networkx": 12, "2023": [12, 17, 20, 23], "pip": [12, 19], "infrastructur": 12, "zarr": 12, "parti": 12, "guarante": [12, 25], "l2a": [12, 13], "coverag": 12, "local_conn": 12, "aw": 12, "element84": 12, "47": 12, "s2_cube": [12, 25], "stackstac": 12, "08730b1b5458a4ed34edeee60ac79254": 12, "177": 12, "11354": 12, "8025": 12, "getitem": 12, "dtype": 12, "float64": 12, "chunksiz": 12, "1024": 12, "chunktyp": 12, "numpi": [12, 24, 25], "53": 12, "datetime64": 12, "u24": 12, "s2b_32tpr_20190102_": 12, "u3": 12, "52e": 12, "323e": 12, "21e": 12, "096e": 12, "s2": [12, 14], "product_uri": 12, "u65": 12, "s2b_msil2a_20190102": 12, "data_typ": 12, "gsd": 12, "int32": 12, "center_wavelength": 12, "665": 12, "full_width_half_max": 12, "038": 12, "rasterspec": 12, "600000": 12, "4990200": 12, "809760": 12, "5300040": 12, "git": [12, 19, 21], "local_data_fold": 12, "sample_netcdf": 12, "sample_geotiff": 12, "similar": [12, 24], "local_collect": 12, "s2_l2a_sampl": 12, "nc": [12, 25], "s2_datacub": 12, "correctli": [12, 24, 25], "705": 12, "935": 12, "float32": 12, "27": [12, 20, 26], "75e": 12, "843e": 12, "155e": 12, "148e": 12, "s1": [12, 14], "cf": [12, 19], "geotrelli": [12, 25], "5a1": 12, "lazi": 12, "addition": [12, 14], "ndvi_median": 12, "result_ndvi": 12, "imshow": 12, "green": 12, "25": [12, 20, 25], "80": [12, 17], "copernicu": 13, "dataspac": 13, "rather": 13, "tabular": 13, "spars": 13, "sample_by_featur": 13, "s2_band": 13, "auth_connect": 13, "terrascope_s2_toc_v2": 13, "artifactori": [13, 19], "vgt": [13, 19], "testdata": 13, "parcel": [13, 17], "test_10": 13, "transfer": [13, 18], "cheap": 13, "cours": 13, "continent": 13, "impract": 13, "100x100km": 13, "utm": 13, "zone": 13, "auxiliari": 14, "subpackag": 14, "david": 14, "montero": 14, "loaiza": 14, "wv": 14, "long_nam": 14, "obvious": 14, "haven": 14, "variable_map": 14, "swir": 14, "index_dict": 14, "respond": 14, "input_rang": 14, "8000": [14, 19], "output_rang": 14, "250": 14, "recogn": 14, "unhandl": 14, "attach": [14, 19], "export_path": 15, "write_text": 15, "utf8": 15, "naiv": 15, "roughli": [15, 18, 19], "quot": 15, "jsonbin": 15, "beta": [16, 19], "juli": 16, "ticket": 16, "fahrenheit": [16, 26], "fahrenheit_to_celsiu": [16, 26], "sharabl": 16, "johndo": 16, "to_celsiu": 16, "86": 16, "unrol": 16, "udp_url": 16, "dive": 17, "deeper": 17, "notic": 17, "criteria": 17, "carefulli": [17, 21], "retent": 17, "polici": 17, "archiv": [17, 19], "Such": 17, "viewer": 17, "drastic": 17, "licens": 17, "question": 17, "d": 17, "good": [17, 19, 25, 26], "idea": [17, 25], "intermedi": 17, "39": 17, "gradual": [17, 19], "stage": [17, 19], "infer": [17, 25], "yourself": [17, 19, 24], "world": 17, "4623": 17, "wg": 17, "84": 17, "lat": 17, "granular": 17, "finer": 17, "34": 17, "56": 17, "17t12": 17, "56z": 17, "half": 17, "instant": [17, 25], "________": 17, "____________": 17, "_________________________": 17, "_____": 17, "000": 17, "unintuit": 17, "pitfal": 17, "unintend": 17, "dedic": [17, 25], "orbit": 17, "relativeorbitnumb": 17, "116": 17, "unfortun": 17, "413": 17, "payload": 17, "drive": 17, "dropbox": 17, "master": [17, 19], "example_aoi": 17, "pq": 17, "parquet": 17, "geoparquet": 17, "sentinel2_toc": 18, "reusabl": [18, 24, 25, 26], "imagin": 18, "masked_s2": 18, "09": [18, 20, 26], "evi": [18, 20], "p1": 18, "div": 18, "raw_json": 18, "lc": 18, "ak": 18, "my_udp": 18, "toi": 18, "substitut": 18, "105": 18, "todo": [18, 25], "checkout": [19, 21], "dev": [19, 21], "pytest": 19, "framework": 19, "ton": 19, "sphinx": 19, "plugin": 19, "makefil": 19, "msphinx": 19, "_build": 19, "127": 19, "tediou": 19, "rebuild": 19, "autobuild": 19, "reload": 19, "watch": 19, "magic": 19, "greatli": 19, "appreci": 19, "welcom": [19, 20], "tradit": 19, "pr": 19, "fork": 19, "push": 19, "repo": 19, "branch": 19, "review": 19, "piggyback": 19, "simplest": [19, 25], "global": 19, "pipx": 19, "homebrew": 19, "across": [19, 25], "hook": 19, "sandbox": 19, "yaml": 19, "freshli": 19, "linter": 19, "formatt": 19, "clean": 19, "excess": 19, "whitespac": 19, "violat": 19, "intrus": 19, "hang": 19, "prepar": [19, 25, 26], "temporarili": 19, "pypi": [19, 21], "tag": 19, "twine": 19, "wheel": 19, "jenkin": 19, "recent": 19, "setuptool": 19, "setup": [19, 21], "_version": 19, "a1": 19, "alpha": 19, "collis": 19, "__version__": 19, "0a1": 19, "changelog": [19, 20], "md": 19, "unreleas": [19, 20, 21], "inject": [19, 26], "uncommit": 19, "subsect": 19, "surpris": 19, "artifact": 19, "zip": [19, 25], "unzip": 19, "py3": 19, "whl": 19, "bdist_wheel": 19, "dist": 19, "histori": 19, "docker": 19, "burn": 19, "dep": 19, "recip": 19, "regro": 19, "autotick": 19, "bot": 19, "meta": [19, 25, 26], "tweet": 19, "announc": 19, "subshel": 19, "onelin": 19, "cd": 19, "tmp": 19, "venv": [19, 21], "bin": 19, "c": [19, 21, 26], "pure": [19, 21], "sometim": [19, 25, 26], "openeopycli": 19, "via": 19, "semi": 19, "submodul": 19, "subrepo": 19, "process_map": 19, "rst": 19, "terrascope_s2_ndvi_v2": 20, "ndvi_10m": 20, "004": 20, "asynchron": [20, 26], "terminologi": 20, "troubleshoot": 20, "smooth": 20, "releas": [20, 21], "inspir": 20, "lab": 20, "srr5": 20, "ux": 20, "lps22": 20, "srr3": 20, "goal": [21, 25], "unlock": 21, "broad": 21, "pollut": 21, "upgrad": 21, "modulenotfounderror": 21, "restart": 21, "fresh": 21, "went": 21, "troubl": [21, 24], "netcdf4": 21, "load_dataset": 21, "visualis": 21, "heavi": 22, "crop": 22, "feature_collect": 22, "b3dw": 22, "wd23": 22, "r8dh": 22, "3jkd": 22, "confusingli": 22, "somewhat": 22, "gi": 22, "simplic": 22, "training_job": 22, "classifi": 22, "__add__": 23, "__radd__": 23, "__and__": 23, "__getitem__": 23, "__truediv__": 23, "__rtruediv__": 23, "__eq__": 23, "ge": 23, "__ge__": 23, "__gt__": 23, "le": 23, "__le__": 23, "__lt__": 23, "__mul__": 23, "__rmul__": 23, "__neg__": 23, "__ne__": 23, "__invert__": 23, "__or__": 23, "__pow__": 23, "__rpow__": 23, "__sub__": 23, "__rsub__": 23, "togeth": [24, 26], "Being": 24, "accustom": 24, "expans": 24, "prescrib": 24, "finetun": 24, "feature_flag": 24, "rxpk": 24, "core": 24, "wish": 24, "liter": 24, "realiti": 24, "twice": 24, "load_my_vector_cub": 24, "onlin": 24, "geo": 24, "db": 24, "pseudocod": 24, "commonli": 24, "fanci": [24, 26], "think": 24, "avg": 24, "fashion": [24, 25], "intuit": 24, "scipi": [24, 25], "incorrectli": 24, "wrongli": 24, "runtimeerror": 24, "exceed": 24, "0x7f6505a40d00": 24, "knowledg": [24, 25], "gap": 25, "rudimentari": 25, "impress": 25, "rescaled_cub": 25, "glue": 25, "postprocess": 25, "penalti": 25, "transpar": 25, "smaller": 25, "isol": 25, "Their": 25, "freedom": 25, "entrypoint": 25, "apply_metadata": 25, "computed_band_1": 25, "computed_band_2": 25, "apply_timeseri": 25, "apply_udf_data": 25, "thousand": 25, "modu": 25, "operandi": 25, "effici": 25, "annot": 25, "cite": 25, "standalon": 25, "stuck": 25, "adjust": 25, "udf_modify_spati": 25, "np": 25, "input_metadata": 25, "xstep": 25, "ystep": 25, "new_metadata": 25, "reference_system": 25, "fancy_upsample_funct": 25, "assert": 25, "ndim": 25, "cubearrai": 25, "init_pixel_size_x": 25, "coord": 25, "init_pixel_size_i": 25, "predicted_arrai": 25, "coord_x": 25, "linspac": 25, "num": 25, "coord_i": 25, "predicted_cub": 25, "dim": 25, "udf_cod": 25, "read_text": 25, "cube_upd": 25, "jep": 25, "128": 25, "px": 25, "_without_": 25, "ai": 25, "abil": 25, "coher": 25, "128x128": 25, "112": 25, "output_cub": 25, "inputs_cub": 25, "my_udf": 25, "savitzki": 25, "golai": 25, "smoother": 25, "smooth_savitzky_golai": 25, "signal": 25, "savgol_filt": 25, "interpolate_na": 25, "smoothed_arrai": 25, "smoothing_udf": 25, "smoothed_evi": 25, "advantag": 25, "preced": 25, "my_process": 25, "test_input": 25, "primari": 25, "aid": 25, "pointer": 25, "prepend": 25, "unzipped_virtualenv_loc": 25, "adopt": 25, "offlin": 25, "turn": [25, 26], "tif": 25, "profile_dump": 25, "tar": 25, "gz": 25, "rdd_": 25, "pstat": 25, "rdd": 25, "correl": 25, "spark": 25, "ui": 25, "kcachegrind": 25, "distribut": 25, "connector": 25, "pyprof2calltre": 25, "interesting_rdd_id": 25, "restat": 25, "print_stat": 25, "achiev": 25, "suppos": 25, "3x256x256": 25, "prior": 25, "inconsist": 25, "cumbersom": 25, "futur": 25, "uniform": 25, "everywher": 25, "reoccur": 26, "mechan": 26, "ultim": 26, "expos": 26, "celsiu": 26, "subtract32": 26, "divide18": 26, "70": 26, "speak": 26, "fahrenheit_param": 26, "cousin": 26, "size_param": 26, "constructor": 26, "briefli": 26, "primit": 26, "divide1": 26, "sentinel2_l2a_sentinelhub": 26, "wrong": 26, "fancy_load_collect": 26, "w": 26, "fahrenheittocelsius1": 26, "11111111111111": 26, "evi_timeseri": 26, "laid": 26, "2018": 26, "temporal_interv": 26, "time_window": 26, "1793": 26, "2498": 26, "1787": 26, "2467": 26, "1852": 26, "2450": 26, "1867": 26, "2453": 26, "1873": 26, "2491": 26}, "objects": {"openeo.api": [[0, 0, 0, "-", "logs"], [0, 0, 0, "-", "process"]], "openeo.api.logs": [[0, 1, 1, "", "LogEntry"], [0, 2, 1, "", "normalize_log_level"]], "openeo.api.process": [[0, 1, 1, "", "Parameter"]], "openeo.api.process.Parameter": [[0, 3, 1, "", "array"], [0, 3, 1, "", "boolean"], [0, 3, 1, "", "datacube"], [0, 3, 1, "", "integer"], [0, 3, 1, "", "number"], [0, 3, 1, "", "object"], [0, 3, 1, "", "raster_cube"], [0, 3, 1, "", "string"], [0, 3, 1, "", "to_dict"]], "openeo": [[0, 2, 1, "", "connect"], [0, 0, 0, "-", "metadata"], [2, 0, 0, "module-0", "processes"], [0, 0, 0, "-", "util"]], "openeo.extra": [[11, 0, 0, "-", "job_management"], [14, 0, 0, "-", "spectral_indices"]], "openeo.extra.job_management": [[11, 1, 1, "", "MultiBackendJobManager"], [11, 2, 1, "", "ignore_connection_errors"]], "openeo.extra.job_management.MultiBackendJobManager": [[11, 3, 1, "", "add_backend"], [11, 3, 1, "", "ensure_job_dir_exists"], [11, 3, 1, "", "get_error_log_path"], [11, 3, 1, "", "get_job_dir"], [11, 3, 1, "", "get_job_metadata_path"], [11, 3, 1, "", "on_job_done"], [11, 3, 1, "", "on_job_error"], [11, 3, 1, "", "run_jobs"]], "openeo.extra.spectral_indices": [[14, 2, 1, "", "append_and_rescale_indices"], [14, 2, 1, "", "append_index"], [14, 2, 1, "", "append_indices"], [14, 2, 1, "", "compute_and_rescale_indices"], [14, 2, 1, "", "compute_index"], [14, 2, 1, "", "compute_indices"], [14, 2, 1, "", "list_indices"]], "openeo.internal": [[0, 0, 0, "-", "graph_building"]], "openeo.internal.graph_building": [[0, 1, 1, "", "FlatGraphableMixin"], [0, 1, 1, "", "PGNode"]], "openeo.internal.graph_building.FlatGraphableMixin": [[0, 3, 1, "", "print_json"], [0, 3, 1, "", "to_json"]], "openeo.internal.graph_building.PGNode": [[0, 3, 1, "", "flat_graph"], [0, 3, 1, "", "from_flat_graph"], [0, 3, 1, "", "to_dict"], [0, 3, 1, "", "to_process_graph_argument"], [0, 3, 1, "", "update_arguments"]], "openeo.metadata": [[0, 1, 1, "", "BandDimension"], [0, 1, 1, "", "CollectionMetadata"], [0, 1, 1, "", "SpatialDimension"], [0, 1, 1, "", "TemporalDimension"]], "openeo.metadata.BandDimension": [[0, 3, 1, "", "append_band"], [0, 3, 1, "", "band_index"], [0, 3, 1, "", "band_name"], [0, 3, 1, "", "filter_bands"], [0, 3, 1, "", "rename_labels"]], "openeo.metadata.CollectionMetadata": [[0, 3, 1, "", "add_dimension"], [0, 3, 1, "", "append_band"], [0, 3, 1, "", "assert_valid_dimension"], [0, 4, 1, "", "band_dimension"], [0, 4, 1, "", "band_names"], [0, 4, 1, "", "bands"], [0, 3, 1, "", "drop_dimension"], [0, 3, 1, "", "filter_bands"], [0, 3, 1, "", "reduce_dimension"], [0, 3, 1, "", "reduce_spatial"], [0, 3, 1, "", "rename_dimension"], [0, 3, 1, "", "rename_labels"]], "openeo.metadata.SpatialDimension": [[0, 3, 1, "", "rename"]], "openeo.metadata.TemporalDimension": [[0, 3, 1, "", "rename"]], "openeo.processes": [[2, 1, 1, "", "ProcessBuilder"], [2, 2, 1, "", "absolute"], [2, 2, 1, "", "add"], [2, 2, 1, "", "add_dimension"], [2, 2, 1, "", "aggregate_spatial"], [2, 2, 1, "", "aggregate_spatial_window"], [2, 2, 1, "", "aggregate_temporal"], [2, 2, 1, "", "aggregate_temporal_period"], [2, 2, 1, "", "all"], [2, 2, 1, "", "and_"], [2, 2, 1, "", "anomaly"], [2, 2, 1, "", "any"], [2, 2, 1, "", "apply"], [2, 2, 1, "", "apply_dimension"], [2, 2, 1, "", "apply_kernel"], [2, 2, 1, "", "apply_neighborhood"], [2, 2, 1, "", "arccos"], [2, 2, 1, "", "arcosh"], [2, 2, 1, "", "arcsin"], [2, 2, 1, "", "arctan"], [2, 2, 1, "", "arctan2"], [2, 2, 1, "", "ard_normalized_radar_backscatter"], [2, 2, 1, "", "ard_surface_reflectance"], [2, 2, 1, "", "array_append"], [2, 2, 1, "", "array_apply"], [2, 2, 1, "", "array_concat"], [2, 2, 1, "", "array_contains"], [2, 2, 1, "", "array_create"], [2, 2, 1, "", "array_create_labeled"], [2, 2, 1, "", "array_element"], [2, 2, 1, "", "array_filter"], [2, 2, 1, "", "array_find"], [2, 2, 1, "", "array_find_label"], [2, 2, 1, "", "array_interpolate_linear"], [2, 2, 1, "", "array_labels"], [2, 2, 1, "", "array_modify"], [2, 2, 1, "", "arsinh"], [2, 2, 1, "", "artanh"], [2, 2, 1, "", "atmospheric_correction"], [2, 2, 1, "", "between"], [2, 2, 1, "", "ceil"], [2, 2, 1, "", "climatological_normal"], [2, 2, 1, "", "clip"], [2, 2, 1, "", "cloud_detection"], [2, 2, 1, "", "constant"], [2, 2, 1, "", "cos"], [2, 2, 1, "", "cosh"], [2, 2, 1, "", "count"], [2, 2, 1, "", "create_raster_cube"], [2, 2, 1, "", "cummax"], [2, 2, 1, "", "cummin"], [2, 2, 1, "", "cumproduct"], [2, 2, 1, "", "cumsum"], [2, 2, 1, "", "date_shift"], [2, 2, 1, "", "dimension_labels"], [2, 2, 1, "", "divide"], [2, 2, 1, "", "drop_dimension"], [2, 2, 1, "", "e"], [2, 2, 1, "", "eq"], [2, 2, 1, "", "exp"], [2, 2, 1, "", "extrema"], [2, 2, 1, "", "filter_bands"], [2, 2, 1, "", "filter_bbox"], [2, 2, 1, "", "filter_labels"], [2, 2, 1, "", "filter_spatial"], [2, 2, 1, "", "filter_temporal"], [2, 2, 1, "", "first"], [2, 2, 1, "", "fit_class_random_forest"], [2, 2, 1, "", "fit_curve"], [2, 2, 1, "", "fit_regr_random_forest"], [2, 2, 1, "", "flatten_dimensions"], [2, 2, 1, "", "floor"], [2, 2, 1, "", "gt"], [2, 2, 1, "", "gte"], [2, 2, 1, "", "if_"], [2, 2, 1, "", "inspect"], [2, 2, 1, "", "int"], [2, 2, 1, "", "is_infinite"], [2, 2, 1, "", "is_nan"], [2, 2, 1, "", "is_nodata"], [2, 2, 1, "", "is_valid"], [2, 2, 1, "", "last"], [2, 2, 1, "", "linear_scale_range"], [2, 2, 1, "", "ln"], [2, 2, 1, "", "load_collection"], [2, 2, 1, "", "load_ml_model"], [2, 2, 1, "", "load_result"], [2, 2, 1, "", "load_uploaded_files"], [2, 2, 1, "", "log"], [2, 2, 1, "", "lt"], [2, 2, 1, "", "lte"], [2, 2, 1, "", "mask"], [2, 2, 1, "", "mask_polygon"], [2, 2, 1, "", "max"], [2, 2, 1, "", "mean"], [2, 2, 1, "", "median"], [2, 2, 1, "", "merge_cubes"], [2, 2, 1, "", "min"], [2, 2, 1, "", "mod"], [2, 2, 1, "", "multiply"], [2, 2, 1, "", "nan"], [2, 2, 1, "", "ndvi"], [2, 2, 1, "", "neq"], [2, 2, 1, "", "normalized_difference"], [2, 2, 1, "", "not_"], [2, 2, 1, "", "or_"], [2, 2, 1, "", "order"], [2, 2, 1, "", "pi"], [2, 2, 1, "", "power"], [2, 2, 1, "", "predict_curve"], [2, 2, 1, "", "predict_random_forest"], [0, 2, 1, "", "process"], [2, 2, 1, "", "product"], [2, 2, 1, "", "quantiles"], [2, 2, 1, "", "rearrange"], [2, 2, 1, "", "reduce_dimension"], [2, 2, 1, "", "reduce_spatial"], [2, 2, 1, "", "rename_dimension"], [2, 2, 1, "", "rename_labels"], [2, 2, 1, "", "resample_cube_spatial"], [2, 2, 1, "", "resample_cube_temporal"], [2, 2, 1, "", "resample_spatial"], [2, 2, 1, "", "round"], [2, 2, 1, "", "run_udf"], [2, 2, 1, "", "run_udf_externally"], [2, 2, 1, "", "sar_backscatter"], [2, 2, 1, "", "save_ml_model"], [2, 2, 1, "", "save_result"], [2, 2, 1, "", "sd"], [2, 2, 1, "", "sgn"], [2, 2, 1, "", "sin"], [2, 2, 1, "", "sinh"], [2, 2, 1, "", "sort"], [2, 2, 1, "", "sqrt"], [2, 2, 1, "", "subtract"], [2, 2, 1, "", "sum"], [2, 2, 1, "", "tan"], [2, 2, 1, "", "tanh"], [2, 2, 1, "", "text_begins"], [2, 2, 1, "", "text_concat"], [2, 2, 1, "", "text_contains"], [2, 2, 1, "", "text_ends"], [2, 2, 1, "", "trim_cube"], [2, 2, 1, "", "unflatten_dimension"], [2, 2, 1, "", "variance"], [2, 2, 1, "", "vector_buffer"], [2, 2, 1, "", "vector_to_random_points"], [2, 2, 1, "", "vector_to_regular_points"], [2, 2, 1, "", "xor"]], "openeo.processes.ProcessBuilder": [[2, 3, 1, "", "absolute"], [2, 3, 1, "", "add"], [2, 3, 1, "", "add_dimension"], [2, 3, 1, "", "aggregate_spatial"], [2, 3, 1, "", "aggregate_spatial_window"], [2, 3, 1, "", "aggregate_temporal"], [2, 3, 1, "", "aggregate_temporal_period"], [2, 3, 1, "", "all"], [2, 3, 1, "", "and_"], [2, 3, 1, "", "anomaly"], [2, 3, 1, "", "any"], [2, 3, 1, "", "apply"], [2, 3, 1, "", "apply_dimension"], [2, 3, 1, "", "apply_kernel"], [2, 3, 1, "", "apply_neighborhood"], [2, 3, 1, "", "arccos"], [2, 3, 1, "", "arcosh"], [2, 3, 1, "", "arcsin"], [2, 3, 1, "", "arctan"], [2, 3, 1, "", "arctan2"], [2, 3, 1, "", "ard_normalized_radar_backscatter"], [2, 3, 1, "", "ard_surface_reflectance"], [2, 3, 1, "", "array_append"], [2, 3, 1, "", "array_apply"], [2, 3, 1, "", "array_concat"], [2, 3, 1, "", "array_contains"], [2, 3, 1, "", "array_create"], [2, 3, 1, "", "array_create_labeled"], [2, 3, 1, "", "array_element"], [2, 3, 1, "", "array_filter"], [2, 3, 1, "", "array_find"], [2, 3, 1, "", "array_find_label"], [2, 3, 1, "", "array_interpolate_linear"], [2, 3, 1, "", "array_labels"], [2, 3, 1, "", "array_modify"], [2, 3, 1, "", "arsinh"], [2, 3, 1, "", "artanh"], [2, 3, 1, "", "atmospheric_correction"], [2, 3, 1, "", "between"], [2, 3, 1, "", "ceil"], [2, 3, 1, "", "climatological_normal"], [2, 3, 1, "", "clip"], [2, 3, 1, "", "cloud_detection"], [2, 3, 1, "", "constant"], [2, 3, 1, "", "cos"], [2, 3, 1, "", "cosh"], [2, 3, 1, "", "count"], [2, 3, 1, "", "create_raster_cube"], [2, 3, 1, "", "cummax"], [2, 3, 1, "", "cummin"], [2, 3, 1, "", "cumproduct"], [2, 3, 1, "", "cumsum"], [2, 3, 1, "", "date_shift"], [2, 3, 1, "", "dimension_labels"], [2, 3, 1, "", "divide"], [2, 3, 1, "", "drop_dimension"], [2, 3, 1, "", "e"], [2, 3, 1, "", "eq"], [2, 3, 1, "", "exp"], [2, 3, 1, "", "extrema"], [2, 3, 1, "", "filter_bands"], [2, 3, 1, "", "filter_bbox"], [2, 3, 1, "", "filter_labels"], [2, 3, 1, "", "filter_spatial"], [2, 3, 1, "", "filter_temporal"], [2, 3, 1, "", "first"], [2, 3, 1, "", "fit_class_random_forest"], [2, 3, 1, "", "fit_curve"], [2, 3, 1, "", "fit_regr_random_forest"], [2, 3, 1, "", "flatten_dimensions"], [2, 3, 1, "", "floor"], [2, 3, 1, "", "gt"], [2, 3, 1, "", "gte"], [2, 3, 1, "", "if_"], [2, 3, 1, "", "inspect"], [2, 3, 1, "", "int"], [2, 3, 1, "", "is_infinite"], [2, 3, 1, "", "is_nan"], [2, 3, 1, "", "is_nodata"], [2, 3, 1, "", "is_valid"], [2, 3, 1, "", "last"], [2, 3, 1, "", "linear_scale_range"], [2, 3, 1, "", "ln"], [2, 3, 1, "", "load_collection"], [2, 3, 1, "", "load_ml_model"], [2, 3, 1, "", "load_result"], [2, 3, 1, "", "load_uploaded_files"], [2, 3, 1, "", "log"], [2, 3, 1, "", "lt"], [2, 3, 1, "", "lte"], [2, 3, 1, "", "mask"], [2, 3, 1, "", "mask_polygon"], [2, 3, 1, "", "max"], [2, 3, 1, "", "mean"], [2, 3, 1, "", "median"], [2, 3, 1, "", "merge_cubes"], [2, 3, 1, "", "min"], [2, 3, 1, "", "mod"], [2, 3, 1, "", "multiply"], [2, 3, 1, "", "nan"], [2, 3, 1, "", "ndvi"], [2, 3, 1, "", "neq"], [2, 3, 1, "", "normalized_difference"], [2, 3, 1, "", "not_"], [2, 3, 1, "", "or_"], [2, 3, 1, "", "order"], [2, 3, 1, "", "pi"], [2, 3, 1, "", "power"], [2, 3, 1, "", "predict_curve"], [2, 3, 1, "", "predict_random_forest"], [2, 3, 1, "", "product"], [2, 3, 1, "", "quantiles"], [2, 3, 1, "", "rearrange"], [2, 3, 1, "", "reduce_dimension"], [2, 3, 1, "", "reduce_spatial"], [2, 3, 1, "", "rename_dimension"], [2, 3, 1, "", "rename_labels"], [2, 3, 1, "", "resample_cube_spatial"], [2, 3, 1, "", "resample_cube_temporal"], [2, 3, 1, "", "resample_spatial"], [2, 3, 1, "", "round"], [2, 3, 1, "", "run_udf"], [2, 3, 1, "", "run_udf_externally"], [2, 3, 1, "", "sar_backscatter"], [2, 3, 1, "", "save_ml_model"], [2, 3, 1, "", "save_result"], [2, 3, 1, "", "sd"], [2, 3, 1, "", "sgn"], [2, 3, 1, "", "sin"], [2, 3, 1, "", "sinh"], [2, 3, 1, "", "sort"], [2, 3, 1, "", "sqrt"], [2, 3, 1, "", "subtract"], [2, 3, 1, "", "sum"], [2, 3, 1, "", "tan"], [2, 3, 1, "", "tanh"], [2, 3, 1, "", "text_begins"], [2, 3, 1, "", "text_concat"], [2, 3, 1, "", "text_contains"], [2, 3, 1, "", "text_ends"], [2, 3, 1, "", "trim_cube"], [2, 3, 1, "", "unflatten_dimension"], [2, 3, 1, "", "variance"], [2, 3, 1, "", "vector_buffer"], [2, 3, 1, "", "vector_to_random_points"], [2, 3, 1, "", "vector_to_regular_points"], [2, 3, 1, "", "xor"]], "openeo.rest": [[0, 0, 0, "-", "_datacube"], [0, 0, 0, "-", "connection"], [0, 0, 0, "-", "conversions"], [0, 0, 0, "-", "datacube"], [0, 0, 0, "-", "graph_building"], [0, 0, 0, "-", "job"], [0, 0, 0, "-", "mlmodel"], [0, 0, 0, "-", "udp"], [0, 0, 0, "-", "userfile"], [0, 0, 0, "-", "vectorcube"]], "openeo.rest._datacube": [[0, 1, 1, "", "UDF"]], "openeo.rest._datacube.UDF": [[0, 3, 1, "", "from_file"], [0, 3, 1, "", "from_url"], [0, 3, 1, "", "get_run_udf_callback"]], "openeo.rest.connection": [[0, 1, 1, "", "Connection"]], "openeo.rest.connection.Connection": [[0, 3, 1, "", "as_curl"], [0, 3, 1, "", "assert_user_defined_process_support"], [0, 3, 1, "", "authenticate_basic"], [0, 3, 1, "", "authenticate_oidc"], [0, 3, 1, "", "authenticate_oidc_authorization_code"], [0, 3, 1, "", "authenticate_oidc_client_credentials"], [0, 3, 1, "", "authenticate_oidc_device"], [0, 3, 1, "", "authenticate_oidc_refresh_token"], [0, 3, 1, "", "authenticate_oidc_resource_owner_password_credentials"], [0, 3, 1, "", "capabilities"], [0, 3, 1, "", "collection_items"], [0, 3, 1, "", "create_job"], [0, 3, 1, "", "datacube_from_flat_graph"], [0, 3, 1, "", "datacube_from_json"], [0, 3, 1, "", "datacube_from_process"], [0, 3, 1, "", "describe_account"], [0, 3, 1, "", "describe_collection"], [0, 3, 1, "", "describe_process"], [0, 3, 1, "", "download"], [0, 3, 1, "", "execute"], [0, 3, 1, "", "get_file"], [0, 3, 1, "", "imagecollection"], [0, 3, 1, "", "job"], [0, 3, 1, "", "job_logs"], [0, 3, 1, "", "job_results"], [0, 3, 1, "", "list_collection_ids"], [0, 3, 1, "", "list_collections"], [0, 3, 1, "", "list_file_formats"], [0, 3, 1, "", "list_file_types"], [0, 3, 1, "", "list_files"], [0, 3, 1, "", "list_jobs"], [0, 3, 1, "", "list_processes"], [0, 3, 1, "", "list_service_types"], [0, 3, 1, "", "list_services"], [0, 3, 1, "", "list_udf_runtimes"], [0, 3, 1, "", "list_user_defined_processes"], [0, 3, 1, "", "load_collection"], [0, 3, 1, "", "load_disk_collection"], [0, 3, 1, "", "load_geojson"], [0, 3, 1, "", "load_ml_model"], [0, 3, 1, "", "load_result"], [0, 3, 1, "", "load_stac"], [0, 3, 1, "", "load_url"], [0, 3, 1, "", "remove_service"], [0, 3, 1, "", "request"], [0, 3, 1, "", "save_user_defined_process"], [0, 3, 1, "", "service"], [0, 3, 1, "", "upload_file"], [0, 3, 1, "", "user_defined_process"], [0, 3, 1, "", "user_jobs"], [0, 3, 1, "", "validate_process_graph"], [0, 3, 1, "", "vectorcube_from_paths"], [0, 3, 1, "", "version_discovery"], [0, 3, 1, "", "version_info"]], "openeo.rest.conversions": [[0, 5, 1, "", "InvalidTimeSeriesException"], [0, 2, 1, "", "datacube_from_file"], [0, 2, 1, "", "datacube_plot"], [0, 2, 1, "", "datacube_to_file"], [0, 2, 1, "", "timeseries_json_to_pandas"]], "openeo.rest.datacube": [[0, 1, 1, "", "DataCube"], [0, 6, 1, "", "THIS"]], "openeo.rest.datacube.DataCube": [[0, 3, 1, "", "__init__"], [0, 3, 1, "", "add"], [0, 3, 1, "", "add_dimension"], [0, 3, 1, "", "aggregate_spatial"], [0, 3, 1, "", "aggregate_spatial_window"], [0, 3, 1, "", "aggregate_temporal"], [0, 3, 1, "", "aggregate_temporal_period"], [0, 3, 1, "", "apply"], [0, 3, 1, "", "apply_dimension"], [0, 3, 1, "", "apply_kernel"], [0, 3, 1, "", "apply_neighborhood"], [0, 3, 1, "", "apply_polygon"], [0, 3, 1, "", "ard_normalized_radar_backscatter"], [0, 3, 1, "", "ard_surface_reflectance"], [0, 3, 1, "", "atmospheric_correction"], [0, 3, 1, "", "band"], [0, 3, 1, "", "band_filter"], [0, 3, 1, "", "chunk_polygon"], [0, 3, 1, "", "count_time"], [0, 3, 1, "", "create_collection"], [0, 3, 1, "", "create_job"], [0, 3, 1, "", "dimension_labels"], [0, 3, 1, "", "divide"], [0, 3, 1, "", "download"], [0, 3, 1, "", "drop_dimension"], [0, 3, 1, "", "execute"], [0, 3, 1, "", "execute_batch"], [0, 3, 1, "", "execute_local_udf"], [0, 3, 1, "", "filter_bands"], [0, 3, 1, "", "filter_bbox"], [0, 3, 1, "", "filter_spatial"], [0, 3, 1, "", "filter_temporal"], [0, 3, 1, "", "fit_curve"], [0, 3, 1, "", "flat_graph"], [0, 3, 1, "", "flatten_dimensions"], [0, 3, 1, "", "graph_add_node"], [0, 3, 1, "", "linear_scale_range"], [0, 3, 1, "", "ln"], [0, 3, 1, "", "load_collection"], [0, 3, 1, "", "load_disk_collection"], [0, 3, 1, "", "log10"], [0, 3, 1, "", "log2"], [0, 3, 1, "", "logarithm"], [0, 3, 1, "", "logical_and"], [0, 3, 1, "", "logical_or"], [0, 3, 1, "", "mask"], [0, 3, 1, "", "mask_polygon"], [0, 3, 1, "", "max_time"], [0, 3, 1, "", "mean_time"], [0, 3, 1, "", "median_time"], [0, 3, 1, "", "merge"], [0, 3, 1, "", "merge_cubes"], [0, 3, 1, "", "min_time"], [0, 3, 1, "", "multiply"], [0, 3, 1, "", "ndvi"], [0, 3, 1, "", "normalized_difference"], [0, 3, 1, "", "polygonal_histogram_timeseries"], [0, 3, 1, "", "polygonal_mean_timeseries"], [0, 3, 1, "", "polygonal_median_timeseries"], [0, 3, 1, "", "polygonal_standarddeviation_timeseries"], [0, 3, 1, "", "power"], [0, 3, 1, "", "predict_curve"], [0, 3, 1, "", "predict_random_forest"], [0, 3, 1, "", "preview"], [0, 3, 1, "", "print_json"], [0, 3, 1, "", "process"], [0, 3, 1, "", "process_with_node"], [0, 3, 1, "", "raster_to_vector"], [0, 3, 1, "", "reduce_bands"], [0, 3, 1, "", "reduce_bands_udf"], [0, 3, 1, "", "reduce_dimension"], [0, 3, 1, "", "reduce_spatial"], [0, 3, 1, "", "reduce_temporal"], [0, 3, 1, "", "reduce_temporal_simple"], [0, 3, 1, "", "reduce_temporal_udf"], [0, 3, 1, "", "reduce_tiles_over_time"], [0, 3, 1, "", "rename_dimension"], [0, 3, 1, "", "rename_labels"], [0, 3, 1, "", "resample_cube_spatial"], [0, 3, 1, "", "resample_cube_temporal"], [0, 3, 1, "", "resample_spatial"], [0, 3, 1, "", "resolution_merge"], [0, 3, 1, "", "result_node"], [0, 3, 1, "", "sar_backscatter"], [0, 3, 1, "", "save_result"], [0, 3, 1, "", "save_user_defined_process"], [0, 3, 1, "", "send_job"], [0, 3, 1, "", "subtract"], [0, 3, 1, "", "to_json"], [0, 3, 1, "", "unflatten_dimension"], [0, 3, 1, "", "validate"]], "openeo.rest.graph_building": [[0, 1, 1, "", "CollectionProperty"], [0, 2, 1, "", "collection_property"]], "openeo.rest.job": [[0, 1, 1, "", "BatchJob"], [0, 1, 1, "", "JobResults"], [0, 1, 1, "", "RESTJob"], [0, 1, 1, "", "ResultAsset"]], "openeo.rest.job.BatchJob": [[0, 3, 1, "", "delete"], [0, 3, 1, "", "delete_job"], [0, 3, 1, "", "describe"], [0, 3, 1, "", "describe_job"], [0, 3, 1, "", "download_result"], [0, 3, 1, "", "download_results"], [0, 3, 1, "", "estimate"], [0, 3, 1, "", "estimate_job"], [0, 3, 1, "", "get_result"], [0, 3, 1, "", "get_results"], [0, 3, 1, "", "get_results_metadata_url"], [0, 7, 1, "", "job_id"], [0, 3, 1, "", "list_results"], [0, 3, 1, "", "logs"], [0, 3, 1, "", "run_synchronous"], [0, 3, 1, "", "start"], [0, 3, 1, "", "start_and_wait"], [0, 3, 1, "", "start_job"], [0, 3, 1, "", "status"], [0, 3, 1, "", "stop"], [0, 3, 1, "", "stop_job"]], "openeo.rest.job.JobResults": [[0, 3, 1, "", "download_file"], [0, 3, 1, "", "download_files"], [0, 3, 1, "", "get_asset"], [0, 3, 1, "", "get_assets"], [0, 3, 1, "", "get_metadata"]], "openeo.rest.job.ResultAsset": [[0, 3, 1, "", "download"], [0, 7, 1, "", "href"], [0, 3, 1, "", "load_bytes"], [0, 3, 1, "", "load_json"], [0, 7, 1, "", "metadata"], [0, 7, 1, "", "name"]], "openeo.rest.mlmodel": [[0, 1, 1, "", "MlModel"]], "openeo.rest.mlmodel.MlModel": [[0, 3, 1, "", "create_job"], [0, 3, 1, "", "execute_batch"], [0, 3, 1, "", "flat_graph"], [0, 3, 1, "", "load_ml_model"], [0, 3, 1, "", "print_json"], [0, 3, 1, "", "result_node"], [0, 3, 1, "", "save_ml_model"], [0, 3, 1, "", "to_json"]], "openeo.rest.udp": [[0, 1, 1, "", "RESTUserDefinedProcess"], [0, 2, 1, "", "build_process_dict"]], "openeo.rest.udp.RESTUserDefinedProcess": [[0, 3, 1, "", "delete"], [0, 3, 1, "", "describe"], [0, 3, 1, "", "store"], [0, 3, 1, "", "update"]], "openeo.rest.userfile": [[0, 1, 1, "", "UserFile"]], "openeo.rest.userfile.UserFile": [[0, 3, 1, "", "delete"], [0, 3, 1, "", "download"], [0, 3, 1, "", "from_metadata"], [0, 3, 1, "", "to_dict"], [0, 3, 1, "", "upload"]], "openeo.rest.vectorcube": [[0, 1, 1, "", "VectorCube"]], "openeo.rest.vectorcube.VectorCube": [[0, 3, 1, "", "apply_dimension"], [0, 3, 1, "", "create_job"], [0, 3, 1, "", "download"], [0, 3, 1, "", "execute"], [0, 3, 1, "", "execute_batch"], [0, 3, 1, "", "filter_bands"], [0, 3, 1, "", "filter_bbox"], [0, 3, 1, "", "filter_labels"], [0, 3, 1, "", "filter_vector"], [0, 3, 1, "", "fit_class_random_forest"], [0, 3, 1, "", "fit_regr_random_forest"], [0, 3, 1, "", "flat_graph"], [0, 3, 1, "", "load_geojson"], [0, 3, 1, "", "load_url"], [0, 3, 1, "", "print_json"], [0, 3, 1, "", "process"], [0, 3, 1, "", "result_node"], [0, 3, 1, "", "run_udf"], [0, 3, 1, "", "save_result"], [0, 3, 1, "", "send_job"], [0, 3, 1, "", "to_json"]], "openeo.udf": [[0, 0, 0, "-", "debug"], [0, 0, 0, "-", "run_code"], [0, 0, 0, "-", "structured_data"], [0, 0, 0, "-", "udf_data"], [25, 0, 0, "-", "udf_signatures"], [0, 0, 0, "-", "xarraydatacube"]], "openeo.udf.debug": [[0, 2, 1, "", "inspect"]], "openeo.udf.run_code": [[0, 2, 1, "", "execute_local_udf"]], "openeo.udf.structured_data": [[0, 1, 1, "", "StructuredData"]], "openeo.udf.udf_data": [[0, 1, 1, "", "UdfData"]], "openeo.udf.udf_data.UdfData": [[0, 4, 1, "", "datacube_list"], [0, 4, 1, "", "feature_collection_list"], [0, 3, 1, "", "from_dict"], [0, 3, 1, "", "get_datacube_list"], [0, 3, 1, "", "get_feature_collection_list"], [0, 3, 1, "", "get_structured_data_list"], [0, 3, 1, "", "set_datacube_list"], [0, 3, 1, "", "set_structured_data_list"], [0, 4, 1, "", "structured_data_list"], [0, 3, 1, "", "to_dict"], [0, 4, 1, "", "user_context"]], "openeo.udf.udf_signatures": [[25, 2, 1, "", "apply_datacube"], [25, 2, 1, "", "apply_metadata"], [25, 2, 1, "", "apply_timeseries"], [25, 2, 1, "", "apply_udf_data"]], "openeo.udf.xarraydatacube": [[0, 1, 1, "", "XarrayDataCube"]], "openeo.udf.xarraydatacube.XarrayDataCube": [[0, 4, 1, "", "array"], [0, 3, 1, "", "from_dict"], [0, 3, 1, "", "from_file"], [0, 3, 1, "", "get_array"], [0, 3, 1, "", "plot"], [0, 3, 1, "", "save_to_file"], [0, 3, 1, "", "to_dict"]], "openeo.util": [[0, 1, 1, "", "BBoxDict"], [0, 2, 1, "", "load_json_resource"], [0, 2, 1, "", "normalize_crs"], [0, 2, 1, "", "to_bbox_dict"]], "openeo.util.BBoxDict": [[0, 3, 1, "", "from_dict"], [0, 3, 1, "", "from_sequence"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:function", "3": "py:method", "4": "py:property", "5": "py:exception", "6": "py:data", "7": "py:attribute"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "function", "Python function"], "3": ["py", "method", "Python method"], "4": ["py", "property", "Python property"], "5": ["py", "exception", "Python exception"], "6": ["py", "data", "Python data"], "7": ["py", "attribute", "Python attribute"]}, "titleterms": {"api": [0, 2, 14, 24, 25], "gener": [0, 3, 6, 9, 19, 24], "high": 0, "level": 0, "interfac": 0, "openeo": [0, 2, 3, 4, 10, 17, 20, 23, 25], "rest": 0, "datacub": [0, 16, 18, 25], "vectorcub": 0, "mlmodel": 0, "metadata": [0, 25], "process": [0, 2, 12, 15, 16, 18, 23, 24, 25, 26], "log": [0, 5, 25], "connect": [0, 3, 4], "job": [0, 4, 5, 11], "convers": 0, "udp": [0, 16, 26], "userfil": 0, "udf": [0, 7, 25], "util": 0, "graph": [0, 15], "build": [0, 19, 26], "public": [0, 16], "intern": 0, "section": 2, "function": [2, 25, 26], "processbuild": 2, "helper": [2, 3], "class": 2, "authent": [3, 4], "account": 3, "manag": [3, 6, 11, 25], "basic": [3, 19, 21, 24], "http": 3, "auth": 3, "openid": 3, "base": [3, 16, 22], "option": [3, 8, 21], "oidc": 3, "devic": 3, "code": [3, 6, 19, 26], "flow": 3, "refresh": 3, "token": 3, "client": [3, 12, 20], "credenti": 3, "us": [3, 4, 16, 24, 26], "environ": 3, "variabl": 3, "dynam": 3, "method": [3, 24], "select": 3, "config": 3, "file": [3, 8, 19, 26], "tool": 3, "default": 3, "back": [3, 4, 9], "end": [3, 4, 9, 17], "url": [3, 16], "auto": 3, "long": 3, "run": [3, 5, 19], "applic": [3, 25], "non": 3, "interact": 3, "context": 3, "guidelin": 3, "tip": [3, 6, 15], "best": [3, 6], "practic": [3, 6], "troubleshoot": [3, 21], "clear": 3, "get": 4, "start": [4, 5, 17], "an": [4, 17, 25], "collect": [4, 12, 17], "discoveri": [4, 17], "exampl": [4, 18, 20, 25, 26], "case": 4, "evi": [4, 26], "map": [4, 14, 23], "timeseri": [4, 25, 26], "load": [4, 5, 16, 17], "initi": [4, 17], "data": [4, 9, 17, 24, 25, 26], "cube": [4, 17, 24, 25, 26], "band": [4, 14], "math": 4, "download": [4, 5, 25], "synchron": 4, "batch": [4, 5], "asynchron": 4, "execut": [4, 15, 25], "appli": [4, 25], "cloud": 4, "mask": 4, "aggreg": 4, "comput": 4, "multipl": 4, "statist": 4, "creat": [5, 19], "object": 5, "reconnect": 5, "jupyt": [5, 6], "integr": 5, "list": 5, "your": 5, "wait": 5, "finish": 5, "one": 5, "go": 5, "automat": [5, 14], "print": 5, "result": [5, 24], "all": 5, "asset": 5, "singl": [5, 17], "fine": 5, "grain": 5, "directli": [5, 15], "style": 6, "background": [6, 12], "inspir": 6, "recommend": 6, "line": 6, "length": 6, "lab": 6, "trick": [6, 15], "changelog": 7, "unreleas": 7, "ad": [7, 24], "chang": [7, 25], "remov": 7, "fix": 7, "0": [7, 25], "25": 7, "2023": 7, "11": 7, "02": 7, "24": 7, "10": 7, "27": 7, "23": 7, "22": 7, "08": 7, "09": 7, "21": 7, "1": 7, "07": 7, "19": 7, "20": 7, "06": 7, "30": 7, "16": 7, "18": 7, "05": 7, "31": 7, "17": 7, "04": 7, "srr5": 7, "releas": [7, 19], "15": 7, "03": 7, "14": 7, "01": 7, "13": [7, 25], "2022": 7, "ux": 7, "12": 7, "lps22": 7, "srr3": 7, "9": 7, "2": 7, "2021": 7, "8": 7, "deprec": 7, "7": 7, "6": 7, "29": 7, "26": 7, "5": 7, "4": 7, "2020": 7, "configur": 8, "format": 8, "locat": 8, "analysi": 9, "readi": 9, "atmospher": 9, "correct": 9, "refer": 9, "implement": 9, "eodc": 9, "geotrelli": 9, "sar": 9, "backscatt": 9, "cookbook": 10, "content": [10, 20], "multi": 11, "backend": 11, "side": [12, 25], "local": [12, 25], "instal": [12, 19, 21], "usag": [12, 19, 20, 25], "stac": 12, "item": 12, "dataset": 13, "sampl": 13, "perform": 13, "scalabl": 13, "scale": 13, "spectral": 14, "indic": [14, 20], "manual": 14, "miscellan": 15, "export": 15, "from": [15, 17, 18, 24, 25, 26], "raw": 15, "json": [15, 18], "share": 16, "user": [16, 25, 26], "defin": [16, 24, 25, 26], "publicli": 16, "publish": 16, "through": [16, 26], "namespac": 16, "find": 17, "explor": 17, "filter": 17, "spatial": 17, "extent": 17, "tempor": 17, "left": 17, "close": 17, "interv": 17, "includ": 17, "exclud": 17, "year": 17, "month": 17, "shorthand": 17, "notat": 17, "round": 17, "down": 17, "period": 17, "date": 17, "string": [17, 24], "properti": 17, "handl": 17, "larg": 17, "vector": 17, "set": [17, 19], "construct": 18, "The": 18, "load_collect": 18, "some": 18, "parameter": [18, 26], "re": 18, "develop": [19, 21], "mainten": 19, "unit": 19, "test": 19, "document": 19, "quick": 19, "easi": 19, "like": 19, "pro": 19, "contribut": 19, "pull": 19, "request": 19, "pre": [19, 24], "commit": 19, "qualiti": 19, "check": 19, "up": 19, "prerequisit": 19, "import": 19, "procedur": 19, "verif": 19, "window": 19, "altern": 19, "updat": 19, "python": 20, "tabl": 20, "pip": 21, "conda": 21, "verifi": 21, "depend": [21, 25], "enabl": 21, "addit": 21, "featur": 21, "sourc": 21, "machin": 22, "learn": 22, "random": 22, "forest": 22, "classif": 22, "regress": 22, "train": 22, "infer": 22, "work": 24, "A": [24, 25], "bit": 24, "terminologi": 24, "common": 24, "conveni": 24, "advanc": [24, 26], "argument": 24, "tweak": 24, "pass": 24, "other": 24, "call": 24, "child": 24, "callback": [24, 25], "callabl": 24, "caveat": 24, "pgnode": 24, "explain": 25, "constraint": 25, "reduc": 25, "name": 25, "signatur": 25, "modul": 25, "udf_signatur": 25, "first": 25, "rescal": 25, "pixel": 25, "valu": 25, "script": 25, "workflow": 25, "": 25, "transform": 25, "illustr": 25, "chunk": 25, "apply_dimens": 25, "reduce_dimens": 25, "apply_neighborhood": 25, "smooth": 25, "profil": 25, "server": 25, "view": 25, "inform": 25, "version": 25, "reus": 26, "paramet": 26, "declar": 26, "more": 26, "schema": 26, "store": 26, "predefin": 26, "dictionari": 26, "evalu": 26}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"API (General)": [[0, "api-general"]], "High level Interface": [[0, "high-level-interface"]], "openeo": [[0, "openeo"]], "openeo.rest.datacube": [[0, "module-openeo.rest.datacube"]], "openeo.rest.vectorcube": [[0, "module-openeo.rest.vectorcube"]], "openeo.rest.mlmodel": [[0, "module-openeo.rest.mlmodel"]], "openeo.metadata": [[0, "module-openeo.metadata"]], "openeo.api.process": [[0, "module-openeo.api.process"]], "openeo.api.logs": [[0, "module-openeo.api.logs"]], "openeo.rest.connection": [[0, "module-openeo.rest.connection"]], "openeo.rest.job": [[0, "module-openeo.rest.job"]], "openeo.rest.conversions": [[0, "module-openeo.rest.conversions"]], "openeo.rest.udp": [[0, "module-openeo.rest.udp"]], "openeo.rest.userfile": [[0, "module-openeo.rest.userfile"]], "openeo.udf": [[0, "module-openeo.udf.udf_data"]], "openeo.util": [[0, "module-openeo.util"]], "openeo.processes": [[0, "module-openeo.processes"]], "Graph building": [[0, "graph-building"]], "Public openEO process graph building utilities": [[0, "public-openeo-process-graph-building-utilities"]], "Internal openEO process graph building utilities": [[0, "internal-openeo-process-graph-building-utilities"]], "API: openeo.processes": [[2, "api-openeo-processes"]], "Sections:": [[2, "sections"]], "Functions in openeo.processes": [[2, "functions-in-openeo-processes"]], "ProcessBuilder helper class": [[2, "processbuilder-helper-class"]], "Authentication and Account Management": [[3, "authentication-and-account-management"]], "Basic HTTP Auth": [[3, "basic-http-auth"]], "OpenID Connect Based Authentication": [[3, "openid-connect-based-authentication"]], "General options": [[3, "general-options"]], "OIDC Authentication: Device Code Flow": [[3, "oidc-authentication-device-code-flow"]], "OIDC Authentication: Refresh Token Flow": [[3, "oidc-authentication-refresh-token-flow"]], "OIDC Authentication: Client Credentials Flow": [[3, "oidc-authentication-client-credentials-flow"]], "OIDC Client Credentials Using Environment Variables": [[3, "oidc-client-credentials-using-environment-variables"]], "OIDC Authentication: Dynamic Method Selection": [[3, "oidc-authentication-dynamic-method-selection"]], "Auth config files and openeo-auth helper tool": [[3, "auth-config-files-and-openeo-auth-helper-tool"]], "Basic HTTP Auth config": [[3, "basic-http-auth-config"]], "OpenID Connect configs": [[3, "openid-connect-configs"]], "OpenID Connect refresh tokens": [[3, "openid-connect-refresh-tokens"]], "Default openEO back-end URL and auto-authentication": [[3, "default-openeo-back-end-url-and-auto-authentication"]], "Authentication for long-running applications and non-interactive contexts": [[3, "authentication-for-long-running-applications-and-non-interactive-contexts"]], "Guidelines and tips": [[3, "guidelines-and-tips"]], "Best Practices and Troubleshooting Tips": [[3, "best-practices-and-troubleshooting-tips"]], "Clear the refresh token file": [[3, "clear-the-refresh-token-file"]], "Getting Started": [[4, "getting-started"]], "Connect to an openEO back-end": [[4, "connect-to-an-openeo-back-end"]], "Collection discovery": [[4, "collection-discovery"]], "Authentication": [[4, "authentication"]], "Example use case: EVI map and timeseries": [[4, "example-use-case-evi-map-and-timeseries"]], "Loading an initial data cube": [[4, "loading-an-initial-data-cube"]], "Band math": [[4, "band-math"]], "Download (synchronously)": [[4, "download-synchronously"]], "Batch Jobs (asynchronous execution)": [[4, "batch-jobs-asynchronous-execution"]], "Applying a cloud mask": [[4, "applying-a-cloud-mask"]], "Aggregated EVI timeseries": [[4, "aggregated-evi-timeseries"]], "Computing multiple statistics": [[4, "computing-multiple-statistics"]], "Batch Jobs": [[5, "batch-jobs"]], "Create a batch job": [[5, "create-a-batch-job"]], "Batch job object": [[5, "batch-job-object"]], "Reconnecting to a batch job": [[5, "reconnecting-to-a-batch-job"]], "Jupyter integration": [[5, "jupyter-integration"]], "List your batch jobs": [[5, "list-your-batch-jobs"]], "Run a batch job": [[5, "run-a-batch-job"]], "Wait for a batch job to finish": [[5, "wait-for-a-batch-job-to-finish"]], "Create, start and wait in one go": [[5, "create-start-and-wait-in-one-go"]], "Batch job logs": [[5, "batch-job-logs"]], "Automatic batch job log printing": [[5, "automatic-batch-job-log-printing"]], "Download batch job results": [[5, "download-batch-job-results"]], "Download all assets": [[5, "download-all-assets"]], "Download single asset": [[5, "download-single-asset"]], "Fine-grained asset downloads": [[5, "fine-grained-asset-downloads"]], "Directly load batch job results": [[5, "directly-load-batch-job-results"]], "Best practices, coding style and general tips": [[6, "best-practices-coding-style-and-general-tips"]], "Background and inspiration": [[6, "background-and-inspiration"]], "General code style recommendations": [[6, "general-code-style-recommendations"]], "Line (length) management": [[6, "line-length-management"]], "Jupyter(lab) tips and tricks": [[6, "jupyter-lab-tips-and-tricks"]], "Changelog": [[7, "changelog"]], "[Unreleased]": [[7, "unreleased"]], "Added": [[7, "added"], [7, "id5"], [7, "id8"], [7, "id13"], [7, "id19"], [7, "id23"], [7, "id26"], [7, "id29"], [7, "id31"], [7, "id33"], [7, "id38"], [7, "id43"], [7, "id46"], [7, "id53"], [7, "id57"], [7, "id60"], [7, "id62"], [7, "id67"], [7, "id69"], [7, "id73"], [7, "id78"], [7, "id82"], [7, "id85"], [7, "id91"], [7, "id94"], [7, "id98"], [7, "id102"], [7, "id105"], [7, "id108"], [7, "id113"], [7, "id118"], [7, "id121"]], "Changed": [[7, "changed"], [7, "id2"], [7, "id6"], [7, "id9"], [7, "id14"], [7, "id20"], [7, "id24"], [7, "id34"], [7, "id39"], [7, "id44"], [7, "id47"], [7, "id49"], [7, "id54"], [7, "id58"], [7, "id63"], [7, "id70"], [7, "id74"], [7, "id79"], [7, "id83"], [7, "id86"], [7, "id89"], [7, "id95"], [7, "id99"], [7, "id106"], [7, "id109"], [7, "id114"]], "Removed": [[7, "removed"], [7, "id10"], [7, "id35"], [7, "id50"], [7, "id55"], [7, "id61"], [7, "id64"], [7, "id75"], [7, "id80"], [7, "id92"], [7, "id100"], [7, "id110"], [7, "id116"]], "Fixed": [[7, "fixed"], [7, "id3"], [7, "id11"], [7, "id15"], [7, "id17"], [7, "id21"], [7, "id27"], [7, "id30"], [7, "id32"], [7, "id36"], [7, "id41"], [7, "id45"], [7, "id51"], [7, "id59"], [7, "id65"], [7, "id71"], [7, "id87"], [7, "id96"], [7, "id103"], [7, "id111"], [7, "id119"], [7, "id122"]], "[0.25.0] - 2023-11-02": [[7, "id1"]], "[0.24.0] - 2023-10-27": [[7, "id4"]], "[0.23.0] - 2023-10-02": [[7, "id7"]], "[0.22.0] - 2023-08-09": [[7, "id12"]], "[0.21.1] - 2023-07-19": [[7, "id16"]], "[0.21.0] - 2023-07-19": [[7, "id18"]], "[0.20.0] - 2023-06-30": [[7, "id22"]], "[0.19.0] - 2023-06-16": [[7, "id25"]], "[0.18.0] - 2023-05-31": [[7, "id28"]], "[0.17.0] and [0.17.1] - 2023-05-16": [[7, "and-0-17-1-2023-05-16"]], "[0.16.0] - 2023-04-17 - \u201cSRR5\u201d release": [[7, "srr5-release"]], "[0.15.0] - 2023-03-03": [[7, "id37"]], "[0.14.1] - 2023-02-06": [[7, "id40"]], "[0.14.0] - 2023-02-01": [[7, "id42"]], "[0.13.0] - 2022-10-10 - \u201cUDF UX\u201d release": [[7, "udf-ux-release"]], "[0.12.1] - 2022-09-15": [[7, "id48"]], "[0.12.0] - 2022-09-09": [[7, "id52"]], "[0.11.0] - 2022-07-02": [[7, "id56"]], "[0.10.1] - 2022-05-18 - \u201cLPS22\u201d release": [[7, "lps22-release"]], "[0.10.0] - 2022-04-08 - \u201cSRR3\u201d release": [[7, "srr3-release"]], "[0.9.2] - 2022-01-14": [[7, "id66"]], "[0.9.1] - 2021-11-16": [[7, "id68"]], "[0.9.0] - 2021-10-11": [[7, "id72"]], "[0.8.2] - 2021-08-24": [[7, "id76"]], "[0.8.1] - 2021-08-24": [[7, "id77"]], "[0.8.0] - 2021-06-25": [[7, "id81"]], "Deprecated": [[7, "deprecated"], [7, "id115"]], "[0.7.0] - 2021-04-21": [[7, "id84"]], "[0.6.1] - 2021-03-29": [[7, "id88"]], "[0.6.0] - 2021-03-26": [[7, "id90"]], "[0.5.0] - 2021-03-17": [[7, "id93"]], "[0.4.10] - 2021-02-26": [[7, "id97"]], "[0.4.9] - 2021-01-29": [[7, "id101"]], "[0.4.8] - 2020-11-17": [[7, "id104"]], "[0.4.7] - 2020-10-22": [[7, "id107"]], "[0.4.6] - 2020-10-15": [[7, "id112"]], "[0.4.5] - 2020-10-01": [[7, "id117"]], "[0.4.4] - 2020-08-20": [[7, "id120"]], "Configuration": [[8, "configuration"]], "Configuration files": [[8, "configuration-files"]], "Format": [[8, "format"]], "Location": [[8, "location"]], "Configuration options": [[8, "configuration-options"]], "Analysis Ready Data generation": [[9, "analysis-ready-data-generation"]], "Atmospheric correction": [[9, "atmospheric-correction"]], "Reference implementations": [[9, "reference-implementations"], [9, "id4"]], "EODC back-end": [[9, "eodc-back-end"], [9, "id5"]], "Geotrellis back-end": [[9, "geotrellis-back-end"], [9, "id6"]], "SAR backscatter": [[9, "sar-backscatter"]], "openEO CookBook": [[10, "openeo-cookbook"]], "Contents:": [[10, null]], "Multi Backend Job Manager": [[11, "multi-backend-job-manager"]], "Client-side (local) processing": [[12, "client-side-local-processing"]], "Background": [[12, "background"]], "Installation": [[12, "installation"], [21, "installation"]], "Usage": [[12, "usage"], [25, "usage"]], "STAC Collections and Items": [[12, "stac-collections-and-items"]], "Local Collections": [[12, "local-collections"]], "Local Processing": [[12, "local-processing"]], "Dataset sampling": [[13, "dataset-sampling"]], "Performance & scalability": [[13, "performance-scalability"]], "Sampling at scale": [[13, "sampling-at-scale"]], "Spectral Indices": [[14, "spectral-indices"]], "Band mapping": [[14, "band-mapping"]], "Automatic band mapping": [[14, "automatic-band-mapping"]], "Manual band mapping": [[14, "manual-band-mapping"]], "API": [[14, "module-openeo.extra.spectral_indices"]], "Miscellaneous tips and tricks": [[15, "miscellaneous-tips-and-tricks"]], "Export a process graph": [[15, "export-a-process-graph"]], "Execute a process graph directly from raw JSON": [[15, "execute-a-process-graph-directly-from-raw-json"]], "Sharing of user-defined processes": [[16, "sharing-of-user-defined-processes"]], "Publicly publishing a user-defined process.": [[16, "publicly-publishing-a-user-defined-process"]], "Using a public UDP through URL based \u201cnamespace\u201d": [[16, "using-a-public-udp-through-url-based-namespace"]], "Loading a published user-defined process as DataCube": [[16, "loading-a-published-user-defined-process-as-datacube"]], "Finding and loading data": [[17, "finding-and-loading-data"]], "Data discovery": [[17, "data-discovery"]], "Initial exploration of an openEO collection": [[17, "initial-exploration-of-an-openeo-collection"]], "Loading a data cube from a collection": [[17, "loading-a-data-cube-from-a-collection"]], "Filter on spatial extent": [[17, "filter-on-spatial-extent"]], "Filter on temporal extent": [[17, "filter-on-temporal-extent"]], "Left-closed intervals: start included, end excluded": [[17, "left-closed-intervals-start-included-end-excluded"]], "Year/month shorthand notation": [[17, "year-month-shorthand-notation"]], "Rounding down periods to dates": [[17, "rounding-down-periods-to-dates"]], "Single string temporal extents": [[17, "single-string-temporal-extents"]], "Filter on collection properties": [[17, "filter-on-collection-properties"]], "Handling large vector data sets": [[17, "handling-large-vector-data-sets"]], "DataCube construction": [[18, "datacube-construction"]], "The load_collection process": [[18, "the-load-collection-process"]], "Construct DataCube from process": [[18, "construct-datacube-from-process"]], "Construct DataCube from JSON": [[18, "construct-datacube-from-json"]], "Some examples": [[18, "some-examples"]], "Parameterization": [[18, "parameterization"]], "Re-parameterization": [[18, "re-parameterization"]], "Development and maintenance": [[19, "development-and-maintenance"]], "Running the unit tests": [[19, "running-the-unit-tests"]], "Building the documentation": [[19, "building-the-documentation"]], "Quick and easy": [[19, "quick-and-easy"]], "Like a Pro": [[19, "like-a-pro"]], "Contributing code": [[19, "contributing-code"]], "Pull requests": [[19, "pull-requests"]], "Pre-commit for basic code quality checks": [[19, "pre-commit-for-basic-code-quality-checks"]], "Pre-commit set up": [[19, "pre-commit-set-up"]], "Pre-commit usage": [[19, "pre-commit-usage"]], "Creating a release": [[19, "creating-a-release"]], "Prerequisites": [[19, "prerequisites"]], "Important files": [[19, "important-files"]], "Procedure": [[19, "procedure"]], "Verification": [[19, "verification"]], "Development Installation on Windows": [[19, "development-installation-on-windows"]], "Alternative development installation": [[19, "alternative-development-installation"]], "Update of generated files": [[19, "update-of-generated-files"]], "openEO Python Client": [[20, "openeo-python-client"]], "Usage example": [[20, "usage-example"]], "Table of contents": [[20, "table-of-contents"]], "Indices and tables": [[20, "indices-and-tables"]], "Basic install": [[21, "basic-install"]], "Installation with pip": [[21, "installation-with-pip"]], "Installation with Conda": [[21, "installation-with-conda"]], "Verifying and troubleshooting": [[21, "verifying-and-troubleshooting"]], "Optional dependencies": [[21, "optional-dependencies"]], "Enabling additional features": [[21, "enabling-additional-features"]], "Source or development install": [[21, "source-or-development-install"]], "Machine Learning": [[22, "machine-learning"]], "Random Forest based Classification and Regression": [[22, "random-forest-based-classification-and-regression"]], "Training": [[22, "training"]], "Inference": [[22, "inference"]], "openEO Process Mapping": [[23, "openeo-process-mapping"]], "Working with processes": [[24, "working-with-processes"]], "A bit of terminology": [[24, "a-bit-of-terminology"]], "Using common pre-defined processes": [[24, "using-common-pre-defined-processes"]], "Convenience methods": [[24, "convenience-methods"]], "Advanced argument tweaking": [[24, "advanced-argument-tweaking"]], "Generic API for adding processes": [[24, "generic-api-for-adding-processes"]], "Basics": [[24, "basics"]], "Passing data cube arguments": [[24, "passing-data-cube-arguments"]], "Passing results from other process calls as arguments": [[24, "passing-results-from-other-process-calls-as-arguments"]], "Processes with child \u201ccallbacks\u201d": [[24, "processes-with-child-callbacks"]], "Callback as string": [[24, "callback-as-string"]], "Callback as a callable": [[24, "callback-as-a-callable"]], "Caveats": [[24, "caveats"]], "Callback as PGNode": [[24, "callback-as-pgnode"]], "User-Defined Functions (UDF) explained": [[25, "user-defined-functions-udf-explained"]], "Applicability and Constraints": [[25, "applicability-and-constraints"]], "UDFs as apply/reduce \u201ccallbacks\u201d": [[25, "udfs-as-apply-reduce-callbacks"]], "UDF function names and signatures": [[25, "udf-function-names-and-signatures"]], "Module openeo.udf.udf_signatures": [[25, "module-openeo.udf.udf_signatures"]], "Examples": [[25, "examples"]], "A first example: apply with an UDF to rescale pixel values": [[25, "a-first-example-apply-with-an-udf-to-rescale-pixel-values"]], "UDF script": [[25, "udf-script"]], "Workflow script": [[25, "workflow-script"]], "UDF\u2019s that transform cube metadata": [[25, "udf-s-that-transform-cube-metadata"]], "Illustration of data chunking in apply with a UDF": [[25, "illustration-of-data-chunking-in-apply-with-a-udf"]], "Example: apply_dimension with a UDF": [[25, "example-apply-dimension-with-a-udf"]], "Example: reduce_dimension with a UDF": [[25, "example-reduce-dimension-with-a-udf"]], "Example: apply_neighborhood with a UDF": [[25, "example-apply-neighborhood-with-a-udf"]], "Example: Smoothing timeseries with a user defined function (UDF)": [[25, "example-smoothing-timeseries-with-a-user-defined-function-udf"]], "Downloading a datacube and executing an UDF locally": [[25, "downloading-a-datacube-and-executing-an-udf-locally"]], "UDF dependency management": [[25, "udf-dependency-management"]], "Profile a process server-side": [[25, "profile-a-process-server-side"]], "Viewing profiling information": [[25, "viewing-profiling-information"]], "Example": [[25, "example"]], "Logging from a UDF": [[25, "logging-from-a-udf"]], "openeo.UDF API and usage changes in version 0.13.0": [[25, "openeo-udf-api-and-usage-changes-in-version-0-13-0"]], "User-Defined Processes": [[26, "user-defined-processes"]], "Code reuse with user-defined processes": [[26, "code-reuse-with-user-defined-processes"]], "Process Parameters": [[26, "process-parameters"]], "Declaring Parameters": [[26, "declaring-parameters"]], "More advanced parameter schemas": [[26, "more-advanced-parameter-schemas"]], "Building and storing user-defined process": [[26, "building-and-storing-user-defined-process"]], "Through \u201cprocess functions\u201d": [[26, "through-process-functions"]], "From a parameterized data cube": [[26, "from-a-parameterized-data-cube"]], "Using a predefined dictionary": [[26, "using-a-predefined-dictionary"]], "Store to a file": [[26, "store-to-a-file"]], "Evaluate user-defined processes": [[26, "evaluate-user-defined-processes"]], "UDP Example: EVI timeseries": [[26, "udp-example-evi-timeseries"]]}, "indexentries": {"bboxdict (class in openeo.util)": [[0, "openeo.util.BBoxDict"]], "banddimension (class in openeo.metadata)": [[0, "openeo.metadata.BandDimension"]], "batchjob (class in openeo.rest.job)": [[0, "openeo.rest.job.BatchJob"]], "collectionmetadata (class in openeo.metadata)": [[0, "openeo.metadata.CollectionMetadata"]], "collectionproperty (class in openeo.rest.graph_building)": [[0, "openeo.rest.graph_building.CollectionProperty"]], "connection (class in openeo.rest.connection)": [[0, "openeo.rest.connection.Connection"]], "datacube (class in openeo.rest.datacube)": [[0, "openeo.rest.datacube.DataCube"]], "flatgraphablemixin (class in openeo.internal.graph_building)": [[0, "openeo.internal.graph_building.FlatGraphableMixin"]], "invalidtimeseriesexception": [[0, "openeo.rest.conversions.InvalidTimeSeriesException"]], "jobresults (class in openeo.rest.job)": [[0, "openeo.rest.job.JobResults"]], "logentry (class in openeo.api.logs)": [[0, "openeo.api.logs.LogEntry"]], "mlmodel (class in openeo.rest.mlmodel)": [[0, "openeo.rest.mlmodel.MlModel"]], "pgnode (class in openeo.internal.graph_building)": [[0, "openeo.internal.graph_building.PGNode"]], "parameter (class in openeo.api.process)": [[0, "openeo.api.process.Parameter"]], "restjob (class in openeo.rest.job)": [[0, "openeo.rest.job.RESTJob"]], "restuserdefinedprocess (class in openeo.rest.udp)": [[0, "openeo.rest.udp.RESTUserDefinedProcess"]], "resultasset (class in openeo.rest.job)": [[0, "openeo.rest.job.ResultAsset"]], "spatialdimension (class in openeo.metadata)": [[0, "openeo.metadata.SpatialDimension"]], "structureddata (class in openeo.udf.structured_data)": [[0, "openeo.udf.structured_data.StructuredData"]], "this (in module openeo.rest.datacube)": [[0, "openeo.rest.datacube.THIS"]], "temporaldimension (class in openeo.metadata)": [[0, "openeo.metadata.TemporalDimension"]], "udf (class in openeo.rest._datacube)": [[0, "openeo.rest._datacube.UDF"]], "udfdata (class in openeo.udf.udf_data)": [[0, "openeo.udf.udf_data.UdfData"]], "userfile (class in openeo.rest.userfile)": [[0, "openeo.rest.userfile.UserFile"]], "vectorcube (class in openeo.rest.vectorcube)": [[0, "openeo.rest.vectorcube.VectorCube"]], "xarraydatacube (class in openeo.udf.xarraydatacube)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube"]], "__init__() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.__init__"]], "add() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.add"]], "add_dimension() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.add_dimension"]], "add_dimension() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.add_dimension"]], "aggregate_spatial() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.aggregate_spatial"]], "aggregate_spatial_window() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.aggregate_spatial_window"]], "aggregate_temporal() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.aggregate_temporal"]], "aggregate_temporal_period() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.aggregate_temporal_period"]], "append_band() (openeo.metadata.banddimension method)": [[0, "openeo.metadata.BandDimension.append_band"]], "append_band() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.append_band"]], "apply() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.apply"]], "apply_dimension() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.apply_dimension"]], "apply_dimension() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.apply_dimension"]], "apply_kernel() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.apply_kernel"]], "apply_neighborhood() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.apply_neighborhood"]], "apply_polygon() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.apply_polygon"]], "ard_normalized_radar_backscatter() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.ard_normalized_radar_backscatter"]], "ard_surface_reflectance() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.ard_surface_reflectance"]], "array (openeo.udf.xarraydatacube.xarraydatacube property)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube.array"]], "array() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.array"]], "as_curl() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.as_curl"]], "assert_user_defined_process_support() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.assert_user_defined_process_support"]], "assert_valid_dimension() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.assert_valid_dimension"]], "atmospheric_correction() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.atmospheric_correction"]], "authenticate_basic() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.authenticate_basic"]], "authenticate_oidc() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.authenticate_oidc"]], "authenticate_oidc_authorization_code() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.authenticate_oidc_authorization_code"]], "authenticate_oidc_client_credentials() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.authenticate_oidc_client_credentials"]], "authenticate_oidc_device() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.authenticate_oidc_device"]], "authenticate_oidc_refresh_token() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.authenticate_oidc_refresh_token"]], "authenticate_oidc_resource_owner_password_credentials() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.authenticate_oidc_resource_owner_password_credentials"]], "band() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.band"]], "band_dimension (openeo.metadata.collectionmetadata property)": [[0, "openeo.metadata.CollectionMetadata.band_dimension"]], "band_filter() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.band_filter"]], "band_index() (openeo.metadata.banddimension method)": [[0, "openeo.metadata.BandDimension.band_index"]], "band_name() (openeo.metadata.banddimension method)": [[0, "openeo.metadata.BandDimension.band_name"]], "band_names (openeo.metadata.collectionmetadata property)": [[0, "openeo.metadata.CollectionMetadata.band_names"]], "bands (openeo.metadata.collectionmetadata property)": [[0, "openeo.metadata.CollectionMetadata.bands"]], "boolean() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.boolean"]], "build_process_dict() (in module openeo.rest.udp)": [[0, "openeo.rest.udp.build_process_dict"]], "capabilities() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.capabilities"]], "chunk_polygon() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.chunk_polygon"]], "collection_items() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.collection_items"]], "collection_property() (in module openeo.rest.graph_building)": [[0, "openeo.rest.graph_building.collection_property"]], "connect() (in module openeo)": [[0, "openeo.connect"]], "count_time() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.count_time"]], "create_collection() (openeo.rest.datacube.datacube class method)": [[0, "openeo.rest.datacube.DataCube.create_collection"]], "create_job() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.create_job"]], "create_job() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.create_job"]], "create_job() (openeo.rest.mlmodel.mlmodel method)": [[0, "openeo.rest.mlmodel.MlModel.create_job"]], "create_job() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.create_job"]], "datacube() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.datacube"]], "datacube_from_file() (in module openeo.rest.conversions)": [[0, "openeo.rest.conversions.datacube_from_file"]], "datacube_from_flat_graph() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.datacube_from_flat_graph"]], "datacube_from_json() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.datacube_from_json"]], "datacube_from_process() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.datacube_from_process"]], "datacube_list (openeo.udf.udf_data.udfdata property)": [[0, "openeo.udf.udf_data.UdfData.datacube_list"]], "datacube_plot() (in module openeo.rest.conversions)": [[0, "openeo.rest.conversions.datacube_plot"]], "datacube_to_file() (in module openeo.rest.conversions)": [[0, "openeo.rest.conversions.datacube_to_file"]], "delete() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.delete"]], "delete() (openeo.rest.udp.restuserdefinedprocess method)": [[0, "openeo.rest.udp.RESTUserDefinedProcess.delete"]], "delete() (openeo.rest.userfile.userfile method)": [[0, "openeo.rest.userfile.UserFile.delete"]], "delete_job() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.delete_job"]], "describe() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.describe"]], "describe() (openeo.rest.udp.restuserdefinedprocess method)": [[0, "openeo.rest.udp.RESTUserDefinedProcess.describe"]], "describe_account() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.describe_account"]], "describe_collection() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.describe_collection"]], "describe_job() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.describe_job"]], "describe_process() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.describe_process"]], "dimension_labels() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.dimension_labels"]], "divide() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.divide"]], "download() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.download"]], "download() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.download"]], "download() (openeo.rest.job.resultasset method)": [[0, "openeo.rest.job.ResultAsset.download"]], "download() (openeo.rest.userfile.userfile method)": [[0, "openeo.rest.userfile.UserFile.download"]], "download() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.download"]], "download_file() (openeo.rest.job.jobresults method)": [[0, "openeo.rest.job.JobResults.download_file"]], "download_files() (openeo.rest.job.jobresults method)": [[0, "openeo.rest.job.JobResults.download_files"]], "download_result() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.download_result"]], "download_results() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.download_results"]], "drop_dimension() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.drop_dimension"]], "drop_dimension() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.drop_dimension"]], "estimate() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.estimate"]], "estimate_job() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.estimate_job"]], "execute() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.execute"]], "execute() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.execute"]], "execute() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.execute"]], "execute_batch() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.execute_batch"]], "execute_batch() (openeo.rest.mlmodel.mlmodel method)": [[0, "openeo.rest.mlmodel.MlModel.execute_batch"]], "execute_batch() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.execute_batch"]], "execute_local_udf() (in module openeo.udf.run_code)": [[0, "openeo.udf.run_code.execute_local_udf"]], "execute_local_udf() (openeo.rest.datacube.datacube static method)": [[0, "openeo.rest.datacube.DataCube.execute_local_udf"]], "feature_collection_list (openeo.udf.udf_data.udfdata property)": [[0, "openeo.udf.udf_data.UdfData.feature_collection_list"]], "filter_bands() (openeo.metadata.banddimension method)": [[0, "openeo.metadata.BandDimension.filter_bands"]], "filter_bands() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.filter_bands"]], "filter_bands() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.filter_bands"]], "filter_bands() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.filter_bands"]], "filter_bbox() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.filter_bbox"]], "filter_bbox() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.filter_bbox"]], "filter_labels() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.filter_labels"]], "filter_spatial() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.filter_spatial"]], "filter_temporal() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.filter_temporal"]], "filter_vector() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.filter_vector"]], "fit_class_random_forest() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.fit_class_random_forest"]], "fit_curve() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.fit_curve"]], "fit_regr_random_forest() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.fit_regr_random_forest"]], "flat_graph() (openeo.internal.graph_building.pgnode method)": [[0, "openeo.internal.graph_building.PGNode.flat_graph"]], "flat_graph() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.flat_graph"]], "flat_graph() (openeo.rest.mlmodel.mlmodel method)": [[0, "openeo.rest.mlmodel.MlModel.flat_graph"]], "flat_graph() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.flat_graph"]], "flatten_dimensions() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.flatten_dimensions"]], "from_dict() (openeo.udf.udf_data.udfdata class method)": [[0, "openeo.udf.udf_data.UdfData.from_dict"]], "from_dict() (openeo.udf.xarraydatacube.xarraydatacube class method)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube.from_dict"]], "from_dict() (openeo.util.bboxdict class method)": [[0, "openeo.util.BBoxDict.from_dict"]], "from_file() (openeo.rest._datacube.udf class method)": [[0, "openeo.rest._datacube.UDF.from_file"]], "from_file() (openeo.udf.xarraydatacube.xarraydatacube class method)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube.from_file"]], "from_flat_graph() (openeo.internal.graph_building.pgnode static method)": [[0, "openeo.internal.graph_building.PGNode.from_flat_graph"]], "from_metadata() (openeo.rest.userfile.userfile class method)": [[0, "openeo.rest.userfile.UserFile.from_metadata"]], "from_sequence() (openeo.util.bboxdict class method)": [[0, "openeo.util.BBoxDict.from_sequence"]], "from_url() (openeo.rest._datacube.udf class method)": [[0, "openeo.rest._datacube.UDF.from_url"]], "get_array() (openeo.udf.xarraydatacube.xarraydatacube method)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube.get_array"]], "get_asset() (openeo.rest.job.jobresults method)": [[0, "openeo.rest.job.JobResults.get_asset"]], "get_assets() (openeo.rest.job.jobresults method)": [[0, "openeo.rest.job.JobResults.get_assets"]], "get_datacube_list() (openeo.udf.udf_data.udfdata method)": [[0, "openeo.udf.udf_data.UdfData.get_datacube_list"]], "get_feature_collection_list() (openeo.udf.udf_data.udfdata method)": [[0, "openeo.udf.udf_data.UdfData.get_feature_collection_list"]], "get_file() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.get_file"]], "get_metadata() (openeo.rest.job.jobresults method)": [[0, "openeo.rest.job.JobResults.get_metadata"]], "get_result() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.get_result"]], "get_results() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.get_results"]], "get_results_metadata_url() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.get_results_metadata_url"]], "get_run_udf_callback() (openeo.rest._datacube.udf method)": [[0, "openeo.rest._datacube.UDF.get_run_udf_callback"]], "get_structured_data_list() (openeo.udf.udf_data.udfdata method)": [[0, "openeo.udf.udf_data.UdfData.get_structured_data_list"]], "graph_add_node() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.graph_add_node"]], "href (openeo.rest.job.resultasset attribute)": [[0, "openeo.rest.job.ResultAsset.href"]], "imagecollection() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.imagecollection"]], "inspect() (in module openeo.udf.debug)": [[0, "openeo.udf.debug.inspect"]], "integer() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.integer"]], "job() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.job"]], "job_id (openeo.rest.job.batchjob attribute)": [[0, "openeo.rest.job.BatchJob.job_id"]], "job_logs() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.job_logs"]], "job_results() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.job_results"]], "linear_scale_range() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.linear_scale_range"]], "list_collection_ids() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_collection_ids"]], "list_collections() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_collections"]], "list_file_formats() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_file_formats"]], "list_file_types() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_file_types"]], "list_files() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_files"]], "list_jobs() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_jobs"]], "list_processes() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_processes"]], "list_results() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.list_results"]], "list_service_types() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_service_types"]], "list_services() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_services"]], "list_udf_runtimes() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_udf_runtimes"]], "list_user_defined_processes() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.list_user_defined_processes"]], "ln() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.ln"]], "load_bytes() (openeo.rest.job.resultasset method)": [[0, "openeo.rest.job.ResultAsset.load_bytes"]], "load_collection() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.load_collection"]], "load_collection() (openeo.rest.datacube.datacube class method)": [[0, "openeo.rest.datacube.DataCube.load_collection"]], "load_disk_collection() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.load_disk_collection"]], "load_disk_collection() (openeo.rest.datacube.datacube class method)": [[0, "openeo.rest.datacube.DataCube.load_disk_collection"]], "load_geojson() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.load_geojson"]], "load_geojson() (openeo.rest.vectorcube.vectorcube class method)": [[0, "openeo.rest.vectorcube.VectorCube.load_geojson"]], "load_json() (openeo.rest.job.resultasset method)": [[0, "openeo.rest.job.ResultAsset.load_json"]], "load_json_resource() (in module openeo.util)": [[0, "openeo.util.load_json_resource"]], "load_ml_model() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.load_ml_model"]], "load_ml_model() (openeo.rest.mlmodel.mlmodel static method)": [[0, "openeo.rest.mlmodel.MlModel.load_ml_model"]], "load_result() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.load_result"]], "load_stac() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.load_stac"]], "load_url() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.load_url"]], "load_url() (openeo.rest.vectorcube.vectorcube class method)": [[0, "openeo.rest.vectorcube.VectorCube.load_url"]], "log10() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.log10"]], "log2() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.log2"]], "logarithm() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.logarithm"]], "logical_and() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.logical_and"]], "logical_or() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.logical_or"]], "logs() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.logs"]], "mask() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.mask"]], "mask_polygon() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.mask_polygon"]], "max_time() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.max_time"]], "mean_time() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.mean_time"]], "median_time() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.median_time"]], "merge() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.merge"]], "merge_cubes() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.merge_cubes"]], "metadata (openeo.rest.job.resultasset attribute)": [[0, "openeo.rest.job.ResultAsset.metadata"]], "min_time() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.min_time"]], "module": [[0, "module-openeo.api.logs"], [0, "module-openeo.api.process"], [0, "module-openeo.internal.graph_building"], [0, "module-openeo.metadata"], [0, "module-openeo.processes"], [0, "module-openeo.rest._datacube"], [0, "module-openeo.rest.connection"], [0, "module-openeo.rest.conversions"], [0, "module-openeo.rest.datacube"], [0, "module-openeo.rest.graph_building"], [0, "module-openeo.rest.job"], [0, "module-openeo.rest.mlmodel"], [0, "module-openeo.rest.udp"], [0, "module-openeo.rest.userfile"], [0, "module-openeo.rest.vectorcube"], [0, "module-openeo.udf.debug"], [0, "module-openeo.udf.run_code"], [0, "module-openeo.udf.structured_data"], [0, "module-openeo.udf.udf_data"], [0, "module-openeo.udf.xarraydatacube"], [0, "module-openeo.util"], [2, "module-0"], [2, "module-openeo.processes"], [11, "module-openeo.extra.job_management"], [14, "module-openeo.extra.spectral_indices"], [25, "module-openeo.udf.udf_signatures"]], "multiply() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.multiply"]], "name (openeo.rest.job.resultasset attribute)": [[0, "openeo.rest.job.ResultAsset.name"]], "ndvi() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.ndvi"]], "normalize_crs() (in module openeo.util)": [[0, "openeo.util.normalize_crs"]], "normalize_log_level() (in module openeo.api.logs)": [[0, "openeo.api.logs.normalize_log_level"]], "normalized_difference() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.normalized_difference"]], "number() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.number"]], "object() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.object"]], "openeo.api.logs": [[0, "module-openeo.api.logs"]], "openeo.api.process": [[0, "module-openeo.api.process"]], "openeo.internal.graph_building": [[0, "module-openeo.internal.graph_building"]], "openeo.metadata": [[0, "module-openeo.metadata"]], "openeo.processes": [[0, "module-openeo.processes"], [2, "module-0"], [2, "module-openeo.processes"]], "openeo.rest._datacube": [[0, "module-openeo.rest._datacube"]], "openeo.rest.connection": [[0, "module-openeo.rest.connection"]], "openeo.rest.conversions": [[0, "module-openeo.rest.conversions"]], "openeo.rest.datacube": [[0, "module-openeo.rest.datacube"]], "openeo.rest.graph_building": [[0, "module-openeo.rest.graph_building"]], "openeo.rest.job": [[0, "module-openeo.rest.job"]], "openeo.rest.mlmodel": [[0, "module-openeo.rest.mlmodel"]], "openeo.rest.udp": [[0, "module-openeo.rest.udp"]], "openeo.rest.userfile": [[0, "module-openeo.rest.userfile"]], "openeo.rest.vectorcube": [[0, "module-openeo.rest.vectorcube"]], "openeo.udf.debug": [[0, "module-openeo.udf.debug"]], "openeo.udf.run_code": [[0, "module-openeo.udf.run_code"]], "openeo.udf.structured_data": [[0, "module-openeo.udf.structured_data"]], "openeo.udf.udf_data": [[0, "module-openeo.udf.udf_data"]], "openeo.udf.xarraydatacube": [[0, "module-openeo.udf.xarraydatacube"]], "openeo.util": [[0, "module-openeo.util"]], "plot() (openeo.udf.xarraydatacube.xarraydatacube method)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube.plot"]], "polygonal_histogram_timeseries() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.polygonal_histogram_timeseries"]], "polygonal_mean_timeseries() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.polygonal_mean_timeseries"]], "polygonal_median_timeseries() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.polygonal_median_timeseries"]], "polygonal_standarddeviation_timeseries() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.polygonal_standarddeviation_timeseries"]], "power() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.power"]], "predict_curve() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.predict_curve"]], "predict_random_forest() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.predict_random_forest"]], "preview() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.preview"]], "print_json() (openeo.internal.graph_building.flatgraphablemixin method)": [[0, "openeo.internal.graph_building.FlatGraphableMixin.print_json"]], "print_json() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.print_json"]], "print_json() (openeo.rest.mlmodel.mlmodel method)": [[0, "openeo.rest.mlmodel.MlModel.print_json"]], "print_json() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.print_json"]], "process() (in module openeo.processes)": [[0, "openeo.processes.process"]], "process() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.process"]], "process() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.process"]], "process_with_node() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.process_with_node"]], "raster_cube() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.raster_cube"]], "raster_to_vector() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.raster_to_vector"]], "reduce_bands() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_bands"]], "reduce_bands_udf() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_bands_udf"]], "reduce_dimension() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.reduce_dimension"]], "reduce_dimension() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_dimension"]], "reduce_spatial() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.reduce_spatial"]], "reduce_spatial() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_spatial"]], "reduce_temporal() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_temporal"]], "reduce_temporal_simple() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_temporal_simple"]], "reduce_temporal_udf() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_temporal_udf"]], "reduce_tiles_over_time() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.reduce_tiles_over_time"]], "remove_service() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.remove_service"]], "rename() (openeo.metadata.spatialdimension method)": [[0, "openeo.metadata.SpatialDimension.rename"]], "rename() (openeo.metadata.temporaldimension method)": [[0, "openeo.metadata.TemporalDimension.rename"]], "rename_dimension() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.rename_dimension"]], "rename_dimension() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.rename_dimension"]], "rename_labels() (openeo.metadata.banddimension method)": [[0, "openeo.metadata.BandDimension.rename_labels"]], "rename_labels() (openeo.metadata.collectionmetadata method)": [[0, "openeo.metadata.CollectionMetadata.rename_labels"]], "rename_labels() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.rename_labels"]], "request() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.request"]], "resample_cube_spatial() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.resample_cube_spatial"]], "resample_cube_temporal() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.resample_cube_temporal"]], "resample_spatial() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.resample_spatial"]], "resolution_merge() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.resolution_merge"]], "result_node() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.result_node"]], "result_node() (openeo.rest.mlmodel.mlmodel method)": [[0, "openeo.rest.mlmodel.MlModel.result_node"]], "result_node() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.result_node"]], "run_synchronous() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.run_synchronous"]], "run_udf() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.run_udf"]], "sar_backscatter() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.sar_backscatter"]], "save_ml_model() (openeo.rest.mlmodel.mlmodel method)": [[0, "openeo.rest.mlmodel.MlModel.save_ml_model"]], "save_result() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.save_result"]], "save_result() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.save_result"]], "save_to_file() (openeo.udf.xarraydatacube.xarraydatacube method)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube.save_to_file"]], "save_user_defined_process() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.save_user_defined_process"]], "save_user_defined_process() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.save_user_defined_process"]], "send_job() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.send_job"]], "send_job() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.send_job"]], "service() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.service"]], "set_datacube_list() (openeo.udf.udf_data.udfdata method)": [[0, "openeo.udf.udf_data.UdfData.set_datacube_list"]], "set_structured_data_list() (openeo.udf.udf_data.udfdata method)": [[0, "openeo.udf.udf_data.UdfData.set_structured_data_list"]], "start() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.start"]], "start_and_wait() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.start_and_wait"]], "start_job() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.start_job"]], "status() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.status"]], "stop() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.stop"]], "stop_job() (openeo.rest.job.batchjob method)": [[0, "openeo.rest.job.BatchJob.stop_job"]], "store() (openeo.rest.udp.restuserdefinedprocess method)": [[0, "openeo.rest.udp.RESTUserDefinedProcess.store"]], "string() (openeo.api.process.parameter class method)": [[0, "openeo.api.process.Parameter.string"]], "structured_data_list (openeo.udf.udf_data.udfdata property)": [[0, "openeo.udf.udf_data.UdfData.structured_data_list"]], "subtract() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.subtract"]], "timeseries_json_to_pandas() (in module openeo.rest.conversions)": [[0, "openeo.rest.conversions.timeseries_json_to_pandas"]], "to_bbox_dict() (in module openeo.util)": [[0, "openeo.util.to_bbox_dict"]], "to_dict() (openeo.api.process.parameter method)": [[0, "openeo.api.process.Parameter.to_dict"]], "to_dict() (openeo.internal.graph_building.pgnode method)": [[0, "openeo.internal.graph_building.PGNode.to_dict"]], "to_dict() (openeo.rest.userfile.userfile method)": [[0, "openeo.rest.userfile.UserFile.to_dict"]], "to_dict() (openeo.udf.udf_data.udfdata method)": [[0, "openeo.udf.udf_data.UdfData.to_dict"]], "to_dict() (openeo.udf.xarraydatacube.xarraydatacube method)": [[0, "openeo.udf.xarraydatacube.XarrayDataCube.to_dict"]], "to_json() (openeo.internal.graph_building.flatgraphablemixin method)": [[0, "openeo.internal.graph_building.FlatGraphableMixin.to_json"]], "to_json() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.to_json"]], "to_json() (openeo.rest.mlmodel.mlmodel method)": [[0, "openeo.rest.mlmodel.MlModel.to_json"]], "to_json() (openeo.rest.vectorcube.vectorcube method)": [[0, "openeo.rest.vectorcube.VectorCube.to_json"]], "to_process_graph_argument() (openeo.internal.graph_building.pgnode static method)": [[0, "openeo.internal.graph_building.PGNode.to_process_graph_argument"]], "unflatten_dimension() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.unflatten_dimension"]], "update() (openeo.rest.udp.restuserdefinedprocess method)": [[0, "openeo.rest.udp.RESTUserDefinedProcess.update"]], "update_arguments() (openeo.internal.graph_building.pgnode method)": [[0, "openeo.internal.graph_building.PGNode.update_arguments"]], "upload() (openeo.rest.userfile.userfile method)": [[0, "openeo.rest.userfile.UserFile.upload"]], "upload_file() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.upload_file"]], "user_context (openeo.udf.udf_data.udfdata property)": [[0, "openeo.udf.udf_data.UdfData.user_context"]], "user_defined_process() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.user_defined_process"]], "user_jobs() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.user_jobs"]], "validate() (openeo.rest.datacube.datacube method)": [[0, "openeo.rest.datacube.DataCube.validate"]], "validate_process_graph() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.validate_process_graph"]], "vectorcube_from_paths() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.vectorcube_from_paths"]], "version_discovery() (openeo.rest.connection.connection class method)": [[0, "openeo.rest.connection.Connection.version_discovery"]], "version_info() (openeo.rest.connection.connection method)": [[0, "openeo.rest.connection.Connection.version_info"]], "processbuilder (class in openeo.processes)": [[2, "openeo.processes.ProcessBuilder"]], "absolute() (in module openeo.processes)": [[2, "openeo.processes.absolute"]], "absolute() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.absolute"]], "add() (in module openeo.processes)": [[2, "openeo.processes.add"]], "add() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.add"]], "add_dimension() (in module openeo.processes)": [[2, "openeo.processes.add_dimension"]], "add_dimension() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.add_dimension"]], "aggregate_spatial() (in module openeo.processes)": [[2, "openeo.processes.aggregate_spatial"]], "aggregate_spatial() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.aggregate_spatial"]], "aggregate_spatial_window() (in module openeo.processes)": [[2, "openeo.processes.aggregate_spatial_window"]], "aggregate_spatial_window() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.aggregate_spatial_window"]], "aggregate_temporal() (in module openeo.processes)": [[2, "openeo.processes.aggregate_temporal"]], "aggregate_temporal() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.aggregate_temporal"]], "aggregate_temporal_period() (in module openeo.processes)": [[2, "openeo.processes.aggregate_temporal_period"]], "aggregate_temporal_period() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.aggregate_temporal_period"]], "all() (in module openeo.processes)": [[2, "openeo.processes.all"]], "all() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.all"]], "and_() (in module openeo.processes)": [[2, "openeo.processes.and_"]], "and_() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.and_"]], "anomaly() (in module openeo.processes)": [[2, "openeo.processes.anomaly"]], "anomaly() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.anomaly"]], "any() (in module openeo.processes)": [[2, "openeo.processes.any"]], "any() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.any"]], "apply() (in module openeo.processes)": [[2, "openeo.processes.apply"]], "apply() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.apply"]], "apply_dimension() (in module openeo.processes)": [[2, "openeo.processes.apply_dimension"]], "apply_dimension() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.apply_dimension"]], "apply_kernel() (in module openeo.processes)": [[2, "openeo.processes.apply_kernel"]], "apply_kernel() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.apply_kernel"]], "apply_neighborhood() (in module openeo.processes)": [[2, "openeo.processes.apply_neighborhood"]], "apply_neighborhood() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.apply_neighborhood"]], "arccos() (in module openeo.processes)": [[2, "openeo.processes.arccos"]], "arccos() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.arccos"]], "arcosh() (in module openeo.processes)": [[2, "openeo.processes.arcosh"]], "arcosh() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.arcosh"]], "arcsin() (in module openeo.processes)": [[2, "openeo.processes.arcsin"]], "arcsin() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.arcsin"]], "arctan() (in module openeo.processes)": [[2, "openeo.processes.arctan"]], "arctan() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.arctan"]], "arctan2() (in module openeo.processes)": [[2, "openeo.processes.arctan2"]], "arctan2() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.arctan2"]], "ard_normalized_radar_backscatter() (in module openeo.processes)": [[2, "openeo.processes.ard_normalized_radar_backscatter"]], "ard_normalized_radar_backscatter() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.ard_normalized_radar_backscatter"]], "ard_surface_reflectance() (in module openeo.processes)": [[2, "openeo.processes.ard_surface_reflectance"]], "ard_surface_reflectance() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.ard_surface_reflectance"]], "array_append() (in module openeo.processes)": [[2, "openeo.processes.array_append"]], "array_append() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_append"]], "array_apply() (in module openeo.processes)": [[2, "openeo.processes.array_apply"]], "array_apply() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_apply"]], "array_concat() (in module openeo.processes)": [[2, "openeo.processes.array_concat"]], "array_concat() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_concat"]], "array_contains() (in module openeo.processes)": [[2, "openeo.processes.array_contains"]], "array_contains() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_contains"]], "array_create() (in module openeo.processes)": [[2, "openeo.processes.array_create"]], "array_create() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_create"]], "array_create_labeled() (in module openeo.processes)": [[2, "openeo.processes.array_create_labeled"]], "array_create_labeled() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_create_labeled"]], "array_element() (in module openeo.processes)": [[2, "openeo.processes.array_element"]], "array_element() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_element"]], "array_filter() (in module openeo.processes)": [[2, "openeo.processes.array_filter"]], "array_filter() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_filter"]], "array_find() (in module openeo.processes)": [[2, "openeo.processes.array_find"]], "array_find() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_find"]], "array_find_label() (in module openeo.processes)": [[2, "openeo.processes.array_find_label"]], "array_find_label() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_find_label"]], "array_interpolate_linear() (in module openeo.processes)": [[2, "openeo.processes.array_interpolate_linear"]], "array_interpolate_linear() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_interpolate_linear"]], "array_labels() (in module openeo.processes)": [[2, "openeo.processes.array_labels"]], "array_labels() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_labels"]], "array_modify() (in module openeo.processes)": [[2, "openeo.processes.array_modify"]], "array_modify() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.array_modify"]], "arsinh() (in module openeo.processes)": [[2, "openeo.processes.arsinh"]], "arsinh() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.arsinh"]], "artanh() (in module openeo.processes)": [[2, "openeo.processes.artanh"]], "artanh() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.artanh"]], "atmospheric_correction() (in module openeo.processes)": [[2, "openeo.processes.atmospheric_correction"]], "atmospheric_correction() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.atmospheric_correction"]], "between() (in module openeo.processes)": [[2, "openeo.processes.between"]], "between() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.between"]], "ceil() (in module openeo.processes)": [[2, "openeo.processes.ceil"]], "ceil() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.ceil"]], "climatological_normal() (in module openeo.processes)": [[2, "openeo.processes.climatological_normal"]], "climatological_normal() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.climatological_normal"]], "clip() (in module openeo.processes)": [[2, "openeo.processes.clip"]], "clip() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.clip"]], "cloud_detection() (in module openeo.processes)": [[2, "openeo.processes.cloud_detection"]], "cloud_detection() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.cloud_detection"]], "constant() (in module openeo.processes)": [[2, "openeo.processes.constant"]], "constant() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.constant"]], "cos() (in module openeo.processes)": [[2, "openeo.processes.cos"]], "cos() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.cos"]], "cosh() (in module openeo.processes)": [[2, "openeo.processes.cosh"]], "cosh() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.cosh"]], "count() (in module openeo.processes)": [[2, "openeo.processes.count"]], "count() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.count"]], "create_raster_cube() (in module openeo.processes)": [[2, "openeo.processes.create_raster_cube"]], "create_raster_cube() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.create_raster_cube"]], "cummax() (in module openeo.processes)": [[2, "openeo.processes.cummax"]], "cummax() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.cummax"]], "cummin() (in module openeo.processes)": [[2, "openeo.processes.cummin"]], "cummin() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.cummin"]], "cumproduct() (in module openeo.processes)": [[2, "openeo.processes.cumproduct"]], "cumproduct() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.cumproduct"]], "cumsum() (in module openeo.processes)": [[2, "openeo.processes.cumsum"]], "cumsum() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.cumsum"]], "date_shift() (in module openeo.processes)": [[2, "openeo.processes.date_shift"]], "date_shift() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.date_shift"]], "dimension_labels() (in module openeo.processes)": [[2, "openeo.processes.dimension_labels"]], "dimension_labels() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.dimension_labels"]], "divide() (in module openeo.processes)": [[2, "openeo.processes.divide"]], "divide() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.divide"]], "drop_dimension() (in module openeo.processes)": [[2, "openeo.processes.drop_dimension"]], "drop_dimension() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.drop_dimension"]], "e() (in module openeo.processes)": [[2, "openeo.processes.e"]], "e() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.e"]], "eq() (in module openeo.processes)": [[2, "openeo.processes.eq"]], "eq() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.eq"]], "exp() (in module openeo.processes)": [[2, "openeo.processes.exp"]], "exp() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.exp"]], "extrema() (in module openeo.processes)": [[2, "openeo.processes.extrema"]], "extrema() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.extrema"]], "filter_bands() (in module openeo.processes)": [[2, "openeo.processes.filter_bands"]], "filter_bands() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.filter_bands"]], "filter_bbox() (in module openeo.processes)": [[2, "openeo.processes.filter_bbox"]], "filter_bbox() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.filter_bbox"]], "filter_labels() (in module openeo.processes)": [[2, "openeo.processes.filter_labels"]], "filter_labels() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.filter_labels"]], "filter_spatial() (in module openeo.processes)": [[2, "openeo.processes.filter_spatial"]], "filter_spatial() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.filter_spatial"]], "filter_temporal() (in module openeo.processes)": [[2, "openeo.processes.filter_temporal"]], "filter_temporal() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.filter_temporal"]], "first() (in module openeo.processes)": [[2, "openeo.processes.first"]], "first() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.first"]], "fit_class_random_forest() (in module openeo.processes)": [[2, "openeo.processes.fit_class_random_forest"]], "fit_class_random_forest() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.fit_class_random_forest"]], "fit_curve() (in module openeo.processes)": [[2, "openeo.processes.fit_curve"]], "fit_curve() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.fit_curve"]], "fit_regr_random_forest() (in module openeo.processes)": [[2, "openeo.processes.fit_regr_random_forest"]], "fit_regr_random_forest() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.fit_regr_random_forest"]], "flatten_dimensions() (in module openeo.processes)": [[2, "openeo.processes.flatten_dimensions"]], "flatten_dimensions() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.flatten_dimensions"]], "floor() (in module openeo.processes)": [[2, "openeo.processes.floor"]], "floor() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.floor"]], "gt() (in module openeo.processes)": [[2, "openeo.processes.gt"]], "gt() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.gt"]], "gte() (in module openeo.processes)": [[2, "openeo.processes.gte"]], "gte() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.gte"]], "if_() (in module openeo.processes)": [[2, "openeo.processes.if_"]], "if_() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.if_"]], "inspect() (in module openeo.processes)": [[2, "openeo.processes.inspect"]], "inspect() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.inspect"]], "int() (in module openeo.processes)": [[2, "openeo.processes.int"]], "int() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.int"]], "is_infinite() (in module openeo.processes)": [[2, "openeo.processes.is_infinite"]], "is_infinite() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.is_infinite"]], "is_nan() (in module openeo.processes)": [[2, "openeo.processes.is_nan"]], "is_nan() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.is_nan"]], "is_nodata() (in module openeo.processes)": [[2, "openeo.processes.is_nodata"]], "is_nodata() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.is_nodata"]], "is_valid() (in module openeo.processes)": [[2, "openeo.processes.is_valid"]], "is_valid() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.is_valid"]], "last() (in module openeo.processes)": [[2, "openeo.processes.last"]], "last() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.last"]], "linear_scale_range() (in module openeo.processes)": [[2, "openeo.processes.linear_scale_range"]], "linear_scale_range() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.linear_scale_range"]], "ln() (in module openeo.processes)": [[2, "openeo.processes.ln"]], "ln() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.ln"]], "load_collection() (in module openeo.processes)": [[2, "openeo.processes.load_collection"]], "load_collection() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.load_collection"]], "load_ml_model() (in module openeo.processes)": [[2, "openeo.processes.load_ml_model"]], "load_ml_model() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.load_ml_model"]], "load_result() (in module openeo.processes)": [[2, "openeo.processes.load_result"]], "load_result() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.load_result"]], "load_uploaded_files() (in module openeo.processes)": [[2, "openeo.processes.load_uploaded_files"]], "load_uploaded_files() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.load_uploaded_files"]], "log() (in module openeo.processes)": [[2, "openeo.processes.log"]], "log() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.log"]], "lt() (in module openeo.processes)": [[2, "openeo.processes.lt"]], "lt() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.lt"]], "lte() (in module openeo.processes)": [[2, "openeo.processes.lte"]], "lte() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.lte"]], "mask() (in module openeo.processes)": [[2, "openeo.processes.mask"]], "mask() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.mask"]], "mask_polygon() (in module openeo.processes)": [[2, "openeo.processes.mask_polygon"]], "mask_polygon() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.mask_polygon"]], "max() (in module openeo.processes)": [[2, "openeo.processes.max"]], "max() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.max"]], "mean() (in module openeo.processes)": [[2, "openeo.processes.mean"]], "mean() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.mean"]], "median() (in module openeo.processes)": [[2, "openeo.processes.median"]], "median() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.median"]], "merge_cubes() (in module openeo.processes)": [[2, "openeo.processes.merge_cubes"]], "merge_cubes() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.merge_cubes"]], "min() (in module openeo.processes)": [[2, "openeo.processes.min"]], "min() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.min"]], "mod() (in module openeo.processes)": [[2, "openeo.processes.mod"]], "mod() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.mod"]], "multiply() (in module openeo.processes)": [[2, "openeo.processes.multiply"]], "multiply() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.multiply"]], "nan() (in module openeo.processes)": [[2, "openeo.processes.nan"]], "nan() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.nan"]], "ndvi() (in module openeo.processes)": [[2, "openeo.processes.ndvi"]], "ndvi() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.ndvi"]], "neq() (in module openeo.processes)": [[2, "openeo.processes.neq"]], "neq() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.neq"]], "normalized_difference() (in module openeo.processes)": [[2, "openeo.processes.normalized_difference"]], "normalized_difference() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.normalized_difference"]], "not_() (in module openeo.processes)": [[2, "openeo.processes.not_"]], "not_() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.not_"]], "or_() (in module openeo.processes)": [[2, "openeo.processes.or_"]], "or_() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.or_"]], "order() (in module openeo.processes)": [[2, "openeo.processes.order"]], "order() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.order"]], "pi() (in module openeo.processes)": [[2, "openeo.processes.pi"]], "pi() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.pi"]], "power() (in module openeo.processes)": [[2, "openeo.processes.power"]], "power() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.power"]], "predict_curve() (in module openeo.processes)": [[2, "openeo.processes.predict_curve"]], "predict_curve() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.predict_curve"]], "predict_random_forest() (in module openeo.processes)": [[2, "openeo.processes.predict_random_forest"]], "predict_random_forest() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.predict_random_forest"]], "product() (in module openeo.processes)": [[2, "openeo.processes.product"]], "product() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.product"]], "quantiles() (in module openeo.processes)": [[2, "openeo.processes.quantiles"]], "quantiles() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.quantiles"]], "rearrange() (in module openeo.processes)": [[2, "openeo.processes.rearrange"]], "rearrange() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.rearrange"]], "reduce_dimension() (in module openeo.processes)": [[2, "openeo.processes.reduce_dimension"]], "reduce_dimension() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.reduce_dimension"]], "reduce_spatial() (in module openeo.processes)": [[2, "openeo.processes.reduce_spatial"]], "reduce_spatial() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.reduce_spatial"]], "rename_dimension() (in module openeo.processes)": [[2, "openeo.processes.rename_dimension"]], "rename_dimension() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.rename_dimension"]], "rename_labels() (in module openeo.processes)": [[2, "openeo.processes.rename_labels"]], "rename_labels() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.rename_labels"]], "resample_cube_spatial() (in module openeo.processes)": [[2, "openeo.processes.resample_cube_spatial"]], "resample_cube_spatial() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.resample_cube_spatial"]], "resample_cube_temporal() (in module openeo.processes)": [[2, "openeo.processes.resample_cube_temporal"]], "resample_cube_temporal() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.resample_cube_temporal"]], "resample_spatial() (in module openeo.processes)": [[2, "openeo.processes.resample_spatial"]], "resample_spatial() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.resample_spatial"]], "round() (in module openeo.processes)": [[2, "openeo.processes.round"]], "round() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.round"]], "run_udf() (in module openeo.processes)": [[2, "openeo.processes.run_udf"]], "run_udf() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.run_udf"]], "run_udf_externally() (in module openeo.processes)": [[2, "openeo.processes.run_udf_externally"]], "run_udf_externally() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.run_udf_externally"]], "sar_backscatter() (in module openeo.processes)": [[2, "openeo.processes.sar_backscatter"]], "sar_backscatter() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sar_backscatter"]], "save_ml_model() (in module openeo.processes)": [[2, "openeo.processes.save_ml_model"]], "save_ml_model() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.save_ml_model"]], "save_result() (in module openeo.processes)": [[2, "openeo.processes.save_result"]], "save_result() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.save_result"]], "sd() (in module openeo.processes)": [[2, "openeo.processes.sd"]], "sd() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sd"]], "sgn() (in module openeo.processes)": [[2, "openeo.processes.sgn"]], "sgn() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sgn"]], "sin() (in module openeo.processes)": [[2, "openeo.processes.sin"]], "sin() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sin"]], "sinh() (in module openeo.processes)": [[2, "openeo.processes.sinh"]], "sinh() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sinh"]], "sort() (in module openeo.processes)": [[2, "openeo.processes.sort"]], "sort() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sort"]], "sqrt() (in module openeo.processes)": [[2, "openeo.processes.sqrt"]], "sqrt() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sqrt"]], "subtract() (in module openeo.processes)": [[2, "openeo.processes.subtract"]], "subtract() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.subtract"]], "sum() (in module openeo.processes)": [[2, "openeo.processes.sum"]], "sum() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.sum"]], "tan() (in module openeo.processes)": [[2, "openeo.processes.tan"]], "tan() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.tan"]], "tanh() (in module openeo.processes)": [[2, "openeo.processes.tanh"]], "tanh() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.tanh"]], "text_begins() (in module openeo.processes)": [[2, "openeo.processes.text_begins"]], "text_begins() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.text_begins"]], "text_concat() (in module openeo.processes)": [[2, "openeo.processes.text_concat"]], "text_concat() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.text_concat"]], "text_contains() (in module openeo.processes)": [[2, "openeo.processes.text_contains"]], "text_contains() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.text_contains"]], "text_ends() (in module openeo.processes)": [[2, "openeo.processes.text_ends"]], "text_ends() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.text_ends"]], "trim_cube() (in module openeo.processes)": [[2, "openeo.processes.trim_cube"]], "trim_cube() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.trim_cube"]], "unflatten_dimension() (in module openeo.processes)": [[2, "openeo.processes.unflatten_dimension"]], "unflatten_dimension() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.unflatten_dimension"]], "variance() (in module openeo.processes)": [[2, "openeo.processes.variance"]], "variance() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.variance"]], "vector_buffer() (in module openeo.processes)": [[2, "openeo.processes.vector_buffer"]], "vector_buffer() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.vector_buffer"]], "vector_to_random_points() (in module openeo.processes)": [[2, "openeo.processes.vector_to_random_points"]], "vector_to_random_points() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.vector_to_random_points"]], "vector_to_regular_points() (in module openeo.processes)": [[2, "openeo.processes.vector_to_regular_points"]], "vector_to_regular_points() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.vector_to_regular_points"]], "xor() (in module openeo.processes)": [[2, "openeo.processes.xor"]], "xor() (openeo.processes.processbuilder method)": [[2, "openeo.processes.ProcessBuilder.xor"]], "batch job": [[5, "index-0"], [5, "index-1"], [5, "index-2"], [5, "index-3"], [5, "index-4"], [5, "index-5"], [5, "index-6"], [5, "index-7"], [5, "index-8"]], "create": [[5, "index-1"]], "job": [[5, "index-0"]], "listing": [[5, "index-3"]], "logs": [[5, "index-7"]], "object": [[5, "index-2"]], "polling loop": [[5, "index-6"]], "results": [[5, "index-8"]], "start": [[5, "index-4"]], "status": [[5, "index-5"]], "multibackendjobmanager (class in openeo.extra.job_management)": [[11, "openeo.extra.job_management.MultiBackendJobManager"]], "add_backend() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.add_backend"]], "ensure_job_dir_exists() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.ensure_job_dir_exists"]], "get_error_log_path() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.get_error_log_path"]], "get_job_dir() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.get_job_dir"]], "get_job_metadata_path() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.get_job_metadata_path"]], "ignore_connection_errors() (in module openeo.extra.job_management)": [[11, "openeo.extra.job_management.ignore_connection_errors"]], "on_job_done() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.on_job_done"]], "on_job_error() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.on_job_error"]], "openeo.extra.job_management": [[11, "module-openeo.extra.job_management"]], "run_jobs() (openeo.extra.job_management.multibackendjobmanager method)": [[11, "openeo.extra.job_management.MultiBackendJobManager.run_jobs"]], "append_and_rescale_indices() (in module openeo.extra.spectral_indices)": [[14, "openeo.extra.spectral_indices.append_and_rescale_indices"]], "append_index() (in module openeo.extra.spectral_indices)": [[14, "openeo.extra.spectral_indices.append_index"]], "append_indices() (in module openeo.extra.spectral_indices)": [[14, "openeo.extra.spectral_indices.append_indices"]], "compute_and_rescale_indices() (in module openeo.extra.spectral_indices)": [[14, "openeo.extra.spectral_indices.compute_and_rescale_indices"]], "compute_index() (in module openeo.extra.spectral_indices)": [[14, "openeo.extra.spectral_indices.compute_index"]], "compute_indices() (in module openeo.extra.spectral_indices)": [[14, "openeo.extra.spectral_indices.compute_indices"]], "list_indices() (in module openeo.extra.spectral_indices)": [[14, "openeo.extra.spectral_indices.list_indices"]], "openeo.extra.spectral_indices": [[14, "module-openeo.extra.spectral_indices"]], "udf": [[25, "index-1"]], "user-defined functions": [[25, "index-0"]], "apply_datacube() (in module openeo.udf.udf_signatures)": [[25, "openeo.udf.udf_signatures.apply_datacube"]], "apply_metadata() (in module openeo.udf.udf_signatures)": [[25, "openeo.udf.udf_signatures.apply_metadata"]], "apply_timeseries() (in module openeo.udf.udf_signatures)": [[25, "openeo.udf.udf_signatures.apply_timeseries"]], "apply_udf_data() (in module openeo.udf.udf_signatures)": [[25, "openeo.udf.udf_signatures.apply_udf_data"]], "chunking": [[25, "index-2"]], "openeo.udf.udf_signatures": [[25, "module-openeo.udf.udf_signatures"]]}}) \ No newline at end of file diff --git a/udf.html b/udf.html new file mode 100644 index 000000000..e597c4eb4 --- /dev/null +++ b/udf.html @@ -0,0 +1,775 @@ + + + + + + + + User-Defined Functions (UDF) explained — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    User-Defined Functions (UDF) explained

    +

    While openEO supports a wide range of pre-defined processes +and allows to build more complex user-defined processes from them, +you sometimes need operations or algorithms that are +not (yet) available or standardized as openEO process. +User-Defined Functions (UDF) is an openEO feature +(through the run_udf process) +that aims to fill that gap by allowing a user to express (a part of) +an algorithm as a Python/R/… script to be run back-end side.

    +

    There are a lot of details to cover, +but here is a rudimentary example snippet +to give you a quick impression of how to work with UDFs +using the openEO Python Client library:

    +
    +
    Basic UDF usage example snippet to rescale pixel values
    +
    # Build a UDF object from an inline string with Python source code.
    +udf = openeo.UDF("""
    +from openeo.udf import XarrayDataCube
    +
    +def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube:
    +    array = cube.get_array()
    +    array.values = 0.0001 * array.values
    +    return cube
    +""")
    +
    +# Apply the UDF to a cube.
    +rescaled_cube = cube.apply(process=udf)
    +
    +
    +
    +

    Ideally, it allows you to embed existing Python/R/… implementations +in an openEO workflow (with some necessary “glue code”). +However, it is recommended to try to do as much pre- or postprocessing +with pre-defined processes +before blindly copy-pasting source code snippets as UDFs. +Pre-defined processes are typically well-optimized by the backend, +while UDFs can come with a performance penalty +and higher development/debug/maintenance costs.

    +
    +

    Warning

    +

    Don not confuse user-defined functions (abbreviated as UDF) with +user-defined processes (sometimes abbreviated as UDP) in openEO, +which is a way to define and use your own process graphs +as reusable building blocks. +See User-Defined Processes for more information.

    +
    +
    +

    Applicability and Constraints

    +

    openEO is designed to work transparently on large data sets +and your UDF has to follow a couple of guidelines to make that possible. +First of all, as data cubes play a central role in openEO, +your UDF should accept and return correct data cube structures, +with proper dimensions, dimension labels, etc. +Moreover, the back-end will typically divide your input data cube +in smaller chunks and process these chunks separately (e.g. on isolated workers). +Consequently, it’s important that your UDF algorithm operates correctly +in such a chunked processing context.

    +
    +

    UDFs as apply/reduce “callbacks”

    +

    UDFs are typically used as “callback” processes for “meta” processes +like apply or reduce_dimension (also see Processes with child “callbacks”). +These meta-processes make abstraction of a datacube as a whole +and allow the callback to focus on a small slice of data or a single dimension. +Their nature instructs the backend how the data should be processed +and can be chunked:

    +
    +
    apply

    Applies a process on each pixel separately. +The back-end has all freedom to choose chunking +(e.g. chunk spatially and temporally). +Dimensions and their labels are fully preserved. +See A first example: apply with an UDF to rescale pixel values

    +
    +
    apply_dimension

    Applies a process to all pixels along a given dimension +to produce a new series of values for that dimension. +The back-end will not split your data on that dimension. +For example, when working along the time dimension, +your UDF is guaranteed to receive a full timeseries, +but the data could be chunked spatially. +All dimensions and labels are preserved, +except for the dimension along which apply_dimension is applied: +the number of dimension labels is allowed to change.

    +
    +
    reduce_dimension

    Applies a process to all pixels along a given dimension +to produce a single value, eliminating that dimension. +Like with apply_dimension, the back-end will +not split your data on that dimension. +The dimension along which apply_dimension is applied must be removed +from the output. +For example, when applying reduce_dimension on a spatiotemporal cube +along the time dimension, +the UDF is guaranteed to receive full timeseries +(but the data could be chunked spatially) +and the output cube should only be a spatial cube, without a temporal dimension

    +
    +
    apply_neighborhood

    Applies a process to a neighborhood of pixels +in a sliding-window fashion with (optional) overlap. +Data chunking in this case is explicitly controlled by the user. +Dimensions and number of labels are fully preserved.

    +
    +
    +
    +
    +
    +

    UDF function names and signatures

    +

    The UDF code you pass to the back-end is basically a Python script +that contains one or more functions. +Exactly one of these functions should have a proper UDF signature, +as defined in the openeo.udf.udf_signatures module, +so that the back-end knows what the entrypoint function is +of your UDF implementation.

    +
    +

    Module openeo.udf.udf_signatures

    +

    This module defines a number of function signatures that can be implemented by UDF’s. +Both the name of the function and the argument types are/can be used by the backend to validate if the provided UDF +is compatible with the calling context of the process graph in which it is used.

    +
    +
    +openeo.udf.udf_signatures.apply_datacube(cube, context)[source]
    +

    Map a XarrayDataCube to another XarrayDataCube.

    +

    Depending on the context in which this function is used, the XarrayDataCube dimensions +have to be retained or can be chained. +For instance, in the context of a reducing operation along a dimension, +that dimension will have to be reduced to a single value. +In the context of a 1 to 1 mapping operation, all dimensions have to be retained.

    +
    +
    Parameters:
    +
      +
    • cube (XarrayDataCube) – input data cube

    • +
    • context (dict) – A dictionary containing user context.

    • +
    +
    +
    Return type:
    +

    XarrayDataCube

    +
    +
    Returns:
    +

    output data cube

    +
    +
    +
    + +
    +
    +openeo.udf.udf_signatures.apply_metadata(metadata, context)[source]
    +
    +

    Warning

    +

    This signature is not yet fully standardized and subject to change.

    +
    +

    Returns the expected cube metadata, after applying this UDF, based on input metadata. +The provided metadata represents the whole raster or vector cube. This function does not need to be called for every data chunk.

    +

    When this function is not implemented by the UDF, the backend may still be able to infer correct metadata by running the +UDF, but this can result in reduced performance or errors.

    +

    This function does not need to be provided when using the UDF in combination with processes that by design have a clear +effect on cube metadata, such as reduce_dimension()

    +
    +
    Parameters:
    +
      +
    • metadata (CollectionMetadata) – the collection metadata of the input data cube

    • +
    • context (dict) – A dictionary containing user context.

    • +
    +
    +
    Return type:
    +

    CollectionMetadata

    +
    +
    Returns:
    +

    output metadata: the expected metadata of the cube, after applying the udf

    +
    +
    +
    +

    Examples

    +

    An example for a UDF that is applied on the ‘bands’ dimension, and returns a new set of bands with different labels.

    +
    >>> def apply_metadata(metadata: CollectionMetadata, context: dict) -> CollectionMetadata:
    +...     return metadata.rename_labels(
    +...         dimension="bands",
    +...         target=["computed_band_1", "computed_band_2"]
    +...     )
    +
    +
    +
    +
    + +
    +
    +openeo.udf.udf_signatures.apply_timeseries(series, context)[source]
    +

    Process a timeseries of values, without changing the time instants.

    +

    This can for instance be used for smoothing or gap-filling.

    +
    +
    Parameters:
    +
      +
    • series (Series) – A Pandas Series object with a date-time index.

    • +
    • context (dict) – A dictionary containing user context.

    • +
    +
    +
    Return type:
    +

    Series

    +
    +
    Returns:
    +

    A Pandas Series object with the same datetime index.

    +
    +
    +
    + +
    +
    +openeo.udf.udf_signatures.apply_udf_data(data)[source]
    +

    Generic UDF function that directly manipulates a UdfData object

    +
    +
    Parameters:
    +

    data (UdfData) – UdfData object to manipulate in-place

    +
    +
    +
    + +
    +
    +
    +

    A first example: apply with an UDF to rescale pixel values

    +

    In most of the examples here, we will start from an initial Sentinel2 data cube like this:

    +
    s2_cube = connection.load_collection(
    +    "SENTINEL2_L2A",
    +    spatial_extent={"west": 4.00, "south": 51.04, "east": 4.10, "north": 51.1},
    +    temporal_extent=["2022-03-01", "2022-03-31"],
    +    bands=["B02", "B03", "B04"]
    +)
    +
    +
    +

    The raw values in this initial s2_cube data cube are digital numbers +(integer values ranging from 0 to several thousands) +and to get physical reflectance values (float values, typically in the range between 0 and 0.5), +we have to rescale them. +This is a simple local transformation, without any interaction between pixels, +which is the modus operandi of the apply processes.

    +
    +

    Note

    +

    In practice it will be a lot easier and more efficient to do this kind of rescaling +with pre-defined openEO math processes, for example: s2_cube.apply(lambda x: 0.0001 * x). +This is just a very simple illustration to get started with UDFs.

    +
    +
    +

    UDF script

    +

    The UDF code is this short script (the part that does the actual value rescaling is highlighted):

    +
    +
    udf-code.py
    +
    1from openeo.udf import XarrayDataCube
    +2
    +3def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube:
    +4    array = cube.get_array()
    +5    array.values = 0.0001 * array.values
    +6    return cube
    +
    +
    +
    +

    Some details about this UDF script:

    +
      +
    • line 1: We import XarrayDataCube to use as type annotation of the UDF function.

    • +
    • line 3: We define a function named apply_datacube, +which receives and returns a XarrayDataCube instance. +We follow here the apply_datacube() UDF function signature.

    • +
    • line 4: cube (a XarrayDataCube object) is a thin wrapper +around the data of the chunk we are currently processing. +We use get_array() to get this data, +which is an xarray.DataArray object.

    • +
    • line 5: Because our scaling operation is so simple, we can transform the xarray.DataArray values in-place.

    • +
    • line 6: Consequently, because the values were updated in-place, +we don’t have to build a new XarrayDataCube object +and can just return the (in-place updated) cube object again.

    • +
    +
    +
    +

    Workflow script

    +

    In this first example, we’ll cite a full, standalone openEO workflow script, +including creating the back-end connection, loading the initial data cube and downloading the result. +The UDF-specific part is highlighted.

    +
    +

    Warning

    +

    This implementation depends on openeo.UDF improvements +that were introduced in version 0.13.0 of the openeo Python Client Library. +If you are currently stuck with working with an older version, +check openeo.UDF API and usage changes in version 0.13.0 for more information on the difference with the old API.

    +
    +
    +
    UDF usage example snippet
    +
     1import openeo
    + 2
    + 3# Create connection to openEO back-end
    + 4connection = openeo.connect("...").authenticate_oidc()
    + 5
    + 6# Load initial data cube.
    + 7s2_cube = connection.load_collection(
    + 8    "SENTINEL2_L2A",
    + 9    spatial_extent={"west": 4.00, "south": 51.04, "east": 4.10, "north": 51.1},
    +10    temporal_extent=["2022-03-01", "2022-03-31"],
    +11    bands=["B02", "B03", "B04"]
    +12)
    +13
    +14# Create a UDF object from inline source code.
    +15udf = openeo.UDF("""
    +16from openeo.udf import XarrayDataCube
    +17
    +18def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube:
    +19    array = cube.get_array()
    +20    array.values = 0.0001 * array.values
    +21    return cube
    +22""")
    +23
    +24# Pass UDF object as child process to `apply`.
    +25rescaled = s2_cube.apply(process=udf)
    +26
    +27rescaled.download("apply-udf-scaling.nc")
    +
    +
    +
    +

    In line 15, we build an openeo.UDF object +from an inline string with the UDF source code. +This openeo.UDF object encapsulates various aspects +that are necessary to create a run_udf node in the process graph, +and we can pass it directly in line 25 as the process argument +to DataCube.apply().

    +
    +

    Tip

    +

    Instead of putting your UDF code in an inline string like in the example, +it’s often a good idea to load the UDF code from a separate file, +which is easier to maintain in your preferred editor or IDE. +You can do that directly with the +openeo.UDF.from_file method:

    +
    udf = openeo.UDF.from_file("udf-code.py")
    +
    +
    +
    +

    After downloading the result, we can inspect the band values locally. +Note see that they fall mainly in a range from 0 to 1 (in most cases even below 0.2), +instead of the original digital number range (thousands):

    +_images/apply-rescaled-histogram.png +
    +
    +
    +

    UDF’s that transform cube metadata

    +

    This is a new/experimental feature so may still be subject to change.

    +

    In some cases, a UDF can have impact on the metadata of a cube, but this can not always +be easily inferred by process graph evaluation logic without running the actual +(expensive) UDF code. This limits the possibilities to validate process graphs, +or for instance make an estimate of the size of a datacube after applying a UDF.

    +

    To provide evaluation logic with this information, the user should implement the +apply_metadata() function as part of the UDF. +Please refer to the documentation of that function for more information.

    +
    +
    Example of a UDF that adjusts spatial metadata udf_modify_spatial.py
    +
    import xarray
    +from openeo.udf import XarrayDataCube
    +from openeo.udf.debug import inspect
    +from openeo.metadata import CollectionMetadata
    +import numpy as np
    +
    +def apply_metadata(input_metadata:CollectionMetadata, context:dict) -> CollectionMetadata:
    +
    +    xstep = input_metadata.get('x','step')
    +    ystep = input_metadata.get('y','step')
    +    new_metadata = {
    +          "x": {"type": "spatial", "axis": "x", "step": xstep/2.0, "reference_system": 4326},
    +          "y": {"type": "spatial", "axis": "y", "step": ystep/2.0, "reference_system": 4326},
    +          "t": {"type": "temporal"}
    +    }
    +    return CollectionMetadata(new_metadata)
    +
    +def fancy_upsample_function(array: np.array, factor: int = 2) -> np.array:
    +    assert array.ndim == 3
    +    return array.repeat(factor, axis=-1).repeat(factor, axis=-2)
    +
    +def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube:
    +    array: xarray.DataArray = cube.get_array()
    +
    +    cubearray: xarray.DataArray = cube.get_array().copy() + 60
    +
    +    # We make prediction and transform numpy array back to datacube
    +
    +    # Pixel size of the original image
    +    init_pixel_size_x = cubearray.coords['x'][-1] - cubearray.coords['x'][-2]
    +    init_pixel_size_y = cubearray.coords['y'][-1] - cubearray.coords['y'][-2]
    +
    +    if cubearray.data.ndim == 4 and cubearray.data.shape[0] == 1:
    +        cubearray = cubearray[0]
    +    predicted_array = fancy_upsample_function(cubearray.data, 2)
    +    inspect(predicted_array, "test message")
    +    coord_x = np.linspace(start=cube.get_array().coords['x'].min(), stop=cube.get_array().coords['x'].max() + init_pixel_size_x,
    +                          num=predicted_array.shape[-2], endpoint=False)
    +    coord_y = np.linspace(start=cube.get_array().coords['y'].min(), stop=cube.get_array().coords['y'].max() + init_pixel_size_y,
    +                          num=predicted_array.shape[-1], endpoint=False)
    +    predicted_cube = xarray.DataArray(predicted_array, dims=['bands', 'x', 'y'], coords=dict(x=coord_x, y=coord_y))
    +
    +
    +    return XarrayDataCube(predicted_cube)
    +
    +
    +
    +

    To invoke a UDF like this, the apply_neighborhood method is most suitable:

    +
    udf_code = Path('udf_modify_spatial.py').read_text()
    +cube_updated = cube.apply_neighborhood(
    +    lambda data: data.run_udf(udf=udf_code, runtime='Python-Jep', context=dict()),
    +    size=[
    +        {'dimension': 'x', 'value': 128, 'unit': 'px'},
    +        {'dimension': 'y', 'value': 128, 'unit': 'px'}
    +    ], overlap=[])
    +
    +
    +
    +
    +

    Illustration of data chunking in apply with a UDF

    +

    TODO

    +
    +
    +

    Example: apply_dimension with a UDF

    +

    TODO

    +
    +
    +

    Example: reduce_dimension with a UDF

    +

    The key element for a UDF invoked in the context of reduce_dimension is that it should actually return +an XArray DataArray _without_ the dimension that is specified to be reduced.

    +

    So a reduce over time would receive a DataArray with bands,t,y,x dimensions, and return one with only bands,y,x.

    +
    +
    +

    Example: apply_neighborhood with a UDF

    +

    The apply_neighborhood process is generally used when working with complex AI models that require a +spatiotemporal input stack with a fixed size. It supports the ability to specify overlap, to ensure that the model +has sufficient border information to generate a spatially coherent output across chunks of the raster data cube.

    +

    In the example below, the UDF will receive chunks of 128x128 pixels: 112 is the chunk size, while 2 times 8 pixels of +overlap on each side of the chunk results in 128.

    +

    The time and band dimensions are not specified, which means that all values along these dimensions are passed into +the datacube.

    +
    output_cube = inputs_cube.apply_neighborhood(my_udf, size=[
    +        {'dimension': 'x', 'value': 112, 'unit': 'px'},
    +        {'dimension': 'y', 'value': 112, 'unit': 'px'}
    +    ], overlap=[
    +        {'dimension': 'x', 'value': 8, 'unit': 'px'},
    +        {'dimension': 'y', 'value': 8, 'unit': 'px'}
    +    ])
    +
    +
    +
    +
    +

    Example: Smoothing timeseries with a user defined function (UDF)

    +

    In this example, we start from the evi_cube that was created in the previous example, and want to +apply a temporal smoothing on it. More specifically, we want to use the “Savitzky Golay” smoother +that is available in the SciPy Python library.

    +

    To ensure that openEO understand your function, it needs to follow some rules, the UDF specification. +This is an example that follows those rules:

    +
    +
    Example UDF code smooth_savitzky_golay.py
    +
    import xarray
    +from scipy.signal import savgol_filter
    +
    +from openeo.udf import XarrayDataCube
    +
    +
    +def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube:
    +    """
    +    Apply Savitzky-Golay smoothing to a timeseries datacube.
    +    This UDF preserves dimensionality, and assumes an input
    +    datacube with a temporal dimension 't' as input.
    +    """
    +    array: xarray.DataArray = cube.get_array()
    +    filled = array.interpolate_na(dim='t')
    +    smoothed_array = savgol_filter(filled.values, 5, 2, axis=0)
    +    return XarrayDataCube(
    +        array=xarray.DataArray(smoothed_array, dims=array.dims, coords=array.coords)
    +    )
    +
    +
    +
    +

    The method signature of the UDF is very important, because the back-end will use it to detect +the type of UDF. +This particular example accepts a DataCube object as input and also returns a DataCube object. +The type annotations and method name are actually used to detect how to invoke the UDF, so make sure they remain unchanged.

    +

    Once the UDF is defined in a separate file, we load it +and apply it along a dimension:

    +
    smoothing_udf = openeo.UDF.from_file('smooth_savitzky_golay.py')
    +smoothed_evi = evi_cube_masked.apply_dimension(smoothing_udf, dimension="t")
    +
    +
    +
    +
    +

    Downloading a datacube and executing an UDF locally

    +

    Sometimes it is advantageous to run a UDF on the client machine (for example when developing/testing that UDF). +This is possible by using the convenience function openeo.udf.run_code.execute_local_udf(). +The steps to run a UDF (like the code from smooth_savitzky_golay.py above) are as follows:

    + +

    For example:

    +
    from pathlib import Path
    +from openeo.udf import execute_local_udf
    +
    +my_process = connection.load_collection(...
    +
    +my_process.download('test_input.nc', format='NetCDF')
    +
    +smoothing_udf = Path('smooth_savitzky_golay.py').read_text()
    +execute_local_udf(smoothing_udf, 'test_input.nc', fmt='netcdf')
    +
    +
    +

    Note: this algorithm’s primary purpose is to aid client side development of UDFs using small datasets. It is not designed for large jobs.

    +
    +
    +

    UDF dependency management

    +

    Most UDF’s have dependencies, because they often are used to run complex algorithms. Typical dependencies like numpy and +XArray can be assumed to be available, but others may be more specific for you.

    +

    This part is probably the least standardized in the definition of UDF’s, and may be backend specific. +We include some general pointers here:

    +
      +
    • Python dependencies can be packaged fairly easily by zipping a Python virtual environment.

    • +
    • For some dependencies, it can be important that the Python major version of the virtual environment is the same as the one used by the backend.

    • +
    • Python allows you to dynamically append (or prepend) libraries to the search path: sys.path.append(“unzipped_virtualenv_location”)

    • +
    +
    +
    +

    Profile a process server-side

    +
    +

    Warning

    +

    Experimental feature - This feature only works on back-ends running the Geotrellis implementation, and has not yet been +adopted in the openEO API.

    +
    +

    Sometimes users want to ‘profile’ their UDF on the back-end. While it’s recommended to first profile it offline, in the +same manner as you can debug UDF’s, back-ends may support profiling directly. +Note that this will only generate statistics over the python part of the execution, therefore it is only suitable for profiling UDFs.

    +
    +

    Usage

    +

    Only batch jobs are supported! In order to turn on profiling, set ‘profile’ to ‘true’ in job options:

    +
    job_options={'profile':'true'}
    +... # prepare the process
    +process.execute_batch('result.tif',job_options=job_options)
    +
    +
    +

    When the process has finished, it will also download a file called ‘profile_dumps.tar.gz’:

    +
      +
    • rdd_-1.pstats is the profile data of the python driver,

    • +
    • the rest are the profiling results of the individual rdd id-s (that can be correlated with the execution using the SPARK UI).

    • +
    +
    +
    +

    Viewing profiling information

    +

    The simplest way is to visualize the results with a graphical visualization tool called kcachegrind. +In order to do that, install kcachegrind packages (most linux distributions have it installed by default) and it’s python connector pyprof2calltree. +From command line run:

    +
    pyprof2calltree rdd_<INTERESTING_RDD_ID>.pstats.
    +
    +
    +

    Another way is to use the builtin pstats functionality from within python:

    +
    import pstats
    +p = pstats.Stats('restats')
    +p.print_stats()
    +
    +
    +
    +
    +

    Example

    +

    An example code can be found here .

    +
    +
    +
    +

    Logging from a UDF

    +

    In some cases, you may want to log information from your user defined function, +for instance to provide debug information or to log warnings. You can use the inspect +logging function to achieve this.

    +

    For example, in the previous example of rescaling an RGB image(from SENTINEL2_L2A), suppose you +want to keep a log of array shape encountered within a UDF:

    +
    # Create a UDF object from inline source code.
    +udf = openeo.UDF("""
    +from openeo.udf import XarrayDataCube
    +from openeo.udf.debug import inspect
    +
    +def apply_datacube(cube: XarrayDataCube, context: dict) -> XarrayDataCube:
    +    array = cube.get_array()
    +    inspect(data=[array.shape], message="UDF logging shape of my array")
    +    array.values = 0.0001 * array.values
    +    return cube
    +""")
    +
    +
    +

    If you are using Jupyter Notebook, you can see the log entries using logs +as shown in the image:

    +_images/logging_arrayshape.png +

    Please note that this nice rendering only happens in Jupyter Notebook, while in plain Python you will get a dict.

    +

    Thus, an array of shape 3x256x256 was logged in on which rescaling was performed. [Please note that at this moment, +this method is experimental and does not support all data types in data argument of inspect]

    +
    +
    +

    openeo.UDF API and usage changes in version 0.13.0

    +

    Prior to version 0.13.0 of the openEO Python Client Library, +loading and working with UDFs was a bit inconsistent and cumbersome.

    +
      +
    • The old openeo.UDF() required an explicit runtime argument, which was usually "Python". +In the new openeo.UDF, the runtime argument is optional, +and it will be auto-detected (from the source code or file extension) when not given.

    • +
    • The old openeo.UDF() required an explicit data argument, and figuring out the correct +value (e.g. something like {"from_parameter": "x"}) required good knowledge of the openEO API and processes. +With the new openeo.UDF it is not necessary anymore to provide +the data argument. In fact, while the data argument is only still there for compatibility reasons, +it is unused and it will be removed in a future version. +A deprecation warning will be triggered when data is given a value.

    • +
    • DataCube.apply_dimension() has direct UDF support through +code and runtime arguments, preceding the more generic and standard process argument, while +comparable methods like DataCube.apply() +or DataCube.reduce_dimension() +only support a process argument with no dedicated arguments for UDFs.

      +

      The goal is to improve uniformity across all these methods and use a generic process argument everywhere +(that also supports a openeo.UDF object for UDF use cases). +For now, the code, runtime and version arguments are still present +in DataCube.apply_dimension() +as before, but usage is deprecated.

      +

      Simple example to sum it up:

      +
      udf_code = """
      +...
      +def apply_datacube(cube, ...
      +"""
      +
      +# Legacy `apply_dimension` usage: still works for now,
      +# but it will trigger a deprecation warning.
      +cube.apply_dimension(code=udf_code, runtime="Python", dimension="t")
      +
      +# New, preferred approach with a standard `process` argument.
      +udf = openeo.UDF(udf_code)
      +cube.apply_dimension(process=udf, dimension="t")
      +
      +# Unchanged: usage of other apply/reduce/... methods
      +cube.apply(process=udf)
      +cube.reduce_dimension(reducer=udf, dimension="t")
      +
      +
      +
    • +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/udp.html b/udp.html new file mode 100644 index 000000000..1fe5e65a3 --- /dev/null +++ b/udp.html @@ -0,0 +1,595 @@ + + + + + + + + User-Defined Processes — openEO Python Client 0.26.0a1 documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    User-Defined Processes

    +
    +

    Code reuse with user-defined processes

    +

    As explained before, processes can be chained together in a process graph +to build a certain algorithm. +Often, you have certain (sub)chains that reoccur in the same process graph +of even in different process graphs or algorithms.

    +

    The openEO API enables you to store such (sub)chains +on the back-end as a so called user-defined process. +This allows you to build your own library of reusable building blocks.

    +
    +

    Warning

    +

    Do not confuse user-defined processes (sometimes abbreviated as UDP) with +user-defined functions (UDF) in openEO, which is a mechanism to +inject Python or R scripts as process nodes in a process graph. +See User-Defined Functions (UDF) explained for more information.

    +
    +

    A user-defined process can not only be constructed from +pre-defined processes provided by the back-end, +but also other user-defined processes.

    +

    Ultimately, the openEO API allows you to publicly expose your user-defined process, +so that other users can invoke it as a service. +This turns your openEO process into a web application +that can be executed using the regular openEO +support for synchronous and asynchronous jobs.

    +
    +
    +

    Process Parameters

    +

    User-defined processes are usually parameterized, +meaning certain inputs are expected when calling the process.

    +

    For example, if you often have to convert Fahrenheit to Celsius:

    +
    c = (f - 32) / 1.8
    +
    +
    +

    you could define a user-defined process fahrenheit_to_celsius, +consisting of two simple mathematical operations +(pre-defined processes subtract and divide).

    +

    We can represent this in openEO’s JSON based format as follows +(don’t worry too much about the syntax details of this representation, +the openEO Python client will hide this usually):

    +
    {
    +    "subtract32": {
    +        "process_id": "subtract",
    +        "arguments": {"x": {"from_parameter": "fahrenheit"}, "y": 32}
    +    },
    +    "divide18": {
    +        "process_id": "divide",
    +        "arguments": {"x": {"from_node": "subtract32"}, "y": 1.8},
    +        "result": true
    +    }
    +}
    +
    +
    +

    The important point here is the parameter reference {"from_parameter": "fahrenheit"} in the subtraction. +When we call this user-defined process we will have to provide a Fahrenheit value. +For example with 70 degrees Fahrenheit (again in openEO JSON format here):

    +
    {
    +    "process_id": "fahrenheit_to_celsius",
    +    "arguments" {"fahrenheit": 70}
    +}
    +
    +
    +
    +

    Declaring Parameters

    +

    It’s good style to declare what parameters your user-defined process expects and supports. +It allows you to document your parameters, define the data type(s) you expect +(the “schema” in openEO-speak) and define default values.

    +

    The openEO Python client lets you define parameters as +Parameter instances. +In general you have to specify at least the parameter name, +a description and a schema (to declare the expected parameter type). +The “fahrenheit” parameter from the example above can be defined like this:

    +
    from openeo.api.process import Parameter
    +
    +fahrenheit_param = Parameter(
    +    name="fahrenheit",
    +    description="Degrees Fahrenheit",
    +    schema={"type": "number"}
    +)
    +
    +
    +

    To simplify working with parameter schemas, the Parameter class +provides a couple of helpers to create common types of parameters. +In the example above, the “fahrenheit” parameter (a number) can also be created more compactly +with the Parameter.number() helper:

    +
    fahrenheit_param = Parameter.number(
    +    name="fahrenheit", description="Degrees Fahrenheit"
    +)
    +
    +
    +

    Some useful parameter helpers (class methods of the Parameter class):

    + +

    Consult the documentation of these helper class methods for additional features. +For example, declaring a default value for an integer parameter:

    +
    size_param = Parameter.integer(
    +    name="size", description="Kernel size", default=4
    +)
    +
    +
    +
    +
    +

    More advanced parameter schemas

    +

    While the helper class methods of Parameter (discussed above) +cover the most common parameter usage, +you also might need to declare some parameters with a more special or specific schema. +You can do that through the schema argument +of the basic Parameter() constructor. +This “schema” argument follows the JSON Schema draft-07 specification, +which we will briefly illustrate here.

    +

    Basic primitives can be declared through a (required) “type” field, for example: +{"type": "string"} for strings, {"type": "integer"} for integers, etc.

    +

    Likewise, arrays can be defined with a minimal {"type": "array"}. +In addition, the expected type of the array items can also be specified, +e.g. an array of integers:

    +
    {
    +    "type": "array",
    +    "items": {"type": "integer"}
    +}
    +
    +
    +

    Another, more complex type is {"type": "object"} for parameters +that are like Python dictionaries (or mappings). +For example, to define a bounding box parameter +that should contain certain fields with certain type:

    +
    {
    +    "type": "object",
    +    "properties": {
    +        "west": {"type": "number"},
    +        "south": {"type": "number"},
    +        "east": {"type": "number"},
    +        "north": {"type": "number"},
    +        "crs": {"type": "string"}
    +    }
    +}
    +
    +
    +

    Check the documentation and examples of JSON Schema draft-07 +for even more features.

    +

    On top of these generic types, the openEO API also defines a couple of custom (sub)types +in the openeo-processes project +(see the meta/subtype-schemas.json listing). +For example, the schema of an openEO data cube is:

    +
    {
    +    "type": "object",
    +    "subtype": "datacube"
    +}
    +
    +
    +
    +
    +
    +

    Building and storing user-defined process

    +

    There are a couple of ways to build and store user-defined processes:

    + +
    +

    Through “process functions”

    +

    The openEO Python Client Library defines the +official processes in the openeo.processes module, +which can be used to build a process graph as follows:

    +
    from openeo.processes import subtract, divide
    +from openeo.api.process import Parameter
    +
    +# Define the input parameter.
    +f = Parameter.number("f", description="Degrees Fahrenheit.")
    +
    +# Do the calculations, using the parameter and other values
    +fahrenheit_to_celsius = divide(x=subtract(x=f, y=32), y=1.8)
    +
    +# Store user-defined process in openEO back-end.
    +connection.save_user_defined_process(
    +    "fahrenheit_to_celsius",
    +    fahrenheit_to_celsius,
    +    parameters=[f]
    +)
    +
    +
    +

    The fahrenheit_to_celsius object encapsulates the subtract and divide calculations in a symbolic way. +We can pass it directly to save_user_defined_process().

    +

    If you want to inspect its openEO-style process graph representation, +use the to_json() +or print_json() method:

    +
    >>> fahrenheit_to_celsius.print_json()
    +{
    +  "process_graph": {
    +    "subtract1": {
    +      "process_id": "subtract",
    +      "arguments": {
    +        "x": {
    +          "from_parameter": "f"
    +        },
    +        "y": 32
    +      }
    +    },
    +    "divide1": {
    +      "process_id": "divide",
    +      "arguments": {
    +        "x": {
    +          "from_node": "subtract1"
    +        },
    +        "y": 1.8
    +      },
    +      "result": true
    +    }
    +  }
    +}
    +
    +
    +
    +
    +

    From a parameterized data cube

    +

    It’s also possible to work with a DataCube directly +and parameterize it. +Let’s create, as a simple but functional example, a custom load_collection +with hardcoded collection id and band name +and a parameterized spatial extent (with default):

    +
    spatial_extent = Parameter(
    +    name="bbox",
    +    schema="object",
    +    default={"west": 3.7, "south": 51.03, "east": 3.75, "north": 51.05}
    +)
    +
    +cube = connection.load_collection(
    +    "SENTINEL2_L2A_SENTINELHUB",
    +    spatial_extent=spatial_extent,
    +    bands=["B04"]
    +)
    +
    +
    +

    Note how we just can pass Parameter objects as arguments +while building a DataCube.

    +
    +

    Note

    +

    Not all DataCube methods/processes properly support +Parameter arguments. +Please submit a bug report when you encounter missing or wrong parameterization support.

    +
    +

    We can now store this as a user-defined process called “fancy_load_collection” on the back-end:

    +
    connection.save_user_defined_process(
    +    "fancy_load_collection",
    +    cube,
    +    parameters=[spatial_extent]
    +)
    +
    +
    +

    If you want to inspect its openEO-style process graph representation, +use the to_json() +or print_json() method:

    +
    >>> cube.print_json()
    +{
    +  "loadcollection1": {
    +    "process_id": "load_collection",
    +    "arguments": {
    +      "id": "SENTINEL2_L2A_SENTINELHUB",
    +      "bands": [
    +        "B04"
    +      ],
    +      "spatial_extent": {
    +        "from_parameter": "bbox"
    +      },
    +      "temporal_extent": null
    +    },
    +    "result": true
    +  }
    +}
    +
    +
    +
    +
    +

    Using a predefined dictionary

    +

    In some (advanced) situation, you might already have +the process graph in dictionary format +(or JSON format, which is very close and easy to transform). +Another developer already prepared it for you, +or you prefer to fine-tune process graphs in a JSON editor. +It is very straightforward to submit this as a user-defined process.

    +

    Say we start from the following Python dictionary, +representing the Fahrenheit to Celsius conversion we discussed before:

    +
    fahrenheit_to_celsius = {
    +    "subtract1": {
    +        "process_id": "subtract",
    +        "arguments": {"x": {"from_parameter": "f"}, "y": 32}
    +    },
    +    "divide1": {
    +        "process_id": "divide",
    +        "arguments": {"x": {"from_node": "subtract1"}, "y": 1.8},
    +        "result": True
    +    }}
    +
    +
    +

    We can store this directly, taking into account that we have to define +a parameter named f corresponding with the {"from_parameter": "f"} argument +from the dictionary above:

    +
    connection.save_user_defined_process(
    +    user_defined_process_id="fahrenheit_to_celsius",
    +    process_graph=fahrenheit_to_celsius,
    +    parameters=[Parameter.number(name="f", description="Degrees Fahrenheit")]
    +)
    +
    +
    +
    +
    +

    Store to a file

    +

    Some use cases might require storing the user-defined process in, +for example, a JSON file instead of storing it directly on a back-end. +Use build_process_dict() to build a dictionary +compatible with the “process graph with metadata” format of the openEO API +and dump it in JSON format to a file:

    +
    import json
    +from openeo.rest.udp import build_process_dict
    +from openeo.processes import subtract, divide
    +from openeo.api.process import Parameter
    +
    +fahrenheit = Parameter.number("f", description="Degrees Fahrenheit.")
    +fahrenheit_to_celsius = divide(x=subtract(x=fahrenheit, y=32), y=1.8)
    +
    +spec = build_process_dict(
    +    process_id="fahrenheit_to_celsius",
    +    process_graph=fahrenheit_to_celsius,
    +    parameters=[fahrenheit]
    +)
    +
    +with open("fahrenheit_to_celsius.json", "w") as f:
    +    json.dump(spec, f, indent=2)
    +
    +
    +

    This results in a JSON file like this:

    +
    {
    +  "id": "fahrenheit_to_celsius",
    +  "process_graph": {
    +    "subtract1": {
    +      "process_id": "subtract",
    +       ...
    +  "parameters": [
    +    {
    +      "name": "f",
    +      ...
    +
    +
    +
    +
    +
    +

    Evaluate user-defined processes

    +

    Let’s evaluate the user-defined processes we defined.

    +

    Because there is no pre-defined +wrapper function for our user-defined process, we use the +generic openeo.processes.process() function to build a simple +process graph that calls our fahrenheit_to_celsius process:

    +
    >>> pg = openeo.processes.process("fahrenheit_to_celsius", f=70)
    +>>> pg.print_json(indent=None)
    +{"process_graph": {"fahrenheittocelsius1": {"process_id": "fahrenheit_to_celsius", "arguments": {"f": 70}, "result": true}}}
    +
    +>>> res = connection.execute(pg)
    +>>> print(res)
    +21.11111111111111
    +
    +
    +

    To use our custom fancy_load_collection process, +we only have to specify a temporal extent, +and let the predefined and default values do their work. +We will use datacube_from_process() +to construct a DataCube object +which we can process further and download:

    +
    cube = connection.datacube_from_process("fancy_load_collection")
    +cube = cube.filter_temporal("2020-09-01", "2020-09-10")
    +cube.download("fancy.tiff", format="GTiff")
    +
    +
    +

    See Construct DataCube from process for more information on datacube_from_process().

    +
    +
    +

    UDP Example: EVI timeseries

    +

    In this UDP example, we’ll build a reusable UDP evi_timeseries +to calculate the EVI timeseries for a given geometry. +It’s a simplified version of the EVI workflow laid out in Example use case: EVI map and timeseries, +focussing on the UDP-specific aspects: defining and using parameters; +building, storing, and finally executing the UDP.

    +
    import openeo
    +from openeo.api.process import Parameter
    +
    +# Create connection to openEO back-end
    +connection = openeo.connect("...").authenticate_oidc()
    +
    +# Declare the UDP parameters
    +temporal_extent = Parameter(
    +    name="temporal_extent",
    +    description="The date range to calculate the EVI for.",
    +    schema={"type": "array", "subtype": "temporal-interval"},
    +    default =["2018-06-15", "2018-06-27"]
    +)
    +geometry = Parameter(
    +    name="geometry",
    +    description="The geometry (a single (multi)polygon or a feature collection of (multi)polygons) of to calculate the EVI for.",
    +    schema={"type": "object", "subtype": "geojson"}
    +)
    +
    +# Load raw SENTINEL2_L2A data
    +sentinel2_cube = connection.load_collection(
    +    "SENTINEL2_L2A",
    +    temporal_extent=temporal_extent,
    +    bands=["B02", "B04", "B08"],
    +)
    +
    +# Extract spectral bands and calculate EVI with the "band math" feature
    +blue = sentinel2_cube.band("B02") * 0.0001
    +red = sentinel2_cube.band("B04") * 0.0001
    +nir = sentinel2_cube.band("B08") * 0.0001
    +evi = 2.5 * (nir - red) / (nir + 6.0 * red - 7.5 * blue + 1.0)
    +
    +evi_aggregation = evi.aggregate_spatial(
    +    geometries=geometry,
    +    reducer="mean",
    +)
    +
    +# Store the parameterized user-defined process at openEO back-end.
    +process_id = "evi_timeseries"
    +connection.save_user_defined_process(
    +    user_defined_process_id=process_id,
    +    process_graph=evi_aggregation,
    +    parameters=[temporal_interval, geometry],
    +)
    +
    +
    +

    When this UDP evi_timeseries is successfully stored on the back-end, +we can use it through datacube_from_process() +to get the EVI timeseries of a desired geometry and time window:

    +
    time_window = ["2020-01-01", "2021-12-31"]
    +geometry = {
    +    "type": "Polygon",
    +    "coordinates": [[[5.1793, 51.2498], [5.1787, 51.2467], [5.1852, 51.2450], [5.1867, 51.2453], [5.1873, 51.2491], [5.1793, 51.2498]]],
    +  }
    +
    +evi_timeseries = connection.datacube_from_process(
    +    process_id="evi_timeseries",
    +    temporal_extent=time_window,
    +    geometry=geometry,
    +)
    +
    +evi_timeseries.download("evi-aggregation.json")
    +
    +
    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file

    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%0Aj%N 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 Uu~j}f@Ev68D%#4G&t8A}FVHY)fdBvi literal 0 HcmV?d00001 diff --git a/_static/images/batchjobs-webeditor-listing.png b/_static/images/batchjobs-webeditor-listing.png new file mode 100644 index 0000000000000000000000000000000000000000..4462f6d4206415cb09418e560ddc38f3ea2f45fd GIT binary patch literal 63115 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 literal 0 HcmV?d00001 diff --git a/_static/images/local/local_ndvi.jpg b/_static/images/local/local_ndvi.jpg new file mode 100644 index 0000000000000000000000000000000000000000..75c523dccbed143016ff1c8fc33c41b9f6cbd107 GIT binary patch literal 96185 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�fF zgI}gacjRlA`f4Hx5fwnP3XobX5P_nvM7^q?x%$kAe@Ii|JYKZolnb&=-98?Rv~A5$ zziq~yb58<#1FnJXt$xPK2r1O(ujc;nF7Bz;PWlTU}|j77_F}4w}ve9^}nviD4a@q!kZ|Cy1eHL zn#y5@|3#4+ZS8drjRY|}cCo+(V)%i@mcSe=1vj_@QrYw#s&7PEK2uX%pNUru{{9FP z0lE1^&4>}i-hBZ0b4I`ymiv&4(%I6A?q=xXK}K0cl0s32^Pl`gT2X;+gt^}vjX%M} z!)nfWx1y*{ASUd7+s(uSCqS%2RM6ZUen)>+5$@=UC&uU z?Nh1Q_$wp#zUC+_d!n&^!ih^iH#L=OEd`cRLb*ij0#+K$(%(<5?N<}Vo*|fR5nsMB zWP2o;WEh|_42wXY%qE`o)CsQjFroUpgSt}SzoVmFA0sZzjRgAJ*eHVS8!2_4vl{6( zBxsJ;2JD8}(|5mJ&g}brl!KXTbn#a$7GCHPJKzsf<%@5l^ca#Dl698V8t~1isuVkQ z*cYut^rps;)BfsUUn?i$(utGYp(_4!HQg&bNl$O1tyDd?w7e7NbmTAz z0{??n6(f1g@f)hT-JI@Pjg!RqV@oj&v-%aXEx(R5;%@jLcNJ~N? zI?{xiXe^+-;+Oe_kl7vw#$HqLjVbiVNT(t&XHo6xE28N=e@&8@Y47(6!eVui0Xxo(1>0IjT^S%WucZJ< z8BEVYQd=O+Q1*1zaTdj9tbXR5VwINTrJRCWZ>fj*98Lu9%d^XqQ(M+{{)IG%7wjv< zW0{x-bBN~R$Vd?6nAy`n)yHY=UBCo+}q1@(3nD#VMnGV~8PLmH%Xu9l>DQM=^N1NcdXH5gaNPM(Cri7TYU{-F7mOF-~4wd z)x5dTIuBCmKPWQjs&o*TxcxgQr|z6bEQBw_@6Pq&>kYM!#}g@6BF`np=%03 zRHz|tN}Hu5ySo9kmdUpzU{sjLU|ssg4)1((;CPDsL1At2wD?=L_med~;_-cO%O>KP(F;V4SwljqGT>ON;st!vn z9S(eVq*umgnI^B)g@@8zkYmL+T;%n}mjFvmgM4aBAv`zUoP}rOwYon+w{_E5SLA0j zl8tTQX7er07E`mD6-;c#=-KN#R4AUyVfBaZ4vo!NQPXhRg$hL>^)=+AIn zv|YSQ4`Y+zb>|TnzQN$ZajmgIiBe`N%lZ}AT6W22P`bqHPT3L1Y@5ZD`{Z2`R^*Q zF-OLl>G}mV|5lTU)mRL~IHqi^@t5ZSN!H>V_-)+mobJ4Q1E1WmoAW6t%$&FSVzZV2 z1Kz9n3(t&M@ofy3tCOD73XNjJ$0Av`n(O7&ZosBW+}6_k#Zo*A*_`7WsyYM6G7We& zwcj&PG5j?2ZvI+n*f--n$uM<$0yv%;o1?^)+%a!siWLjka+DwyeE`KOj*x=ynhgLraVJbJ0C;<3P<@ZiB%B2xsxI%jj|%%Viq zI_-g&p;*Wl!zZ?{*V^oKI{yZ4ms4ghos@H4ivGMU8?BIjv|3uHxsDMxY?7ky9GIlv z&*QHsWmyd_D5U5gXMXeHz7ev?^73_$+sg}d(Giq8GMgh*hOpWXvQl-m+;G3l)(lbG zb!#M&VmhRItCK|z9g-dC$R6Hjt3Xz$b|d&hwz1*PxHj{7>ay$>iT#dnf4g_zm)B~I zHC52nC!b?TqjK*p!Dc`d+V~JL(thgvUh5q^sxwRcC;i_G&WDq#P$Sy@Q=WNJPX(%z z{tpj@v-kg?)%0vFde)f+Tft5CyJ>=0*TBZe=rUyJg~a<@odjVO%GJnMc;97H42(9Y ztL6Trf1ow!(rNv{?>8kBD9NO|Vb1ev%8YQVe1|nRSnB|FRFvJ2mgX@`(=j{NYe3>F zEGUB}4f$*|)5py{o_97=G|s4`^rp^2`A)*}Xnm3nHK)~)@3CQB?{z|C`a53rbM$## zKP#n~d03)QdB4P3DtZ$l$0OznN3?U3D6B;1w}7auf=sDT14XIpYtM$BYPEM1-0dL; zjxwkfD(R%d=q;|gK3eavbTZ{H6S$U7r@^P2Irwpn$ww6{4E8+qRFi!5Qr`O$;G76Y%hFj-DQQnA1hYXJi%R!1rw*nCVr?Sr8_`{u{LX? zp`wkkY)zUsmda|KcqR*50;i@_k}>hfOB-g^IpDf7FyU$7E}Yxp5r@-EwNqps@y;cY z)wA;D4_3!DRtd)*4y2ac`tY%)pdx?MnQxrPL`wpvoy3lWEG`bpxn_pu{tfv^RKS~W zeEzPk=>?4tg#$8+vx?R7T?~&b+c+&&@8Z?fe!5w{7cCl&c4Ql zqSjPX*LymxG0hi4+kfopG?b{*VP$(q7re{6tWCB%yzF&4yp@xsoqa75)0!p?lnN#H zIRz?v-Ih9 zdGEA&7KXB1hv8RC@iB;?p=*GH`~ftj%Kf-i!G{WfmF5Lsr$c=~JHUvYX6mn`om}8l z&DKG`^f}|7jM>8(-q^yG&fS@iHZ|>JWwhrjY9B*#WL3+dPnxg-K6+}2)(?RJP*WT> z&tLerqy|n|$-}6lV0$;JWk1TnCDZ*Xj~jzubNi`O7sIDsG36>@y9XRKm^d;<(t*{* z72DJTu*oKuNT`#%pS%w$#iqsUYp9A|(t2%2YsMds`Q+-QYcEO*c%fL3`J(TT!4z@w z3iC4|69pz)2sRajlJyx+J~9%%p+5UDFJ1#t)YKeQ(R8%VBfu|_i+MIuSWwzS$FL?@ z>T7yF?+E&YFO}3&J1_({y6{iVMX@l%U_AQb6K|UH?uzay0LUj ziH|+Hm*o7eC?<@~?m$U2A?R%L(l68_3rY?3+`L%VSwKQ9_sk36IblMcDLQ<)65Q?k z(|+h{zV=tGqZFHBjDPE8IomM3cqg9b-5I4H1P2c0mjzHI`TX z0d*%f=TH1t5ABJT%qad374Lfp^tm zlTV%l8NPq0Kk3)t?PgT^Mxn zeP%{F99Zg!MkUao<@3=Y`MqDrnz*uDfwA8aa^+;tFJ=!*alqBTSW-eSt_wPA5C$xsbAZOz zhZkfZ$=u*V&5;npHKB}ge?ZsGv8o|CZ8vQeFvwOip?;8D*yVi#8muX4wvU@wL%FF* z_(<#@fB|ez^wPCZ8N7#fswu8ArdEo@4L9iZrD@Cu(;B68zm#L3XD~0kDd)@jB}QLc zBzc>Bfl>++fDLmEXM-a{A6IOi!VtyXrF!|j#dh6a-I?>R-@sg0(Ry$1X!hcT^?8|b zzD+zGl_7|94?1F$N%->2VO8ZjppvaDq2Xplr5^_2EhQ#3IoQt~R0ZPx1Qvn_W@&5#< z$hw%lvnjFdW6)Kt@6??;Z&oZSIN#q8bZ0Q2W851&cmxSq8nw^8;?*_dZM%or5|&!E z8Q8OZ)hzh?Y?~UT8Ypg5LICV2k-JCPCp=WEU~B1`s=_PTjiWFfoeA|pm!#e6joR;o zTmuFE2^R)^;E;I72q--60-nLS3&diQ{l?H2;F49e%E*dLudj1+olZBcubx#d z{Ma8WR>Z8k63)Q(w5i1c^`Ngs;VoC`KO>o65#oWPJ99RLHF{Ey4}+Zv_G zPRrI$dZz>$cxU_k+(WrRW*KZK#cgui4yyQb6&WsN9&I|a*T?gryQzKQitO&q&6mm^ z8d@C~X?#b!enuJRYhNqwNt1K!7Rq>Dt4scjbek%^jpSVwnG2hn{F~y`yz}32fPY^r zo50IU$tS8P7NDI5kYg&CV#T%o3(zkIGjhU$0e7C}Zz_VRI#zHzf7J(|GqgNn;>^FM zd;kRWe{HdGj}K_}4F4g&L~WEhU{%xjAKrslSK+nON$L`zDhB)(0LBe*5y&(d)U(q; z#(aJgMgtTe3nx;JVqJut&f__3&S#7MXXfoAC6*aLv!8Dxui+lCwTjg1ZcWiKwPCcw zn|XRA3!3@vQc`J$4l}(sI)kfp-r7d`L!=)`T4jL_;4?;424S26p#qO3N{)1yLX9xA z3PT0@=vH`tTu`g|{M1i-O`$qV)5yLVA74Qby@2H;Yv(qA@_vn6iauqJe2&YF_duf< zwz6QzFK%^r7`VOU_j5J#T%5*^ zLiBtpMShK}bTR`}&rjbviWNbrNoQowTF4uHKh>lEfod+*11uNXX#?k;wK9+$9N`i zNl-tRJ^H4ZdAUqF#&R%Acu8b(Ajy?x%C!u^OWf8WK3&eS?aIAAQSKi`r%{t(JRwzq z7yx{GAt|Axg)}o}SlXIA0%y$lHV9R{mx|9+wPQyww%*VHjG9}<`}r*vwN6{1tJbwQ zHrL(K-aoZUNYJ^cBYS2i?Z5V^5E})%RL&NDMq&ba{)c(cStYLmakH`r*V(`Xa^s10*!NTRWuu+urx@`0 z1>{i>JKVjay#G#;Xn&fzwb32j5`aJPOEd-4vuD(eIQzR`GQi8mWmL8t{OEAGwIyqN zFv)uA&fEkmvr;hU2T*Grx$7lP>?)tP8C;Om2P;h7e4Ow8^3j~?CZETLck(7lFF&UK zJf{}ovRLC%U!8t%aJuk79?xpoJ{zq>z`l<=N(MnaIx^J7Ba9{rP#zKwIm(8};&t1u zgRFYL+N)oCFQhQ=!5j?S$q-7C50!3n+SDEztug6uwRi3Pr2_BoH|;}z81WE{S3V{L zV2!-aNm@2bauv#w`1H^@jyu&>L&XoK(-lm62@Pg3U3J^HYr@U-j9;(|1gQE89A(wN z1u6jtTR%5z<|Omz{;~Vk0R=jv=weU_Xq__J8`&HUBw;7x8rg>&ml zavM!;g+5rP2Dkk$jhV)!4E0Zi8t7aeH()O+(t$3be;crcacz0nHmue+glqD=*NwF1 zc%eb}4k{3?*d1UpJMwaB;Q0qTr~JlUNKHm3g%N_wsw?)ciJ$AqTJsU+()Ik5VDRGE z0-$G1t0%Jf`Www+^U_RyXApv;O&FSr`PwWyon`rY_7>(sg2;qV1z_9-V)7pIq}u)1 z6IMxA5U6rm#sds2{=fdk&WZ2pjDBz!=2leV=N-D67Ovif&lwImH5u-GWHQ;K6ZKYG z!iLyT2WOQ-C2Gcw;GL0eag3vtBT@8h2gYf-_HT z)~{ThCMV?M4a<=Fzh_|VM~#^zW7sc0C`8jsP(OvGVypPt@v(fu17U*K;SDcR!tIh+ z&AB|5EmpjjZ!a(0m_2C!PCCkO<@MPk@h&XrWji)u+C=mX&^{~3 zU|bwqpJKZKdEC$#^QeDJ@2XRrX4Sjzw|dxJrTOj+SX@(QZ)NkX9UXG<=00o9w3Fhq zmzs3%ajwk73qP&rR{FmA^LCFin6*hI&Dwm)20BHI? zk-4-@c&*l?D#EElsYii3!}=!GQEA{(5AW-%WuDIj!k6Dc*9(6-h*4T(!JJSSue9sh z_;00$kDk{vr-d7HNMAbVl;OJ!+AweQ*5wypobN7xrfi1F1VghtLEYEBK2oxeQ@eBNCXiujlKZv4C%jf_+K`!dSC35P6;*8CeZjqWwbm;7eM%?JWx<{Nc@aYI*lXexu(98Ae--7*2(R>=j66_fz%*=j{ z_x-`e6hEkt=dLUy+?V_ck4Q$UnTBM`*W=I5-WN>N5Od@1p%dhA`oNRmr(!9A*I(A} z#TRO(=npwy4o5r&B38cyvBz_2)xA{>G0Cw}`bWmg>Aqo*w$+P{7i*Ra0O8m$$E-1Z zdi+3Xp9%Wdgp$*C#&+x7qWideo%})V6oI?2t}gYZXU00WsbX6F$x~@PyVop(MsW@k zi`H9QQETs?3f!hF?DTRDL)!(gS)^1#jmHQ_=*`ygr_E8@`X2rv_V^E>S)u#YbHxLKM2C1JUJ^D~tt~YG<`LyA(^vYoQysG;?AW zajZL^Pe;4*YC3Ud%gd(#V*TY8GSk=-U2V4F_sUVUur&a}*rHYHn#D^Q3J=pmyg7$Kh>`w$3jh9d@oO?O%o!U zMsC*USar?CbQXy+)}9Uf6*LU}G_WF?9K&EL$iHCGd+t0D0z*cdX?F+=)};J zsuN%J4c#8@+?S~-^nehB`Bb)#Yr@=$^@ESv+SeF0kHAqfBaZ%ipHq2Nii#d(+ty`G zU06FnM=2}^`-P6ac_;m8Rd1cU%1~y+rV?FjHr$tC%^i6rZci;k4Yd37z+F4j$BX-k z>&nYRT|hsw>ihQ|`jZ#0U^x%nj-_?P(*q9;=$j~AZxkePuX=)4jd=KEPA2`o!4G!3 za}1D8KuyKb$-XHUdC@=m76j6!mz&+P zDbGoNEs$Bkw#Ir;e)id2rbVlh@5Ro~q+u4ICziL9ii>6J^zOQy*RVRq7J93gjc>U` zdWn90>-!7n1u)q5JX(=A46ZzJ2yS8j>bpI6vQ~OhLZeqjE{$@Wl!n@^Z=aaQGAr(^ zh&2yt%w1AcU5j;R6cliP!o7Te^-a(h8aI$N z>A1oZ@f~#bg*N6B&4xNs9aZcg8R5ut{P3st!OeuUD|ZiHMx^Aw^b*Z;1NF+O&TdG$ z4CN(AI;JRQ{r;MDy^bekkZAJe^$RG&n~zuS_5v<2w^r)T=w3Z4&8xo8yMpFPPN^Ub zvXPS^Vm$YDPQUzyuaH**vtKaJ^7;Y5i4!S-*l{N-?EC>W&n7c1s_@ZoX}{3L76NCu zlDCgx&cY8{^Q_s~wT>ybbnbArRgDvGPFq1m#V1!TjJ!PhQU|{+^+BFdYs3h$YGQrA zj<5kvG!j*VeT3C2%g82_M-D$sKluR5c{LUNQXj1q6v(_c%k3+=M*FOlg>WxZm{Lcj z*>(N{O36dt4F|BHT?Yf;=vU}e18H4U3-6gryY;La;A+D(In-`BPN=#vgRvV-Pu}n= z&++a>Vbs&=cq={l%};XMbWFjsRsj?srrXq|))jq@JB>IMI*GuR_y8V$>0gLpwLKO= zQHC0}7Cw%k3fJ>Xk*j@HJbI{dU;luJx7XVtB;hut|0EVm=jBvh0*S=~fC?_MzvB_t z;vmvwE*T40q9RXT+E}dvu?f^W7=RjB3Q;&K;ovU_B2^GI|0q9G3i2nL*`45QG zwa(!>Zn%|hrt*k{T)4LRuJh}~>M9EhQ%-C158-F{LY94qqU#-yXb62v@N%m{r)A=2 zvQbTj5#DTimXKfMo;A;Gi!4s^x{nEJx&AcpL04!0r9e;B=^B%JJm6TMItgS9h{J$R zBxSfbKYLT1eKAqLQ%rb;>X73nAzWh}=QAf$#`3Vl`HESiQ|HrCQNkNaGMRy71lhE7 zkf_JsZ5nmVVz91-ux`!L=GqlpdjDgJ{SK!|oYa5_y4TP!OgRp;Mr9=P;ZWZhqneB& z$n1HWRBqgGBz<_VVRiCA)H!kcB;|A$XXj`7GBS6CQjGNe_e;vX1anaD5`C8GI>Yq4 z7bPc9)uC!%P9Pr5B-MI8%goyk5JC@!{SE}shBB$I=_^AMBGnSO1?Z39)*+lPZLtM0Dl^ z?Z91dd-+AGfqg)eFt4d%u?`tk1A(64>kZxr+s;tYn8B?=S*(7Lm`_QQgO^I7b8-?U z=}xDU*+(~|a`Vk4FW!$WsTS^=S#X?bOp^ufJmEY!A{<^n|2r{@x_hZlFSIyv!9*zo~=2--sv^( zc_tcLM%k1|;p5&P1yxKfiC1}rOX;x=x?It9p>5DT#knQL$7s<)CWR;@(G+_cOw(p-q@lNXJjJloJny9BeXJcSHHb}B00G}AX zO12>eU{y-@`3wL?1h-Cl-*U9Uj7$CrOGaWkT%Ox>DALkCI%3VGB#yvOj2WO7?NjX$ zlwL@ttYvh}@_bec<;#W;IXjN@d5p{$a=B+_;X;VwGj7P@L!2g}y5qqE|$34eGZ%9A1UfsN| zQ)Kc?)Ing8G!LHGL)Acs|$I=JpEAoYlLe~P&umoHZKF{p3|_- zS`KTOB8zam&kSVBbR19Kb9vl#iD05XXFGOx8b>aJ#Xw!CS9tJgl@W3miYgO{MnvVj{)StP@U`Xt&8$k8vtvGX9D;5oU*|<07KbC0<8Kr`juFP zDu1e0U6Di>WbNpL#}E5xPfs)^Jr}4-Pp^eV;<>2|Y547)KOjfy;Do9SU?{8i55d*4 z{u#R=b=X1DQv`S5N6)$AIh8g$D1NK;c^)*DT4n>k$Z6AeI=FcAbE{?_@aOA){nELD#r?6qhtt9g(Z ztXitWls%HawFk7Fhps%IlU7cs)%80Mb7&A%m0-fc=Xb^9b)wU8?~=?0UYu+o?GSYgrU8IGr=*Nc@i zo%ss1=lqxFUe(Q;&xP6kJ5}{aF7y!Cxqd*g!W=e+An23zfb3{<+`)*|F-3-|0W>=J z-3NbHymk41_{#?9Z`QT~f_>>KhJ$pkcUwxipnX3(lFc*54*p2g&Dx8*! z_ekc}`!WlS+Z!{pJ;%;u?eK+AHQy^+t%VFS@Bv96dHJzEQR+f?*(KbA{css*z5Y1) zOrce%c_IeimR4j?rnl_zV4`wOc_+pTqdOz1Y2)>efj2YSDZ`KLEv$3&9zPSH%Yh`S zn&1(HsEOJUjy`;{=7d}#Ux-hfpKUJ-v;^VReL@e}SO$(kbTux2Q2q&3M7d@>vRq?z!U9LXGqnWNzE9W1< zs^(jhd90&lZy?~DAbflN#w;D~ z^jtt@(s04jh?e?T`wdLYEBK#x})rk(gbvbu7 zUALDvcFU+#9JLHo=juYG!kP(Tcv?r(XHKqUee_sAL+S1a;hlK%JKnN~;nH`4D>t9T zZBPd~31mG$WuVVC9YSOQXEDa2a0WiJI?G1ib8NeF?-1Fs2HaY>OI#VT0S1P=L7mk= zUBf2RMki5D=Sd_aaSKO4w(JS_Bl)nNXRgmXyCF zN8t(eCn|lWj)Kpr+AlLQ>-dUBhkE7PZzyNk_CHJ8t;mBqUBIS2OZugjEH|Oa+qMP@e%92;%kW-8V1Aod*bTyrG~(ghE`XqM~Th`Oo+E zv%*m1tNet{*2!|ANw5o?+0N!ZJ~ltTyN%acDADLQuhgdokrD*gkDJePm;AKwUWl%5Vke=B+R2`Yw?{b!& z@gWwIm6~}^sH0!)fkO#c5uWh_>6s`O6qC2(M|g)3dLjSk8A|?7f10{;a6>Z-)J(0) z*=3$QFHZRKBdYT*a2&*;kiS>P%8$SEvz3_^`{AJ(oe7IU_T7es5tPLXSpJ6q^b)6S zG`ltD)dH`nXbpDFA7mb?AUdlg-|0EC;%<<3`Nz2!tbn9$<)(WaWX4~$5617rxHIqv zbk^m7f`t=BjCQS;rMQVcMtJsi-~ktfYEE8>&DWG{MW4(WH^&W!V40r62G~#K-tJh} zRs8CIo^I}APyCAtn4na(u|PX6>ljf0=hfqluiCgr8#n2plcm@Nt{5}(>s9%nh$LwP z7&%mnD3M1t#lznO4B4n;v=M{K`zklqZauthuUEL}wqpn9qU4?~dx5*m2o=>|tqu7e z4#95x0mX!+0&|bTiNMa2U4ZTH2Uuk0%A+Co5rP*n)&+CHQMb}5wF|~^%OBLP5>=k7 z#P9!{$M=mfSrNGUC2V|=m00;@dp3G!4rpnvCSjj)vqcM?xZ2O^aHWKfj!tRhEDCnB z3{{0|X=$PW2m_{L(Y3YJG$5iH`9AU%@r`{q8+Y8(Y2HFXv;-Gv3hm3*MF4A3HwUN~ zS#`sacX~;A)t>;~ojtgF|JMlND={8>e!>gxViZI8R-)mHBa!22$Qdy@G90h-_0 zY@^CM<5>JcgW)xM&QQvoGt^H-<*1sC0x#I1Q@fH)@@-RKWaR2!@OEK9@7{+w^y#!J z8|qxBk!V~k@9hEm2~WV^I64n4_i<{9o3(h41SPKNIR@V0%nU87e%)_)ga8IP$02qB z*q|t;fFC1qs>JL^Osm#sWW|%nZ$bFz(N=?xq)6?kU=qJAd2X zg0X0RwK+VW=uwtWQclj~-;y++g#?p-5Phf@-jg8K(C{7%i4cqzO0RlUF6&Fo?u-`u zm~v)9N8m8w^{eN89*;5XJ{OXtBljy8bxxx{9NsDb@F%f|!8X8t0FzwaS@H`IoRUali<7_r4WwRtOC30C zs9kUz#75HyVu|QxN8z*}v!@{efJ^8Czbe!ZKy(BZqU9s8{D)Uh@kjfRajk1`XX8Us zAFwmv9~}0i0nBVBxqlYk&I0%N;h%Xu6&S~Zl$8%Y#D}UXul0uihD1_N?j}Lk-sQd#Nv- zhY-lFx@I9tZm3oH_kQ4LaZLIHIt1qS_w-S*7NgiF5@pR4w=a^8&!Ezdtkc~CK2DE1 zwa6G@l5IfACL0Hc{kYu1GJt_!uKd;cT=o6?qSfbO2jO=Uy9k`vzh>?hb>^{s--{(+ zwx7R8ys!YAh5HCoIL2}MXl42ct#xzNpRE|&QUnc2?REW+DL-WQ0%r3*r3#}5L{3Z0 z^w3}VU5h-o{et_bV_2H6XGW0P;N=+px*I*E09gM7Bj3ISjA{`p?T?#_=L9>Rq zPHc-(0svF^ln6I6oB3>wcAeX6xDAU+-q})rO3hofFZcs`BXi>^39;-I>k!0I~IS*yE4LsW$#@TYo8`e+X31w_;HpxGZHttjegw&>hBn^rv=(771 z4Vg_wi`0~n0Zs87#!i?zj({v$GQjYjH%HbYC%wEy-<4VJ3wkAqDrz|^e&?A!;>AfV zuf>y8La*VHU#lwccENaYhKX*UHe-EnrJL0uBd^D(1g_0np~R@15qCq)ul+l2tF0+{w3y8EAOqqBt?{vn%W}UMK3en9r4^ zP5I+MOZMrk%iYb@TkPpYqiN$6XKwCjFr>8)u_Nl}y0+u>903V2?Aj(%(QxJRB9_`Y z`J0thI^26FTCgN1ZxzEn{rq~G89fXRE-iWl$@z{#On6+}8r(A!Y0%B?o> zR5ZBD3)0>ch%C`x-{OjVE9Udki;($3b@Ox5#=Wukjf33T;#RrGgdEDdBcEBn!;Yr1 zTmigGc&PnyNO46iBMa1d?ShKPNE6<#Cp6B z2HXn?Z>oDwk{|;~i#Ar`-o69s;}(_0q-ah)qHHtHt9|Na!vLHCW5T~Tc^Gwuv2cL& zf~*%M5=eRf2jmJWVPK(@FAswNoZ9a&euFIGT(-ov?eM}4SDIDuTNLgwKO5i^Tcc6j zP)mXZky1i*>7I3}tNF5+sMEnjsTjiur*j7CRftur1gO|+URr()t%#s~k2(4@45H?VfM=qeOu7eOo@+;t+sc;MsX#uS1L(%;EAocKL-v|LI?b)vy7LL+!V+5$ zcP=+QpAvEE*b}^3r%UrXh_UEqNqkMSrHCH#`A(?G9}wd?N(pMCGZZi$(VCrLGOS@g z23&8sJ6Y^;w+{{ZHSEQ1WOcvqd^x6^;c;fc{LE9KSIDNw+h$%jbp>*I1*A5#SZ9nl zFX(5QCXZxNuNd&i-H|Egv$jACq`_|ALS(~na}b;f#K(4$?OnWz5&}P`D}JZNLyD07 z{;^a~bpq@uIQp9)R>hY!^x@lz3IfW1U5^Z(mGH-INL3vB5a_-KJE5dFxE z{sEo9AzwcHuYAaMB;`|^EYSK>9Sp$ow1JO&g=Y_k4ZX@hdE*M>{KMo4_Qf}XjYJ9C z&Vp;+VoBCa>v0r^&$anE!yhJfO}}PQH*-9rSf6Z8l$#Wy+D5)ZIAQJlb%2Z^vz>>! z0Fe=BFhKUWXt?`P_C1>OE(L|6B6F z+RGTWO!`xpIg?t^Gxdv*MNLOHHo=L1lBL%$9LHCYL91~^;^6#?D^wXWa1g6O?~iEW zX@jJJ=EkoqP)y;ESs2O{jO!;P^uP=3Y~R=*7-OAR$AXyiKCA=m*D{Vxmi0S7W*PK9 zG(hdk;6kXpg(P$MXgzTb2vUuJ1mD3}GBFUbYYuFNC9DtmmZ}U;a(GCMa4i8GqsWhN zSvc;R6fx>V>fpZ}jsPz3%J|=vK1T*tdZcI+{KQR%tYSm}uFv9ZQkLr*gh+|Lk zfpzu?xEY_6{}#W%)gk}&>S5^Ie`b~!XqjoFUPA&Cr$$WhQzfS&(Ts%S=;x#WjP?AI zthK%F+iqmeVD`rn>OSXuf8pt!3L}gZ;P_%P;>ipZ?xXXq$DOU-25_Cb4^2$B4Ac*e zo?(g8JIB*BZqyrvNPaw1P4ZeY^=t(7dYk@#JK~9I|F4{r5AaSPqIIu41-v_MI9d;l zpxRg-aclkC5XdM0cCk`1wHsb*k&K6E;nYU{u2w7ZW6b5-B-`;Fczug9Y}Ca`;){ax zK3978jPUQ0UFS=S-eyc?mVal}3J6oTQ9OXU*F}s|4NB`fQ)UU9=lll!0vB9a;|D9B8)yHVc?Oxjn@xPO*KH?H0F)u&1 zubkeqB%C<5Ya!ldVFl{9{X3~Tz@%^0&w1bCHH| z?Z3G{*1s@=U;h8sq%I?VRTAQe@fahvjnn@aR@)(+?@cAHSu5bVMc(8cg=816&~Hvi z0e<=E^fB-I1EfJ0zv|?Tjz(}aqZzwj|p8mV_3h=Gd+aDozX z?(5c2^GMw|S$~Ag|X?se_Gw-oy5E)u{gA3=@c?c5}sPr83yC#5X`6z;JkKaBy&T7(9$XzFuI-~NOj zi4EG;3gKU<;g+H}$K|?c9D4@<1&+oxCiRePCj(9%9AsK8xZ6bbq?U#NJN-d8WCC-P8Jz_W^`19l0@u0hFx zKi{8=2h^qc|H8^yrTkl6bckV$(f&~Ja!Vr|rM!!O_7;zB$y(S0hmjPN>WjH>T^jy8 z1TFYE3Pc@-F;2@uF1Q|N`KycMR3Jm<5*-L6vq=%xbSe1|Qtb1l6s<&a)>+dZ*UpK( zv4u0J(*j+kD%%a%(IZi{+-l%hN5S7dapKc-lH186|Q z`!oC+lc=X7Tu>2@%4jgXGd`#X5UUxk%qJ#y-dQxjh_qDKB3nbkY!23}`OOaNdzRe! zEcYM#e4vd35-9^{sVEp7S(Xw`m4pg^NyS9>gjpIO@jVUoMiR$K%M)ZJc#*pVY(@mz z-xw)+|K#A(bxYSDm5nHu%D;#P@Qh=3p*;>9=`i^`a!J zzwK3$cY88s8*g%O^R1$BXMi0gAI9Sfz6y4(oO_8~is8~Cj^g5bxaQRv@SF_+6RHBT z@hW=$rTRA*_XIQJbn&0gE-$v>(61|7%K*m;xJ#gzo(#rS=i#170V!@o7Xy%}(jWgS zQnX?6n{_;4>6vZMrI|*iSiNUKE2%nN2%@M?J0c#%Y1_Ma9rp|ZO~R}V9~^rZhnz>0 z8oAZ))HwX=m7aCbyV7;x_^R%Ys~~~f%QU}a8JZI{HNG`8NAFBOw(S-A`3E#2dYeIN z*$;fN5!gwV>z2DGI8rY^5Ri~rjWmg1pD$#^X;l{VQY0Lg+5Hqdr&4aDfiTXnNFUP< zQ>TB*{#e}CwnVkUbip|-Tt-*y$fBj55KBpb@lYp~qY}fg23HQY&2Xm%Y=~mFtRX^t zk*${clJc1VCs`Se=fAQsl8#~VjfUqyp*0FIZD+`UpBb*>ir@q)S(k`DC9bH8Eh?o9 z{8zTP4BEbV6xhv-2!EK$dO5^-LnS`@=9okYLve)Qn`8<6{*If}PBV~B>7Zn`UF`hi zW`jsTu?9awor*?$;Kf@u_ABqnb*G`XMFMUpY0HwJUCcDqsC&SGXBg0^ zSoMogfEL&LcE=INAL(5?*D9k~n_{c45;VS^g!y?b_Jbam!6k3UR6iw+R@*ET&}woh zm!49r%Hjhg%XwYn%iX3dN8JNGGak<@xJ~70h%;$btfu)u5soKiBTSkC%!FRVY!-Vt=cuRyt77h1;wjSgi^_VKb7ADX&wT z@4v1QotjUnEYG0QlR`)~P=)2!J|LnxID$(m?)kS-j!rkU+QW6ziCR+pwizUSN>4nG zx$b+ThgNEZ9%-PHA7``_LA^%2g{h3L0+jYi9aQDaicl@K(y)LM`|VU#Ef%{)y8+?B zv7$JM6x9Ok!MK}!KD#<2tP{lmI}erVesv`h9ndgN_WufIRl;u{UAJuQC2yu_E44W>W}_{lqtousxurMpBO#=Lr&^P&6c+3%2SF^KJeKn zV7bFP7_8X5{a55W8yR*M9&R1G|;z5Z}-pc^9l&rRg#Mr4h*PmOPX~ZBh1S*GR>F0PuxEs z_X_Y|g^dEC0d5gd3-1im?10dRO5t;dvCEOsag489LQ3mW^NA1D41+?rHwv!W1!o+b zu-xkxFpYIBC&UDSe#4!mE)ri7I@>78Fb?wlmdUp3WQBU7K1Kp)kJx>ey5Hp>FkX37 zF54S?Cf%$--c4;e(MB)&hQZ$b*034;0D+G9nDoHo)UX_5ba_#;bR)}mv|Q>);-xW; zGHb(xJvE(pNTsLXqA{W!C_19_Vf)X`CdSU6?44qHTkNlR z7hkL9voP3}-g?&XR`q%5+jsP5PL7S~zArJ#{wC&m00>x}SjkFcaySb2(?JmzQ`_2- z;u?@6rCU2GSvzzCWAV(TE)F9luDu#jkqZn^OSH>gO`XG<>_B8hH<#}6FISRf*~3+D zczNy%Me*`KoZOXdF4xx$H-GY^E(HS-?}@xG`DsHw{2c6!2OL;P_HaVbDD~RVax*vl zEHTivqBfgbEIVGQw)vlhFZxB2dGEb%G#>KK52w)U>#j6Pc4bNJ@Z&Oo!yK6$c^4|# zgZSu^x zf+%1*i-=O~{1=XFeJ&Co_wq9!%k{fv`EvKfR~pBE^WGNYefU5q!Vg2(6ZwaHklbSR zNpJ)F_7A9PsbeG@NPe|gqZ7G1zAd<^t6s?!rp}?7rX^eMB{IG<-CH}gF3h0?H`5DN zm!yC|Sw1@pq)TKeO3H69ePf(dw0Bv6gv}HK{XUY{nPk;$tE&(6-^wDmeTkcu-m$na z<7ny!WM0evwuQCC0=SkX8@zVTGU^RLrt4+|kwx(Uo<6?U5$FfkRb@Yd&EYzro^B1_ zGCkG1bbt2Nz4)E0np_&*>ZIyB;Huvk7%MPV|4>exWltLM%~ztF7g_5{p>O$I-lWv? zv7G>h*O-vGFr}~ZFYNW!^qQb~)*L@pzKQFB$m2xxax;+eX9gJ5U2Rv#kx~rAAgp^P zOs=kIl(^I}RcF(RM6O0gMw4s5)n{>fwv)^>(9+-;k!Ag(X+Q;@;7SBK`(bFH5WwKS z^#qzixbMdr`4qV>iXzjEc8zFkHH1vs8s(-iguoZ#Ar?Zn>!mTmI#Smmd7*!^{e8si zn98^y*qt_O4fcPM3~4_UX$!%J(LOCbN#s>p9P=d?r-&NLn&7 z)t#~Sdx=3+pZg5h#0S4oGnO5|(FQoQZx1_taLnsH^j|%!Q^vcRirT8GxzYv=4(1=F zS5y>qdU~wApkeCVXPgxy&=QSE7TbZ!h$K~+m&NWju-wyoEj3e>N6qogbWcW{UJ8G~ z%T3lO3_khT@;qJGuUEcJj@r4zfO2KL423+zvqxRBpwekFMi-3AiM5{Je-QiG%7)t` zoAYVbO&i$-|!fim&WC@Tvg?8EX;q zc6NI@=Jj>-sCjeey13!5C(X?b7b9XicQ`JBe*3V&I>7XyPB`{X)TN3RZWoW`5xRlP zJrOQn7wp_>Hd60%=%|%Xw!EL$xWg#ol%(~(rBAvy#HEDD2&A;Y1Set;V`M1f=kC0X zsu8(4ZIN`0M|SMTKH0+&8P%F0!Ees#mM)HyiJ(9;0A?ASyouWDn`R7{L)=eb!uG5?S}?vd@f@AW0h6`RHRAwR!j zH9(M-2`Z2@i3OhlgysN;+8NBFgONH1eX#kep!`b{EO&fsdK%}NUR~XiKE-5bAY^f; z=7zJFS?rZ=j_+q*gJl6c-X9Rn0uj=Ms*&mrsifPS1xJUv;m<<^v8=g8pD|KeG+HlIEnqS%|_ku|jp`BB16EG2N7ojeItR5Qh z#jm;{X4zph)9hVY*ATAh{8dZk$nK)-tJSf0&nss!DBcjly?q(v6Njr8nC zA?gde_ql3g@tVs$<;Al^emjrCxa05d+;VxVP~%zOSGeKwYc4tcjw3RxUY&9K{>kCF zf6ZDXY#PBXK~-~mu|>ZOkD@ZCYF4*oqLVv@ism5m5cj~+_bUtBF?C@DzBd@;jQh{f zZ9x+FafZneU_e6;oTzHK+%@rgyRteA1%v}$j^&iJdfTwJ;ae%Qq<#TUl9}l)=*(+S zDYzECa}JkHsKLus)L>BzL&fgtry-k+0WM__H&cj}OooS8zMCw>9Vu?z5=;J3Js9}c z-(Z0KXaWHC?YgR#BxzTE{xZv6E-~0}9aYX=(0VZa)!H|?h4QkdkGRx2H*EburuCbH zp~LE3XWB3T^F#X@&zDyL>q-v{%1R?39no-B09&Ojk{|qHT4r(62G$C9dNw4+Jmysw zezP-0|3bS^ioq*|UhuCFG<=smpXfZ$waDoNIp0G#W$lSCUUXH+dcerlE5u}HHE?P4 z`$kMTb30N@e5{16c)Vw6d6pmZIMvsPp5NqRUMO49Cl`2k6?!^Q>mDFCSC% zgi`cAUEcbiK|23$zgG{Kf_o=(yV-OvltHQscUg;cykxpEEDnf9eT^5p=viP5mB?@J z8_kvzUPCJx5X<{-!ONdf^}XF*U~JIafD5&i=g5k<*6FAgIgD6LiVp)ocd=|knb3}D z@*ebgU4pnp>D;CKLz_yQdi)y-Ai1xTXvw!I<*J%4rO@q81+JuGm!~4Bgl6EF)yv)L z(Ox82GP=lWuT5sB(spBnQtMOST~VRZ2jDXth!Mby*AdmQJ{)%Luhx*h%h|Tub2Tgm z!6h;16QJ6krRSW;W~k(xy4c1=yhSnxf-hFoaybg5E(EO}!8m7QNBG=wZ;q{u$^jL* zsD4KJ89ho?mh(S}aw$5Z={CXMdsqqPp%<$wRu4ER_kmhW5bill31=CD{<&N;sm{9@ z^hz{ZeL%L3aB816HYfg5xW)6jlbD+~yWd?6J{Iq_p-N`*HQY#ox;PYAN9mb_rFf@0-^8=IlXr`-E&0QI*!FtotW@66<1AHv+r!#MTf=-%Gvnx+Y%y2w?1 zTd&-JK64@M?3u?e9cflB(;E|NU+U4MHaV4tt-Q!c>+x8#WYGq>_>ON)!~63svj=k(dyLs^eemE! zqB+A55c>e}VHB!bKF>wr&EwuF`BQHMCC#O93(VA_QSO!=*!jc?Q{CE{HLI3)?Uq&N zP1;+aclXpv{?D#tjH!U1QbKUUx>7+zI*XJ59Js48u1=XfZdotu=5H0D@c^-3I|a8j z?u-PvxhFMt7T@&aiO{Fg@1ifuEF0}6lJrBxa9*{qj5;Co^Te0tqqX|aV4a^FAe#rR zyU1$)D3JrN^#jWb<$iONKML|G} z^d%KsuVd0|8}rjFP2BWY3Vd)~Bp&a^=$yh-7__xrG?xAd6TbeCzrSI>Q#;v8dN z(^5|>Tl+^&-s44>)l3NQ^2P*qHYjLa(udewpq#m$gL9u4vX&qPGam{3v+%)d2YZuA zThf7Yl6mbNe$fedBSI1qz*PD#YO%#R2@$yy-+7mMLk5_Kno>80Yt14ePNa9)4JhsE z+XE_#;%xMQX!@sK+V0tTcQ>3Zy`$GXyxUmT@+HVpN7qJ3=@eV6)IL~@*ib!ZIrH#! z$T?vme+)_hkLm%Hf*`v&xWwjFRnlEvN!h~em#fHYMP>6h{DjGVFxbnu90D1oYBw)@Fjo_*Hs5YLMRB(Awl!m-SQO_{zhG!qrnYZL_6?!=4)> z&sInRk>!x}5!PgMmuaL}8GfWdlEB(bZkJypV4yN^^oyY*iqjaa1b3mYw|c8LHoWsh zhVAO|adgR(7jf~tzXee6NLg@%E?i~aGp-}H0(WYHaU==WUVfa!`GbE1$a6QqG(*~_gx7i{hb}y_8;`t&VBosi^;7aOtx5L@OT=m5> zjjWuc3i!ow!%0|%gv)9}_(Q6E=g+F+8ubnL%2x)y3TC;&)}h3tbyL<5r*0CgW_JLG z|FUg2cD>;J#FYtBK2!0#&da$^uCU%mqeF*V^Y^zNCo9S9D(?-%K{+TEwA)t6e^C|W zs3qxyxSMw`D%c9Gruu2uP-j+;XN!2mb0BFc15gbrW83v%<`Bsg)Lvrcr47bx0*U;XJTLnuTt6_)Ox+Xx z)Y$mqxfw>=$TE#9)v)x5d3qTn9ay#oF45lvY#~iw()5v)%=C5=Mv9o}O6$Vv-=vwO z4Lcc?J{I~Ya6QxgE`AsAdLDbsJrN zcCyYY;>g-(WnK42@0{HF?#19YtJQf={}%AbNC4$4ISo;-aT?tXPIt<9kC0xpfHPD4 z+EDRF)<`1@pSC=|#98Mo)#QrnO9@L})Bh4&fM}H9S91m>R{t4_bCy@sfi`-zf~AUe zcF2)Zqai@@Jc5&x(u_^cww)j*yCQTdrpxzYgM@QWw1oM1E>S2QEEk__7hV=IW8W;P z_hTi4rUXP=Ob{j1OfihrJpO4{%a*^+$Oj%jl;W6Y{j4_e=i$Ev9Qa_y?srU+<%S?6 zNDv|Q#iQBw4bva{%I~V=hrgP8T_HDtUOQ2j_vOTWLc~F|L*Km;%KNoi8s$K=;SBg}!H3W?Md=Sa$A0?UYOy>m@NXa+Qj?8tt)>h)UN;1dIH05`MDO#a4X&Sd^dffO&qX4slIC+NXgU=xKxs z|BH6}YCeAiN77dt1>b^3rEYUtg<|-y;;=bBw zxw)eH&n$Ew#N1C@d1B$BpjX3u4uOHga-eF&6$9H#%112cx}f5CO`88T>DZ5GuL*6G z%>>q)kX);7x_e<^(!c5LQHiu&0#P1rV9qS2K!TUoegFyBb}4F~k&Q=dH;C=DQXjX` zC+KI9wa4qM^v5lRN7U2auUl%{g#F&m{=KdJudTgzw2s1q^`nEG>U@)De=ZD9PZKO2 z4&G!J`J|jGDpiddYfKni9Tc2Q0sWG8;TJkY@#-2eAgaZ6Xin(wc{9XAoFit~w8-U3 z&1`N5kar|oVK`ywS@ySTljn<1?)zLhh93oOz~iEQs&{oWAj+7`&&{D9){%jEWkgCY zGJXEZS7v49bMpd*uV|0Cq~61d;1~;FjRWVUw`)i4<2At`R6#e^wNy?ubtmQxRvzd3 z{_eqGR-cS0N6+++hvp#@+IyOlvW9({aNcPa53`~=I2(Y`vb!H6sSA~IZ8vKke`b=u zA48$!;^hokGj0L(xzrHODNBt0dX3KH5r`p#u;U^HuON3&^8mcVBK7ASyVoA^U!M}nf>0HIS5^t4w%uA)>zso+%{hA zkXGu;*}@q*Pa0s#|kCx2ov1&%fP}7ZpTD_s0 zao0?1geP)4Sau*u_7|!%8Gm>Yx3SpYMZgTwBe2JbYeNwgu!~V~@4w8_rKs=Z(}&<_ z;;EcY)x72(Tp6jQ!UWGz1S!&{a`iUu!TYGoVy+`17}+0T1}Em*h`9};XJ6&K9ko)5 z4Gyd6>9W##{PWExaTG@bC};bw*|8UEm;6JN?fW~3a`*76Zh#HR)#yI_Yzcb*3=-Bm zTz)XlD#umLs1%~RXlAc=tlAEE!_W}mW|%(!G0FGPlssskuJGqya({)s(ShT9 zw=YMXKiBG->y-7@yZx%p4Z^$11M!1_@BDYt)-A!exw8f2w24OwvgOi99U`Ccsz3>g z`lFBfAl9o0rRNs)bmr#-b^b}gAFA=p^GJmYS?~PPN@AsBTQXvxEc?P(kTd{Eg&P(F z(7vnyO2NsAe8*Am{0oye0z(_^U^#zcf`fP6B-TEx-AlL)wWVDj6X4f1YiSb>(&P%4gDwIFNgS##-A zfS#8?=BExq23IDv6G1F^#@1Z3o8Ve58QCV@scOQ$3Q*jLe?7CRW;=15|DKYCT5#zK zl&&Z>LMrTKi_>FgRwAqEv>6H~lU?1{5qGCQy;Ya3;lwtKZ9i(xfXL(W?SVp>{zU8z zIc9A|^W{`!%42EI(`a~S%XtDdoayvU?-G*(?uw5V8wuuzR?)ie$bz8giI<)&sZmC%I{sgBwDLnVX(=i(Y+3bgJAvx!CF6oBwYF@SKJ zJTgrjx-fZUf)prrWlUFPY^K=VO#IvaL0HQP>XCFLd?{$fhepIQ8(0&ZD^vQ<5Pj6| z%&PJ#)3Z}K`7iu)e@$`gS%F(s;-oaaOEu^fx?s>OH-(Y`|&5D?L1SRej<}WY$;OfEd_TE?7Zr1j!`&>y$W(K0eagJ z{p^x1g!o3g_UfG9+TN!3(I?U6J8)Ea;)wQ$dX>Wosp{Ef z-pXs4hlOR)Xb82i6G708(~h)cEA?Cf{7ff9|IojCx2f{u6P1nYeMblGAE;uc$DMOq z@>BQwpgWt(5eKbv5!ZN`QuY(ywo3slB&|Bq6_&6P?L8I*i=jv$-yW#QHak!U7ad6Y zkbH8_o~mrV*u`Hx2yx@xBhS&YXZR#PcHLWw6Ebk2vmu4={36dRm8_aPn?iSslS#?$ z)Zg(X4E0YCiVH{W;(D+}u?mA_0E*6AkySYyb=7QAe{Mn4g?jj&+pOEU+&{IRlxQ;d z+f_CyKhLyv1D`79%CJ5qe0zr6>`_s7Cat~657Zn-2w`pqAfMMiIHu9qK(I2s4STIV zCKZw?fASE2EAM9pCjsOa=;A3Vdw8X-?sr-5ZAAiT(oDDj^b_$}K4ML+5tZ9XH>*+m4qE{=+{tJ_H+p;?cN<^X{Oqw~)%3hg+SdvmrSeCV3x zHb~U&a^vc5+w$KvV|&CuS*V;3>=E%2=qd^Qgaspg-}+v6KNW+!Zja-CBsT8(Yj?os%?B< zaKLRhSI@N(Q{_AbMWbX-Py7W*L+KsgQ9T*JQLyLH_X_1-ur!k4zS@!JeL~S*_@Ppo z?Mt+r++AbxZYK98sq87?zS_}Tsf)wvCPMPQ8GQ&qQ?8R1gWAuvp`&DQ?-~7WEacn} zV~^@6%xGnlULaGTm0y0n0Y|StS#u=ZL-J{2==F0y3zs+7Gug$<^gr9 zK*K!U8EjQ6g5JUm=q3;6P$1$J+2$=?JI8AOd{!YM3{HPK7shMT#_z`uAog&BL37)d zx4(kg*q&Ob^=10zzJUEm(6!fjFj^+fiQzhE{Z@YEigjUo=FZ}zOtmvAa8_bDYnv~k zRq21`Lkn{44)pEmZ#)wz&37J+sTch}xPQ4+uk7q&DXg&T0j8HPfjip~0CG$EIU;Ps z7~fGYn%;!mt64N z+PudIECjNuBK-g>5$Vsirsl>Mxo%s`Imd59%V*?Qm-Q2!tBO g+zNx}spK~^Ui>fC7XK{|@;};N{2$+g_P5=M^ literal 0 HcmV?d00001 diff --git a/_static/images/udf/apply-rescaled-histogram.png b/_static/images/udf/apply-rescaled-histogram.png new file mode 100644 index 0000000000000000000000000000000000000000..07d97647d4e0438481f3bcc285af2548a55229fc GIT binary patch literal 5777 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 literal 0 HcmV?d00001 diff --git a/_static/images/udf/logging_arrayshape.png b/_static/images/udf/logging_arrayshape.png new file mode 100644 index 0000000000000000000000000000000000000000..c8b8535efe4e4d9261585565c08b5807aea39375 GIT binary patch literal 65288 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 literal 0 HcmV?d00001 diff --git a/_static/images/vito-logo.png b/_static/images/vito-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..64974f447eff3d59c3d13d7994c5a1acf1a8be8a GIT binary patch literal 8365 zcmZvCWmFX27cGjkbPX^x2uO!8bVzrHv~)9cqjb&CpwbBPqZN=2sTsN%I%EWt9&+f% z|Gls8(>`mTbN9J>-SgqDb#J1swhAFWEj|VY2BDg&qCN%&CK3bVnFcQA6O)uwtNH|X zx|)VckB^T+0)kHUGLU{x2YZLH(XqybB3Wsf)6>(>pFTDGXfQP~UD}^qT3n2bh}hoV z)>PL3H>vx8!70hfJ>5O!W#yMQXULP4kTzr3@0Q~6xR~zu2N%0lGa0!h;F7eF_v*c(sYs_2`&}NcWW3m$eox_NZ_k)n zkUGbNfM>sqMk$zrD!98ZF8q=Vf;5x@7e)p*wg#(-Ku`Myw(WYEra`W_nE)7XF?f#j zRUHGJGq6G;@eHtkI}OtIC)@SNy7~$>BzYy6VlI#5KzcrqBsQ3z&B*On*NecRyP#H!Qa~HMWCgLXF^HhBGBjWXNm%Fo_4jMH2KDk8iH)l zV^qRnbq1Qy-^9VKYf8aci^6srV|=u5cH1cqBAh3E6Q0b7&2#F!8c_yMj-9Y?O7-N& zc}os8sMd`Z+o|I?+wNlvQEW(tsdwXqHWKxT<6h$(v4WUG=0H?luqdrHbe?=3jJ_Io! zyBSo`(e1XAJyRytYe|`9=kq9!w40%Pm{^|3i!qAK9E;$p&#O5e0iSQ6%|O{=oUg)X z7ZK?FSNn}VG3#`)1Qn-L5G&a?esSjd41w7uaq|~zXb*j^#M@KqymD-(Jz`BnV4!@! ze|8Iycr$iFAS$oo4s*|g{(&spDPq`5?Qa`uZD0J5cl&a8!+L#BQ)6Vy8YNi0--7yH z)j9mP&^=JJU^y(|B52rN`Zavf3)xaeD;2m+Gcq=7ZebwHJJQ&-nak$4f-ZUIh_qA1 znYcI?U6|9!Y$&^7Y-rb}BW~RLY#LI%cX#^E(jd}3A#tA3hfdN%O0#O%*T70oQ-4MH zf?5lqvW*)q`mkiwrxnb46z=Y+IU+P4!RX*`Daz1Q#d<1{Bj4kCh1>ErnCePo8_?l? zcQ%mNiDkVgNemp8XG%I{C+QVp>btLR*UNLVT>Iv1aTth^>Ij>>NCwnoDRX^P-d#(5 zpREX&)xXOL3$`FV4|F2lCw)=+#27y@;4gz>e4W1zIX+6(IFUF%r++NkYWc%`)|Fr# zxqKiAz2;qZ(X%W>s$@D|Q7l*8=?(A)bk6p0GUtvF;LmtPRb=?hOVBFK5Gl6|FYfX}VljnrsA)HvqL)&!CyYymd}$%21_ z^*XVbYH1>i|Cn}jt9=oHTf*dGx&udTMSpA<;Lt+$myFeXJEMlyGWesb(Kz}?{5)Yj zrWhYN$5GgPb=|qamQj@Vf*xVE(ow(o#!%#H()*L{XxwL#^b7V2GrL^8s(?Zcr@^gO z9AQUi{mCD6SEJc~jF8}l_Tc9x+mULls)mIzy1_u5hqpq*)RA(uV&4ky>mK@IeHalE z(ViPN52awEMEvKs7;uyJNDHL=IlOYiTna{M$HsU*?Kh0{AdbB#u#;6cZU7QHy{s^g zs15y|%kFX)muAOYNW5S8l%m`Tg0U`sBl6aZXdJ@sBF$~9rc4d|V19NQAFpn!^pXbq@>0Jl&j&^+^j6ICyBR-vHz)IR< zg*q!Q^v|B6IMx~*l0^sc!p}a|VVTtFzlM6xuK@ay2Wx&`7ls_!M^L{I%Yz+h#Qn~l zC0kX{dQzenojh={ZXddhQkOdp4FHk*4FQ$)&<*!sC}T<+tSW|{ZRBt74ciE~zxCaS z#})9}um7L3Ww@~0WDSIPKYea9*+GVVyQt!rp6pNt0aCD zl&dc?0TWcZw)1DUBWsVta+(QDOR)2GBijygvVs`@3bs$3EaeT9w&QDW9&89@xVtgb zH>BQ1!=x1UdG^mg|M20}S>K}k1E5krqGVeh@=~VW4th?yKj#~?F8t0?{xUhckoka= zpABxbcfI+&P>w0lr_=ZN^c%I$)t#~HKJ{xUY8q!r$1{!d-Ib~D>uP$ISxCA^7Rt#k zgvSPkqI}*$#-wR9(7MOFBzi#RDE7D%s8dWZWH~fCTSO`+Ge?>Z2mP7$i$k zoMC7U^!Oj%DjvTO#$w3z(9z9n_AvVKmXB(}X*^G+K7)7OJ%@;H8q0?Nd%uo&{kzA8 z@gUZia32f)!VJ2?rBdgTmhjed_a`_py%etI-%IvDaBYN{=VC+u{29jxie6+SE3f+W zKY|e79t+37@cx@lPIixe(R8tyQN9tBj8kX}CPd^&?ma!#=k@YUgp4m+v}IoKbkDwo)O?ZKxXFb$yCn;lUMV3;7)5=8x{1a&VKs`*^MKS&f3xcRK+bC|P!k9wj}h~18YXiXSvDUtJJfQMw0iUf)Z_Hd3Y$$^B_xUm9ys+W5S(p45eZ}hVP?SDL5_<(B9>W{w~n{#Gms5 zAngHrDNRIs$i`Uu@i1VvEA^d*>6{N$7q<)x=bXW<-qs|r8uv!ji)MviS-}kB8t{IfJgW&RZJ5)BcpB6V-bQpe-eUy$; zkp1zW@H({UIh*L9a!3CK9u@8ZAw@H}(zi9}<8Zs|!A4A|g*(v_C(*%Ygph8?^$Mz5 zvM#@ex9II}&g~0LQ+`m{h_BSgC^qyPaIf`< zFlQ@A-gS*9{PF$Tl(%^|22vv!EB541aab4qW1d6gBI!<{YMugkH0DC*pkN8g%KTEv z18?9J73IlekHjq^)6aq+i#dO{(1mM{+&bl%Qo`OSDiLU%6R40a*?059EB?hOsuGBk z*1sMqMPYVDyuUpqJ0>h~l)lkDXa?4R?HoATWN# zCDHz#DqO7B=Z+2AMb3KbOA>QB&)qK#vy|bE7;4(OJ|MwgJyU7V=PLf~bC<`oyl8QH z6MA~;mLkd9mu*x#6e)3&Co?ZfmUk|aDDI9NbqnUe(!tl$t5QkQTECs$R~o~?5dgeHiB?mnJ%RVl5Rjc(OI7b58XP`Vhl7PN}a z^7S-mi6YSN(Z*heiIZP@$4NF zA+aW>n^BTmA{hg};r&hgTz${<52YsIl8wkIm(K_3 zsxM%QbjI$xx+8D&Isfp#kp79ROAW<#;oOAs1#e%jXk0h5hG8oh7A>Pzo$kh%A%t;q zi0@IiKlImSYq-N=3sz83(olaDVEgtZzy)GT=O&izqeN9hQhKur-RC24h<>Zpa3m6L zUNws|9V(+#=%VHy-A0eIz*HmnB6=yQruT?|}NW!{Py5zd<+}sqeurV@P11SjtmQNO*hnA$T}-29t8d zUZ(XieL@|`;_nv#%>k|exNPh#^Bax^E}=fFvZhy44uK33dTAfN)+im`LF0FxV=E#8 z8wyp<*3>lm3~7Gz=ozz;RalC|zIe}e{vpoSqE8!Nl>v~H`y$3Jh#{$ZT)8#fSxjkk zf3>guxiQp)%{JBJZPWGSSB3mQ;{v$5`3R4UxEGMQ-j`tiV=l5`N$NlO*CWST4Z?w| zfU)Mb5ockRG3Ea2>N0bICG4338viE#QP;Qe9dG}036k!Ji2_aMGO#P-p`u(?9!K0W_?vM@$}l8(Ya|6U z{z$;}n}0FJe{u?ybW5@n#*uK|?x-BAqRR4#(LVhIlYG632>Uh@`{h3!TXF=sfZr+- z3pc>d+@*|+^1I~w8qYzE)|iX2X|O6UJBBj3xpD zqLQdd-x9>o7pVFcRuJJ*gBI%aG7bDShvLo|!}#T-CNuHAvwq8yX1(>ms16$4JL~;r zfMJ)YdD6HvOz1n|(A^>}q5BDxvV*jPUv& zTNz3QQz-?91N5~5U)z`+{~#k1Y{|(c3dX7kgBF?S3elXKCOzuVI^}&N{;g}cdjLvk zgr2o}`*A(UzGdX=fJEI^cG5rgt#@t12&0}+#367~uuQw90v=b~H)xF<`q+P5OYfR1 zWC`261T9U#;z2UkH3NquBKI4({-b|^#Y8Q zEao=svwa1Zb|e3C8S2!q9si{_nDZBX6M-DDMiKj)-qVYUH_qsgx9n2q4_p4Z+acVW z^6!j+W%se zxV>&^dyti3*-cI7W?R$Yz4(9YyssAsyRu+Lru?7jzWkG(G-xY7*>#P`+~_PZ`nfqE zQn%_i-to_Fo-ig7>lbfqePcm*GEQ#qp^<^VI7Cc_Pp9fj(Rz*dcFqh+Y){#Eg6|^= z%W@*w)uOz%9EI&TOK;3y?OonHBkiIl_HMBtV%C0b*tK&T9PIk|#V?QZxKfy^=RTRI znUL9{J2iyQ{SG?9G5>ntW=stH7R~qr%`71unTw&EcDZ$Vu#>q*a;ZdZj${__E`J}K zpB^m1r@OpPJ6U|wW><7xk@L6wfwgE`rIY;3&tiz)_h|putZ3-hZvB%pQHQ<4OM`WC zv~~B^kd?hOeJ%lPk`Z8+aU%o!bRFFfNY6Y=4I6Bp9oR9F`=aZc{MLShfJyT^CHL>d zw~ikKdJ(G?fM5sgp{<-Rzs01{&w-oiK8faEA2?(#+g&zGzEy>muGt-zVlli%@Mey; zk5po;y7GUnc--cpv&K*hizr-|O))oK`H)Bdv%b;fviVum3-fDJLEA;nmuFhae|x+y=v*{V%G(G*)B&mK(=!Ro;{25=zKHp z`?7por+B>{deMw131mfy%6v_*MdS_Rhtdj-gd{ZrvQ(rO#I)ypk9hhQWv1ucN zY!hHwDqF60p>z;rEGcbZGct1%I^Y7VPnkl`7?e956F`vJ&uBL~u-9Y%N3U+6y#fwx zuxtU?zr4MD3ye+tSB%0QE9T6LaR@X7HXk0>kvJv8?^&!&Q|$7)sXRN`2*74$PjQ5K z%LSU9dP&#OEe`BT;TBe5je@J^uLv-5rC_fIkSDu-k@)1s=I6V$GK4sl{X60hR_ ze-$+Y(kd63B(TcY1L$e(&XbL&u2c?Tn(C`y!yeQ|9O|)-E^ar@=@~3k5*+OPM08zb z=;Yq^N=729F;VHaqA5K~k{g8xc}}7tAd7PR!l==;b^GxnSAD}0c8F_YhCf)UUh|L2 zen~2K`JpEv5ngg=-=1}1#3SqA?;o;4>-79Kc!@n!{)DXXsv}#EA8Gd$8+SAG{2yNQ zTaOy0SU`~cycF@b5oa2KQb=qdahh%`qY<=6RPeM;2iAcU7uy8I4#Yz2(D*l&J+AWS%&Xc~3)x<8v(GRk6AQiY+M>#n$|_i&GGQaj z+l1L-@BHgZWV~`xzec2Em>7IJJ>eDuYor$B>9;Jc8mqU7N&ZmZ4-nd$?`VT%$%iR-$o^Cj&BiFWGO-o&xrW4%5m$@_?9Gnq zvlj{oacy`uoR=r9ElC;bC-s_>Mwo!o42}-+-7g(|}_13n7hng*-NHaN==3 zsPv^nqcpGxFXs$g(%LZ1#6tHxACLp(aL-CW;R?9bE5~tu!z1_1!yT3^fjbGCO4Sbvk1;--qLjuLoqI<{!Z!!6-ViH45Ot7R{H7p&aMmTSMk zTl4O#QFvE+5LxhCVLRHFNQ|#pF*$|sMK{WJjf*~Gu_*Izt=grbPT~92`ihRAyXUmz z)pBOAp6r#%)5V-|nKbZADHoccD&si%aNIt5(XH(-LzT%4!d7?75%A?DvKP1m_)VpE zdo+`*0GpjdcU|J?B8#-e4Q-S!x#83dY7&Qtw3XeV+RkqR4I_ant#WsYAaUe6$CMHE z9!m#ZG`Ygqvz=;mAtxBaA3ifTxeo%yN*!i_m-c7MnL~6GCglsq!M(-&p|Yd?R_m zf=x*GX%NY~o%NXJXo2qxq+&+~B*xP!(Gj~GW@b#wv3%6!&+)eDO*Vxv!eg+cJU^G6mq>CL1&)DrC zep;IV#%iSZ!^#|Og$;_F4_z3+#M$}|_||gagO+dRcL&fp_Q1Dk)szkZc*Yfh z3$97@*~jd;1;@&Teo!O_%ntX+Hq2(>r(Y;D@nqL!ETBRROXDkn(E3IiszLOk#B2|O zqNcO~{*%+{#iO;#2ZKiO-wjv_SQ*0|D>ulIcXc$fmj5<~bDUOl3n>^nuO9)CPgd;0 zGC4;L1y>P|FbE1mvXcDDUZufy8P^$$$h&kUxDN}NImE> zx-GsnL@nGaCqyeHaEdTlcp|x`ppDPEJ-422lpM$WQb_w>*o^T;?@f@JbPIX8kzgHJ zyrgG0PTY5UaKaD?Y-zjP^&Fkk4}vXu@F7Pxe2!vJMTd$mMk)M>g(3T0HA!Phm8Y>C zJIai~hD69#Cz*I~WY0~3z(d>Gy*?!p*sddrjGZj2K?~N3)O`Qi1w!Jw@gbuIA9p0h6-k63CxCx9lNg#x?I~U>qi&z%Qktz1JvOnvHcf&lVBHKx?_D zoW%}HN}$`^D#MT@3r~uC%tB3O#5tM0k3bz@YyIVqBr$eWq-g@=U+8I;Pw^YQpVBfh*DZ6L$=;fK~%tzY#;)@C*vRx!9}N2 zr=2lBj7C;4)>OWRt+iF-wt9FEIRKA&G{)p+IvnJ2`ahnI_;GLJBgcJUSjQ!wPE3=U z&}^ekd8h>kh;a~7_h^|WMLF+fzDwf4_y@5Daw3ttN-$FYUkL|aIAIr1KmXi-ot^q}Rx&W*ejf>Nm4tzDjV<}71I z!!64s-e}Dap(|7nhBQyAF;64@PmE%yztDgs^tG-txyro0gH9-oPBxoAAM#w1>rGuj zxQhmoQb=1iD`Pb1hL_En7MA-Wfvgx4td?qi%c#EORZZ|#dN*SbbkDc)y2^r4mch&* zJSC7%VcL|bt}tRYO?&%<+LoF_>8+E*9Gh8jZ|Ba11iu#9ipC07qVK)Na2Vn?|WMP33h@G!bWnoFoChCi-j5F;9jQ^ zS5L3``~7aXCDBPz8ckFZUFf!GAwFe8ZCD3nL5@x*cCYo`s)N7cU*$>=kD;<8p9c^xUP326s9I^6F-F@Cv)K7Jy7lT_!>E!M2XV)*STJd^S zIz4_?ZN2hs<=IbiQvF}c4IL);0z&)0#!pFAtEKS2?WW;3a{K??lGFPCe~X`qeaoAf z-seOr@7zFH`CR}o#7)aemmhyrR8+KR(TNfM*Yi;8{j5}J7c8MU3l>Y3%;Djo`-qfo zuNmK6#>uVIBxhLH$6A-qd=vls&JU-Z5DXCeliz8#H*tRNZ?QX9pO;sNzpk5_J1>%l z>{<`dgAuj8E*kjEa+L^FCn_u+rqEw%2&a$_Qdt$ST{evjC3Kx?-Xifs$D9b@NB z%)aTqSCs2CC&PX-$o}t!F=i*4d2+ix?}J7}K^p(9pPa8}#VqfGLsvpXL}WlIt+dzc zLJpMN4*@UgW|O;gk0f|}k$ zTGzV?p2vQ|iKp9^54+o@2YI#E#u?rmrtA4~4>*Q)ch~1x7f8*&f0JteZqa-X)O-(; zAF5h*VF339OXqeHrRa95+AlNd+8qU z{b7);{oyis1DMK~fdP@#3pNaGd*H2)OShNhA-=&0_N{S9{%66=39@R>g>spCgPa(@}qn|yzNH`+X8UD9T*)bxIx%R5}C_GMK-&8eHD|GK4j`uccs+URse3=nvOCZQH! zwRduI(stW$(RNu-dGEo02kzU6*RtzO;hFMSDAyg3(tA~u&F1J4&gSb^ZKqgFX-N7F4?cyG|!wpwA>70 zw;pC%;WbWXZQheU%w4r1MDikIVv<7wS#rPb-^$NHr`$NuYC zH94FRUHdtc?#rm!?H@TG7$dm6xAmhIfYp^Pon-^GzvVXW_Z;Roe11;Ts0r`?EtK(z ziGs$%3p+n6?QWyLg=+84 z3K1KT_!(xrXBr*1Db@ROpZjunbFUt`^>uZ-d2}dE}GUb3Gjmj1*zdvn%T>0@^Sy^=)i_mkKv@(W%{|oaZN04j##OKEwu)2;;PF20z)#l06 zglW>sibgCB=WWa2H&}0yc1L`xJD+!>R@T>f4$d0pWZ(Xs>AJ3%{D+tcJ6~o19KUsR z|Mqd!ewjclwhXWpMO&!^pSQ$26E3%6~9u2c6a z`RVQV@82g=jhZnpFCNK?b6dcneLFw6NznLBzLhYv3&7ZR_19~)hOX{s!P%zc7_E7w zM-QwnkU*#I(UR}Q(tisNFr4pMgYLU_h}+4us@j?QJfCv!!`{3uGs%13CvQDS)q38= z=n@C0zdHcb|0%`B!4b`k1E&r^qbi+tyeE!tKjW*&gSKgfPu=zP)-}c6^&)fm@6Gnx zus`qRzEH36){<5ltuVq6aCe$J+ky(XVady zA^C^R_}?_x*w~iW*Nf*)vTuF$Zn~1bfuNr4ahUP`TK&c4cZ1<~1G=Q4r+4&i!rv2m z<$c7Rk(HH2=e38uH4N}9Klz?or#^<6g8&f3xC^284%m9@-13^Q>(LiL6#t4&)ZIYirD%=P=jn z^5x$jWO8OqxM|J$ni>HG)Q&5ktG57^gUBzP{}%3$_sV06k~3b5=WS)GWX0O?FvINI z5oYs$-SHm*?0bvyOxtmU6d;Ai^OZgk44r%83q7bFDc#$|6WaEqZ(Ck&w!?3CyE^Q+ zo7~%tqW7KuAEW?`EIlXZAZzQL%T?~6F5sIahbmwY7YL-$Sn`04F^(e4ACnVI=~ ztvRl>m2(r|zksf>yKb=80RVJv*YSN&^GjiXYkgSMdO7m@G&?*xdfC|e(6Q~f5uM~b z!U5uYor#-0dswbDf>hJ!vs({;T&>OR(`IXteI)!S|H?Q&GXV4wj(sVzKF ze`0+5=sL40yv?uAC;k->3n!QXBwKetf&gNlx3Y z57*B_yU)<2jzdIc8p#K;5d{PJX_%C%{y5Mj+2LJv|y7~Foe0QqW^*Vy5 zIv_{LkH!}2_mbwfQ)%ZzJ&5Uh$L^N|F!0Y2JVn5&|JMfOfaN@Dt)h3%>!%I@OWZrJ z{smxG(j2SSym%x!!M@0|oCPMV@&bieNAa=?ee-SE`^Bm_2=r=$rR!xEv z>UZ@fkPV21wd5KC?sJHi2HV{qgNL*pfPkri(YA(e5R?$3aT+A+=jy34ze`>sABA5| zs#tDS!pUnuB935rzEMAVvgol8RCwZtJ$kBEL|lBSwT2(y%tnMdVkqdJZ_3*v;ZTUx zdiFVH4Da1(=$2q0^!+-(%m%^^93Qo@=Jm76D;;Efb+FS(gAS-cAb)p~A+T>-Pj!($ zq|*d%vatxJB&b2CNP^mdDi(x|aye)n14@747I}`T38GYtjLiK zdImNL{e?L6#_lI2jyy z=(HsQ0Zt}|X`DDxS*f~oj*!d)=ubAD*UqTX4o+{&#h#c4O>=At$B7#d>Bp7U6uawd z3oHu}yS`0pEi^!h(*~SoCxB^%wCD;B(PaTn7+dV#-f<$Nb<0kmlunm zly7(`!^R6> z7TY`Dr?-tm1s9ZyQsDeBfd%W$w-;tAEf-}m_KfUS;UM`0c#t-Icx z5e7l&aZe-V^AX6U&U^@dc}?%j!qs(KWPcer)B(Z-Yn_`niR?|_-hvl}iE>F~UE7B3 zG`op&`+$q#Hqs2Et+Owicepo0tDn*!q((KHss!S|!rMdA&K8?C)4Cvn9KCeT1|MxKNjCdHG` zwy_(m5OoScLx7>~IH5-v85?F07AA*7ngWv^+L9dSfi+0QmuC-rV1E{PYSjakmNq2i zyu3PT)gM+HG=)KkDrb7OpBC$r#QW{O?8|#oBaeA(bxx5 z_k=6KM829UrleB8bl85h$Ze`&Low#ZZhU>3s(N@Ri!+SC4l1%3J0>$e+;hF&+hE*H zmHf?Ko!^)5Cm^oc8^IF=5M>~)KLkVfxnyMJa=Z&oIm(Nu_KLltD172kVt5Cw0Txb2LmyYVi-fMr&QCbSxdoAxq^vVozJa zuR;zFT(>a2PoK9W(umibI3y80%+_oiPy;?=BCdzwrNnn$BT_>*Szxv|#tq0A`}trf zj)q;%I!J!FqXDWb?}tc9GZcx?I;V6~Wly0X{bW*mF7Kne@PVH8alXNG|1M(deH{{g znNE5R-8Q9bVA2_q9J|rZKGVxI?53zSfi!49Br%)N&l{BlVt~`=5;jgs7FtM_{$(4Q ziD^xdkO6))tOabLMu;O0I{}JpFq)>NYP`o9MuWrDe9S29*q%-86gCddc3rpxhKLn5 z4oCIyR@YWxA|<#Sb|V`w2ZI7*d?}8ekM5DMI7?~99y_Ce@~^{#%&jVKjO530oS}39 zB5{lo0_yOxK924?7VxYAte`0?o2*2Vzh*kKcr!QRfv7<=$rRcze?|1A@ed=}TGV?6 z*&5SKb#jjt4Y#>P=-P44^vT+6=b2gj{DKIM&Zge!epK1ojHQ>SPmPKa_(f3{w%BHi z$+)tG_pK6#Kn0|_X{>}iUW4mlgkA%G3LH;Ed5M5OVfRl%{aK;rw4@x#&yzxuyP_!Z zAkl*JmWbxUouSllV5@HUl8V8L_Qz#myUy`CU+v%^bo+Q zjqrtDxiqq6kVzC{Rl&1-LhfU?%y_~@hg=&~#EQt8H#EwA}T2iM5!d%!1jU=AC z(?;gm6g2_eRD$y;*&OwvR+PUh$=7GL#w=&IcTza(9Q-5UI06t6Ff@e899Gv*jrD6i zIQ4-i#e?rv6N%I)EJmXI*C`@xR(`l=B;Uutq#L3Cb|QK=7o~%+H|DJc1&i zDYHqMBYPz*sY(l&GO2!-4;HiO8-m0}bMbUANnv84YYM4@7?BQ2{&Vw&^gKc`OsOxL zF{8Dx-_Ooo6qNW7j-|j+m5K~K?ElS)DR{&U@A{}@YzO55yeMERU_}9=cXH8$BmuJr zrWS=5!)5COYROo&(N77k5o^tsk6y%1zKyfP0HI&Nw%>XoRBv|BeL%I^}+Lg-S-`!%lW;|dEX}Gy%$WaA$x`>u_%vv zGptul7uKj6BHr7;`?pC)n8;GV5o04oW!FaeqlO6Vgp0`1y%R=>$P&Q71t!ECXJENx z5IRUp3vfk4O*FYXjr!TFP>Fg3|KU_5oHh!`%x=gH9SPiPef!}cd&cpj;V9!6ksWT@ zOYGh7iLQ56btVz|ukxJMFSoPCy!ZBIM|Z&vExWqqSA?m*xQAaj9m$7+5?p7~TjsS5 z))7nZm1Y&oF=JLTP;*4>m1uEy{IC?Fc@*8@j? zjxZ#zs&Da>EWntYenVo|6^T1t;nPxg6S0H!1+He2oKO`z2wPFwj@4sRuY2|x^|F71cUeuuYrs>z`2-AW_+>G90~W}DcPKwUu+`7RoAPxuTEW~Dm}JP zA`f-KASzGtS$MLQmM3V*0ss^!LoMMTbd&aC0E<3hGfX*Hs}fH(o&A-4gisJ&5)DBf z7>#pShxd`2hOF6hZ-7~0ib;b4u?8IGAyVz=&tfD&YEm2acoA_1isP#vD;!e=OJF6Y zKeG)a4$V0CuE_jvQ#T5`;X|k6!`1y!TLktH@J0HO#wQ7OF?Waa`g)+$P!ZEMqN4}c zh?RF4T8St@982BpIpn+vihb7&egrQQkj&_d%Dpt_{>PP4Xt@_ToJv;wk7Kd#90cRw zbqRZC#N8DCR~Vlh%vDcH?~F2~%Ly%v)+5+;;DfP2I)E{_0TkgPliiEMA-!A?J&ByG z50_YA$P$-LKMEW^Qyz<|3lwzx>$hO=LN0bT zR;|xivRFXYYz#I!furZ%^Kw4G3?e{WlnZz2)j}V=;xB6}=NM5^Q2on3$QsE71{#18 z&klYf?QaggED-Pf(a(k=Ax)7_IC7TQfxw1%|71aShwFUmjkd^j-(N@;+VQ7zi>-N^ zr1#e%x;QbEXj8WT5qW^b9(gyXO6*JkJh&{3or^fGNOLGwiEkjPf8+3YvWnpuxdCup z&9Z!o5fYEPbpXSt#wlEUZvsXn%NCa%0wt}c5FM^ZiG%7kOavy?mMbZfvlVpxP5MMb z=mcsKOSY_Xz35I8)$HsS?ZIzI_4$tK=CmQ42`*#RxhbRKnosQ%46y(fO!DE%-On4M zp&^;c3{FAjVe=45*cha#bDUDrq!UV-=;B3*mZM>0vn!sS+*h(Qi691+eOkc|XtwwU zgoAlC5>Ml09_C_ms7S09fuKexBiWZNhdpSx&~S=dH0??s7dM`OUIO9RvmYNKVX7@0 z{opXzmdd6Ev_xxrylr8SI)yU)9`c-5G8hQTtn8J5-D2S`^e!d6E3oe8ZQ9)}AaluB zeHCKMh~`;4{&Q_uZW}o@HC;c!Shnc8kQf!*2wP@pN}+$&kI2g_h}bEz1~tN0F}={v z$g?EW0h!u6QfP<7QBf1M0;7fvNE5u4jw7KdT)Aib-M^=bL;>*DE6IvQ#T1bql?|o zYc$mW6)cpu2Cx)?kCp)l-DIu<>Nd9P>S}W+YoH9YL)E{_~v*5CEL!yuc z-?hc(rCjU~%D5m#WU~-{RZ&Bj0~^>@Fls0^G(kCrO*O<&@BpTMt|2m)VUodTWyrkk zZA2LB68lAiNT7we>Qj|PKm#cJ~mvWVhA#&6mhu4@LtNi#{w}3 zUPhLkywb0O=pC9ilH#q;wOA_RCi0hVCN)1l(?>I{u9DUzg)<&PY0B@@KP!}do6GP z)25Uav8LlM0_lw2?V@2gkUbKc18OrX5vR6JPTpcdrruc?{T#p*83PeUhz6!Y(%WQ- zD%2x5(^@9CSB;Vtj8#tpZy)K%E!OeoybnjB9g}={_!Q@O!co&J=x$9cfrBrNC+moo zt{xLXoXv>NZ}aK+FXMJ+pYQn^XJSyle&9ZHx<43 zLw{K=&^ohkuSNmXplJ z^PoQzn~@!kn(uD6%B-_$lT#j5Xc4H;0P50nDmb#l>%0N0ZQs4l3gdn zYd91Kh`oT}w0mma-4YQLp!yXh4Oz(RR6X$EGL}En?i{o~K`5DFXlV;r&aWz*j@&V} zyq{SfueA3vCiYC=GQP5M;KgV}d_pz)6AXk|kSg#l7&M?(RL<_YUwJAA2t7Kb8csSF znUcbNMfU>u8jT3m#p;y%SU`-?iEn$eVjCeU<6-aQQJ4RL8+9DZyk9_aOCm`G9=qmO ze6E^GFG7dM#RY^*;4!cu9lG0`iaZ^OWMfsU{Z~Y~K{>RbbZvGtZDz6n20@ZfqYPkB zCxHdJ*QP9Ux=uni}v&NQz~09n}0VJE{N&X$Bl#rYt# z5gJP|3Y}a~6RCbEJS*pKbp}R?vlG1&JqRO{Vozj6?7w2)?^8r->UQ5!;q#=N4T<^d zoD$@z%hT28K~1K78iIZnEmj^A0luvPpRu2OmZ@1)pEv~Th=VjC#N;6moz35!SBwn8 zfJU(EzTeU>TSliyQ9-uh4oy47HtMkAH|E8yVT*!exROG|<4w$YIVOLYx3`T`RpS%2_-~M)ad~rf z`_C;O)lXO{u@D+a<3n5R#T8y7Am6|rPy)?qpCaHAdRagM8ySg4pihB2nXOpj%q^2p zG15+uC0~poDB~;1n)uUSJw;GcS2~bkK!3@PFC&+|Di0~qupwReE>DjYyD@_U3+Y;x?mVw9BLl*OAV<64q{_C(pqjAk)1p zYOGpo;gb}@c>th*Qbk4c3h;fNf)Ix}U0O=JxEHtJB`r*ybPD36**4eN`-Sb9y`nUE z&7TMn)6~KOdr3kVvFWLV5aJAIhJt*D4gopIf-?b9@cciO7^tifNrC$E`Q)LifAgkI z8wqspK6S8PibL%6!`TRMQvYrDGOku4igt_dV1>T+#}_uM8!T5A%s9nH%~yi$80u|1%vX- zPfuV~qwp=JXmhB2K^jDWQW(`Ep`4ZCWN)Nm-~kePoBUQz$ypd=>rX|Qdleb)4~-r|O1NuYY3`_Dv&W>?$Z+=( zF3*xr`@L`Tv~-pfH*0h4>)p zwvHZa8zRKJGxx;knw&nf;X4=C>X5oCx>ni%h4Vslxy3z$cZfm;@PUskE) z`z)+D!(O%Gy-B#|m{r|%44C+qc%&C;q$wbIl!MsoGen`rGOtk|yd)W`dePf)?jYu) z6_3x8R~XYyR^W^69A~WF+c6@8d+oW1))SUz$*5O3=pWG>xyCW0#6Tax8}>NtZ~A}{ z$1pJVatT|CV^~FFbkMh#y*d4a^C@L%pT54awLtLLDQ|UXp!HAj`%vGxbA=RAr=Na+ zGVZpBI%^0_mO#2@W**DFc~@~Pf8HEK9viDaUhvPq;@(tI{%$--JU0A}P5l+fsj->K zC*c2jv0?QnqfA7l$SShP&?7`-i3j41KosIz`~l#w7FP4@s&GICjn?U3eqLq_F)Lk)8=ZiM_y?+~fI;Gi)~DSC1={6~oM6*vlv@@{+I zf+}sFF!SiIRR>9#BOH9TpX5j)RWpJ;oKZs&#)1TJ69j?=ohiS=6Grtx!z#6m^=m?e zf1t{8+un8$^=VXbBuM1^18<)C?{*&IJlb>qj8Z}uP~j6voy3-=4+f-T z>|F)VYI-4%c1&YO;dewOm&XtX8CR9eItZZ27Rl+12byYVwV=4Iyh-uB$r~%1`W(PS z0>+q>?fS=aZ14cl&LR2xxdr6$F|1b4US2XFkINKZ(lbPJfHBESP&S%|&P1$fZY@B9 zdvEAFVTWUOMJC=#9>M!uXM6obV8pal{VKUfb_w8+1^t16KMMOS7q{PY#5jvuCA+Tq z4pL>8$E~c5A1tCZOj(jzfui*NoN`vCrylt;otMWg;p)THk7yPl=9MRNtlBxsI|I;D zdnE=%hIe$sVtjqDPQVG02M!WZFf8+i5wYmA#gKEJNkGXv)tdx=8d-r;DJbbx*C1Aa zf%(t}&;1lsfE~kRMkFT+ZOr!ECO(EKik~G4zH_QAe&TOV&Z}urY-q7+$(pC?osL%z zxTJ=$@nL7}c*5EVp$j0zhJ-rl?)^95;%oaU=vi`@1a-^xXQ3e|xJDZC&!21wq?(Kc zbMTS*wwecCw>1pv+EEQDtcpY0Q>Ls{{1*qgvH5K(w=f$+<2C`zM5Wkb;8t>rgznAiLz7t&`OusPz9W`c8SwXC95feb$RP*okBp)s{lmdZNHh-C z#;k0!TvgFqSR_b*eMVyeT50+%qnd1sl#)!U1^&wc7#xT&Rr@!XsR?_YIoRQ0*O7k#&22POt0dY zvC1*v$E4%fFnN`d*l;T&c#xAEo2gTZ9}#)Jfmm9Zpddn%-J{(*i~3Kqbh{}tLzs>7 zY>MI*bdY23V9PDPuocz_$5klNG|dpYUG>^v3=}%lTVmr0@bojz!6VrQP z{2HVFuZD|sw|I9M6BvT>Bveh9VMe=W=(u}AHQyajO`z+?oMb> zNmJe%nGj<>j4G@Evk~4O!q;0-@h-|#O6twsFm6$iRJ;hg*|!20HpsmGIm|askp3u7hZ^pOBvB#qyFZ_NwX@{aOo=xT;P2B+_M$j~eDLXmC%W39zdc`Y2 zQjJRcxX7js_u6mbtZ~T#ik-AuKCPRM-M~<+ItNcSembK({d9|!p+YksI-lGe0w+DL z%|I0wgnyLkQjBNHQjvF|r!JvIejdHhAeo`bi{@=$LAyMDR`J^frj(+>SP?9`F5WY~ zsQ92if20gwNtz|=NZh)J;QUp>wJ2Zk2pH2OvWJ6cBf1A__XQfZ5~+4F1755G10I3I ziH2Ng+WHTzc?BW&iFJ8 z^5Y=(=dZp$7VO>gmLL`_##^B4u3JvSY?c5${DLt*FwVg&&375rcljAs>TQJBwA&36 zhLX5LmzT26DNo=e_7&n~;b-)7=}aisC`X7&#nZjgu2CCvp99ngX|W)blCBKNW`92R zO&H-?0`6g4-x9deWMW1zg;({z!!`ZafZYdz9_6?sp-KF+08@a=KgiYE!ZFF2LbFq) zAH@!dxfc2v$vSi1bk&Ah40bCxj-@}-({ukMaf=v&YL3cr)%U&y2`T7@5F`dJbd1=D zO&UIkhuMqloyIyK?lDPR$P4g1(gx~~xgSq%EHB^QO|^zO6%s2|({&GrDE+AFkrttM zPsrlXQT6e$1nYG>T>T3KKnx4x(L&rbl^5!ftWoW}6zqWI=4~Oq`Cn%${pPxeABRrf zc0Lg+tLgGsp(4Z3D~5cSvg8*57&ThLbpi$!f0MQUS_ChqQZ&oTQl|tkz)4G6vgS;~ zb_rlPmX~Y{{?b4c@ALV)84>hu++S~jjIw8q#tQO;zb=UX7%c6F@(kMlLPVK0q$ichgj=eH{wuj7t ze$;bM|Cn$gBik27a@bl0!4~5hjv%>|Ko|x$oy1d8m#}1EO?eX~aqr2}lp%pFuE8u% zj}ohh#;W)Y4=8XHkz-N=ssUZ$t$r=TiahxRN_Ctj+brIk8v_tgQBOG3VMZstEB}izH}Kh%}P}Uk~NxaLP@nY?&TKo!np za5^mS(w7&BoqaUixe^SMW15=Qnr$e_NxKHLpydXjz4k0xgAQ#5_HS6wL_#! z||8#;mB}R zkiuVTuJw%0Ap9+zF%sNtoOhnQZRwlw&Dx;*X$(agZcR^llsP=S!4T)@=UY95p};XiXIiqHxyIG~T}}2$k9_ z$GaCxk_MY>q2sLkEqAzeTo%#;ZkjW+s0cYnVi{a@-%EZAzy%wK&6oZ`b}U!uRZOE) zY^f8m&N*;MLn*gW*4Hnyz-3yH;bfEH?hq{kBelz7RWiaJI&~eFvc|fscu%Dog)UZ)P(*Z_ zqHdD`EjDj*sF$Y%*2_SdMYudGMl&`{b4C)tf;!OTUJu39(+|sJ(0SC%gAoBA--~QL z@O#7tTv?4WfTpCHvk|!UUZX+FNL+ebi&u$GcwA4Cm&*X1ISF@;cu<)$LW%kMiadG-#)_EJb94A*X{&J&Vn=eHHGMEm z^=K6Feinlwq(dA&J|Svpi<9ICXiN;k+DR$c2s`%oijX323$-YET%Mr0yw=hD@DS09huai#LZHzxB>4yz zVRiLao7~TCQVL}ZebP9t*#avUd$o-ClBXQ(S^7LKjOH#hNg^I*EXnK8!-h87+v*pK zs_OpW5+jz}vxfn=>dNi~U^o_64vZG1^~y!LG@X55&Hd$Nr02Yf=jaPma0U!lM1N|b zTl+-q%IUm6ny=zo>I8rgZ9BmxT*88a7OantDcV73EkLqaTifrK3X|b#=6|4nkVvhs ztW6YOR~BapN*bVrz2YvaX*rvTfvw78MyUQ9wH}3bj=MMGaJ5I@7>%&{X+#`;=$Og{ z8f)8t^u&@-PFSLq&&Dz#Msgtp?wPK{g0@p)S~oXywxnSmjaf|C$x~9rOr#R8b@0*V zpKQvNP>n68o~pA*?sCdStPDX5-_|j_{PT%}R+HEPxR06m-@}I4b@!&oqyE4}L+T=D%yh|iSq zmyTq%;_wU@doIB#tMq!Wr9`cKUar%Y3Vr{d(fa?%TmBb0OhRKZnW)wDl>8wMDWWAG z|3g?iY%!c15Y3tE6~a=7v?vivhHFW6gv1-?;Fy`4Z{JS@h&Bx~($IF1+5@M}Zg&TY zd#;u^MoRw7DG;Lv@g?1X{##v*dwoK`2_2wJAD8HrDZ^jbm)UZBlJ63#-r6>M#51*P zVS9l2TIvr;BHxJ79+sRTbHWNTZZuDGg`MbLG#^e*&9G)#kHg_18v&V?-tcjPatj%~r?eO+snfJzf^ak&Lisl__m<0Qq^q zv5pAnGAS9cxKfqXeh7e!?cO*fz=nv#B-tD3tXD(>lXh1D%KjjFG?eEkZU7sVRl+K^ zCt)J7)A-&xYEtc(FYXAocPB`MxyDb=Q?@lg-`}Rk#E|VLQc%dxzGAZLOv@2{-W}@# z1>1w=BoAE1YsM>OjcJ63s)N-|wz|=Z#*pqOu3SN34KYc}%x+;MPD0nk_Dz_I1DEe{ zElL8mML7g3e9h!JXO$9G8}`zbxii>{>YR%Otn9nvD=HNz(bC7XxJ;z>p-!4ZFRB+T z|L%uR#&cN<3zV=F1}WezCSox6X@ixH3osgcx(k%T#z{P2rT3YWLR{2I#km9BRf=-r z@KF?ZgRdWhafB&-b!b7LP5;3+MZltpY>=}R>x9s}KQ=K%HfxHgeW#|B--|soBXzU} z9UJFeV=oapCA2rI@K=W4JdjM>SSL#UBxwxPgfA8GHgx(ItF;w0&^FK7bvtVRI*M}M{Rpn;p5diIr*s9DTj5_(+4 z__QU-eNuWu)z}hwNk+TY1exR6$J_&j(Ze-Ok2q6)&ke_bx&-a;3er=pIKWc|u$*tU z_S^<|TrMxmRKSQ@h-X?BmJuA2?Tf_d=L52GH*JD(@KmsvQWB~#x~1Or@vChjF-}`} zEezqb+(F5R=5_|l$lV1HR+O4ZOswhZvsy;7uY%2H)REuk!z8q)Z$8enGr+LQILO1 zm$zwA!gn|1*zbbGmfB8$L%&8`?Fr}>0~s!N;`h|lyp-E3O%?ru0^eqHqOY_h^myL!&H-8S@y=A zyevpfQ%E=Ed`>0GBw|2e!A#wa2hV^`hdlPnOU7}n`C4P;-{kfwB@;IJ)pc5YhxVrl<%{aK!ioAEJ<>boWg`bM;LM^&IHxGBRMnvr`Vv0C>(94 z_Eu=9k(Zar72(4rjQEGNGGMx7xRDXAkRl(6X)`aE5MGt z2lh!_pOGH9%B@()Se(ER(|(u-RI>fVdzhApS+~bTnm=KNg_>^o!ZJEWoEzM3d3|rT z{e8TFa02!By2V9sX6*}$sQP0hYwon2*;_ftnx==Vnz}&$tl`4@03S z^675WXFyMg%l{*lhf&x{K7OC(eBUj&hd)EYg8LkWuoLsQ7M)wRzE-$sT^?% zisMnrVyI`7!@VHLvv6uaL&>3PYv%1^=bY5zH{`HNFtdTMkkz%SvygUknp8ELl(p)u zFQSc=ZRcU)fH^HsQ=WjNbN2*hOXPHGa@=RO(S{3J!mVG+prb_r+GE<`4&xqvgH|9L zrtd43=G?M`=&>%taK)3pV_t+^+>LJkGo&n|dil#}E;595ox(NVovxqQ(F{|B@}CXo z<`v_rrNeKpQJT06Gr%58S~=-zF&Q>QhSaklVX^48W>r4Zo|)|;C>Pck+!9z8I+Wk> zCs==J>Y@|*kH0~{)ud6>S;ftzE#ge=rXFvvGRO+GRecX{sqFkiF?O9W=c9u)y)e`j zHN8&|)#7#KAvS;As2$D9MleNDub}dd9q9;)ebxUc21?-2M3I%o?4U8v_=W= z$y-h#Lcb;MhSn3-F~?o4T&vY^D8tQX|2Ri~ua2vBGWRSF3!Ka?I)*Nx1ulhXR+85o zu-Fhq4qxrX8e}6yXQf5+9_Gz3LRzP3=BU(?J|&?j`&)P$o2y%6%G5LwjQzsanABiA zG7o+hKx(|hMQ>i7Xv1tWCoLfy@n9&St;a)vfw$D4+=}!3w`13L#ZSWLB6HIGPhv<6 z#eS5fjmX4u$$n!2K5Zbms;agX{++z{x6ZO)$a~@YG>8W0Nzc)&&X06rF>noa=9oDn z{v!1ziK1DJ1PXR+v)D2IVXaDqqUNA#FaBFxg{JE@udQIaU>rxcY1Uq=y$uk#spM8G(m7)3Q8>^Ss0#5p=wW)|sqLWnF#%J;V&CzUrgih&2?EOQhBS)E&?(2B_7 zWC-@vw5I~*XZJ79eV(#vUIUM*M)DPIc7o>2b*$KW*YKdVI1N7tM0=+ip|)E8UxuBg z%8jiVwhYvU%9bnKc=DB$r^++4q?($igGySO1N~&ucbGWol;>L-6B$@_ZCQUZT$pg0%^b|gR;UFTT`ie{Y^Oa zhrqZ;2u9^w^?ggnF3Ji`s0IfM8%3ZHLH^!>Q_0mh5VUbUsgrkm1jFvDK3{jt5f)0L z<1zo}GrfzVRFTp*I^F{6tT|pc;6|b<|LHw+offBeL{2|hD{f2I^qggeXIgHWQs4f+ zNPq(%L5rjB!ZJvF-WeP1zU(rgl>*M}C4Q;xcd7G1U~AORCCVX{Fz%?v8j|eTWfo?( zhvX_v7Ep_YAjhy!sIZ;NG)?Tub6A5i8Jf;^JuZ*vQK}{_C5Vy0wI$xtGn?J^P{TFH zN`4dWOcog<&Q@lcih^nkWnBkl*A?o;vMl%N5LODDwV7n)kiyWa(G_Zl_lt{i4(b)m zadBmH`tlA#b%?t59O;v@3J=}AY;OrAtpl{Wkze z5s{=j3lpvgb#zg)+noeUXquX2CIm&ItE7yRnX3oPaW03uWTZqpHRlfeSImEq(Ot|T zm1b%8Mu1jJ2o%u7Ji@$^@HFst#E@L3m?{HLJF#Wdg^}Jo(%Sd<2G}93H~l9&Va&ji zq%!ZD1lO4w{LgogJGLJ`xg^SqHzqUwO&|HvYQV7^wJB+~!6}%@I{B^cxmU}1E+Ml1 zHTlvC{o5(3_>1P(e41u(YMnXATo{f*WqcUpUKC}--w2bK)B>s&S9`0T|92L^+L~<= z7O`e?vSsbZKW!3{GtRh&$CtT1HRf<8&$eztcNx#L0F7-@;nK(zq7oCT!m>dxL2Igx zu!qg;qN4D9ivBo>vl~_caU*l093go7pTpG^yq>^cv%6YE`(mgN^Oy$BeuwVS<&SI+Y!U z+NEP7-n2CBGtuo)tg)jAA89apyLdH>+QK;uk|1our(RGGRzi*SKv2EMdj&0kv?Z&okd&g{J+qUhrNt3htJnwtX z`H&CUYp<2Ha?d^2fBrMqZ`|$B%e|zFI*kmgt=x55tArMGF_|k>!px$B#nOGs{c6z3 zq{NJ^YhX(plEU8)ywIBju7I!4Kd$MqCi%hzkWg^XCGUiLr>D*+X88Q#S{$gBZx&BG zhG+xh!Pac9e2OwhXd9$N{rm!RZJfW_Tc2J^oiC)^klL31vW2}a9>fST0;WS!z#02w0e6u_=RAwTOq0s)^Jgqg?XFSt)+l;~p&~L9+BtXq z_RuEaHssUL*L2HVIUb(g0onc*ebvixqq%$Sr;7DUWSnqf^j4WksM;x|MLXJtDWr4k z_rhUa8-<#vtD?roMyr!_fGWony-;>AtFMIj9JU@rVwHmYnNRq2T~|pjH|KWYcsl& z>2dl~?UEHWp!5qIceHcthfQYJE{nvdW`D7_OR_ijJzO_fNP>{|{CFAK$TWpkt4y44 z+#aK{jz!7?E_YkKFbot;{k2M8vAu3eoj%RX37p13=PjX=wd*(9GSeT~GzhWYRLWza zCBYCA)w0wjzmsRFR=y2t*8|Sw7MGgnl1-LD_wWhbs7FSVU3F#QrgK#E99GsF6n@4W zj!(f@(T2c7f76FnwU<)Jjvfh)4O%j6w^MY9q$SJ6MC(*Cn<&oUtvQG@*+-S44DQ5N zRn+>5zRI5hKC5LZ*W^Uy{3|#!kOp9*;4_RUl@qvN6kZb`T|%dYU)RO@CR~#RXROxL z#JX?TIyU?#riN*gYs<8ly&M-a27{V&7#F~|X%3K4+=4L*4h_Ozy^`zTJU7ZURpNjT zf)$Y_I$efphP$%r_m0vx0jCkc)w>lCTv9p>Exv|QtwUNymFtfU9up3$yX~9ECQ#4l zAi+^Pl|m3!v@dBu`QI{zU=LKr@C7B>h3+vShb>MUca<>|-g|3lbQ!>7tbrPS~z(dCFGNbkda9vwXLfC!t};Am+h4ChrnIS$5j3r-i(#VLwq^5nF`a{AGSQb)+{wW)~}CVZ3my# zSVu0Mz=V`OGeW8VUyVC_otDQC`DQRK!NqfBTs!!DBDxL~xN)lF-3L{?p$jq9DSzGb zb3alhhg{XB8?L`CwJxs89+1c|PGcwE4)AhXjV0l;9?vKc9zE%>`n%rRkr+|qlDE-E zn+-LJIV!?qZKS9|ObirWI~Q#X{$DSbhUwwt*u z>Kh{9dmsy7-qoKw*^Hzlz^I^+j4DD{3C`2-B)`+%NB1P2?V!x^{G(tM0xznlzV~KE zZn=}@NQuO;2Tibry(=P;VF_io1cn*v&VtF#zpAb14lzfTFlq@l#8dIc9L}r9vB0gZ zS@K9$W#7FAwv?gUrtKon!E=~OF`p*X`OAB3X*$6RWq#B^*cE=y-7xOt$5CU|Afwn@kd-@Lvb- zbICYqTRI__$L?X+ia+03t0O58SSKA5ztdakV*e{+Kxfe{UmtDKWghaPs47UK5ZVev zBeRpHI~((UiLuR2v?~m;NrIxO!E{v<(!r3tz*^(zGVh-BpUUlnnph;K0)X?GNyLxo z;*FE*4$ZnH^e?1A@S4jOfibJcPezzd=`TxssjPcF&V6W4D^{Id8|`oY1C**UHAekI z(;R2UVLT$sRTeD9p|9FSCS>6ro;L|DM1nNBiA%vjY;ztrBhB%nwEorEXH>sUL5bG? zbn`)1I?U)5PC*78l(@>sppLj#vK+fKPi`pFy}a9}?t~DH@H+MOYIZZvoG1-W5~qn*){}yZM!Mq?#)Cup z4k+RB^(?NWgaCoQ1xn;UPEPI8K-P!7N+;9DILDo&XPe8e=`DJQ}CXS1%n3qfcaU@6?%qkB6Gt z+P}#gbNx2S@ckZx|z%4w*xu&rpg%=Zbt7y275+7olm zQdCABZFYRQ#-vRm66;7uTa%8b>K8Z8ke)=0pZcKq7IJWN0dj#(vvay05*T^wNjC?H z*4c3}E#BkP^F-O7dc?n>_>_@^e~V0-6vIo^GdT43Vta zw0Vy9PtMs*+dhn=S!Gl4b{4uCKuSi+V^4P4j>%XLsg$A0Ax>k@zKgNvJptJ$iH|>i z(&>w-V=cFqO#%f=AW$@<^B-W3YxJ~Yb?fnNEOkMJlh zzIOhZj9b1bLr&4OD+pQ&$IY$Bui1X845z~oTkX5sRIA3#tz2gn z9OOqzXem|@LxPHJXx4@OcVc^%irrAIyudp3Zr!t6hlkT zaY!y2ay`9NjHZJ3`v0q7)L-on%*5Qkf|w^CF;i1hM+g6|Jifoie{%g}R{ee~7nmv+ z_-pkK4)Kt`DNaYzy6Ac~0>ALlSG<}ewjh3-v6i9p`@2`oSgw^VSQ&L86nY)KRzq#s zglZ^^n8vZ7V%!GsS7kyuZzHt0=68xmkQ>_HVL5rR@}jvK;e~(qzW3cpnVHwB(cNkC z=p#bH2NHlssOTkkq}HJ6iONs8c!{u>^LF$jxhNDZuXk*2UYTdAGxI^yIlfZnb;tgl z@?KhH1%?_tF$+;el)%~i4k@>yp?kYAL3>a(`I7ctqJOHd;X0uM>Oy4eIu2XKdkQf( z9y`shNPTMHigX-*Xs&30F1k`CwhgSNK-=g^OYc07ds?qM@(l~oW=S32Skf|XC zFp;YzK7_BKcYWd)XBw{2hWKTaW+3%}a+8ls;jv9`yiJ~ZT7zuld#;!2QT8ZfpJlzo zg|?)0`y%&I+16pR<=twjU++UFZAN5K%cr1Lj7>P*6^r%6+pdHq4}OCbkrim7F-ZHu zl_-egxm`;!!Vb(0MRn_NP^AX8Doz3;h{rCX7H+3)_1?8<_o3FCAQ$>rZBU+Nh?oi* z0^^U^g6=Y`c4tWi8|MfvVEfA0PavlaDB{#6asx4TWg2{^Eo^Hoo=$(3xBt;TqV6GH zLO(4~t(9A(Z~#8+lHYS-%%QF}7SB}xQCK#rH1HJU_n@J!|e ztzu>Ax}k8HpAN^uTeWC;yboXTRSKF-+<$@(KZITRhyu&1?@JNgiL#s_AocK#7ij7` zH0qobpVQ8uEVgA&AXbtEp+4h#2zL+9;B_}hFsB@qC?utYI&a3NgXti2462>P4NW33 zQPjM0oHu_KWGq9sZGOiX8yG{@@t#ky!K!OR@MPG4PBird8DBXu8;haCjBG_H5z1H5)aVF@Z3gU?`Y43rsTXZL}hT+IwslO2g`C`*Ze~xTa!*mRZKA zBabcYU0X4Kjd19oajdZyHG6(s!%ywmhWlJxD00#mAGZ4+{n)OSudLaBbdUF>W7Z-{ zYPD-{YG8&sNpx#Zs%rg}d8@mGEc2wIDfq1jCm%)?nGS;omQWrNeN`4yrm#|eR|%+)E?_aT-4^G3JmIVz6fG%M$# zzH1^kdE!->C6}^2Im5Do$t7d+LQ&tqu-Qxrs~M=;B5VnX3(-VF!Iu!B{R4*CGZdhE`*oe>#5Gd^=QCaqcswMG|I34}2Fdun6kJ zZzZ*sjO%y5O~`@5&>@I3v3FngdOF@qI!tS|dQ>SC9Do`bx{jEq(e5qqMgfdsheRsk;_m;=Gye{(&-40^ zC|FDeM^DdDh4(>)+kaRiasy0ZqCtU={6h(WKT7{dOklUG7Y7Y&aZp1D`YayIxYomq zrJ!dUS(Cuk>D*|Gz}v)Ndj{QsxUIFZ2$L_g&nyU>4Ds6)sDU~xtj6pMK8K4hfxN6_ zXSm97ZecwfHbvcO?KV0f0QD4T8Pe&^Qdd&+nOmsE7c~!oLbg+;i~7uTI+GVrcKwE1 zWqC|M`j3ZLPGfoUIjr|b*&{g7aZ`dhGDs-M=qW*6;k=q(X9e0(qs&aO41>l0UZq)* za9!^ox#@5h9480Jyj#@bI^xL~&;C(#5N3o?@X-!hRAg@p3>v&5b!3!Oc&OPSnp{ds z-b1tQTovA~YVu;1;K71b;ck{aI+`L{mQ>`qTiDV(^7kA-n2%NG-E1-l$4FS28yHiH zxy)aaLhul3*o^|Gz^z;*MARJU^Fu8yFu9~44KNS!L-RZy}Ifmc(50d zWpeH{h%~j+{T&s&LQC|;6wWnhDSs)(Wx|eGj0SF`G=-MXWxMQ#w^HoUE?E-29h=$o5tO-}qX~LdilY*IF3`zF_KqoeQbD73wom3XIhlwyH`iJF6=3o?Wkb&NY98+_6h7 zecZfl{Ew9f^J#Dg%t8YpguuRRY;63aiyc%O{H5XL<=y-lK=|YB<)*2p=P%>>a^{V@ z^+GA;GD${$DT?P9=)YLyGwF9*E{)eS91q)2Xg;YoIZ7U*+rKErNZe*5VE=nA2_3wn zfS$&?$WUa;%j6zRVEs48=fskL8Ew}6`&fzesO@AOfy-JBT`hVYb%kQT32yPJ z(45K7Q=^^&2aLmI#}to>oMGbM$;m4X?OS5%L8hmYVFX6F_vBv)%TBXhfeC`MbVJeW zjNl(`x-Rs5`#I3;{mT((<5!B)N1U{5VFRy{M@{fR_Hi* zWN^VLNiZh|Uh#-cyj(D__8tkBgV$bVG0T(J#9xSQIkaFo51Ey5;CB_S8VjHObh+JV z1Duj+l_iT6ZqkJqQF_Fz_%R7pS0Ek5NTJ=NET9Nu!Zn-+TEvb6eh76AOSDdZJ@5O3 zJI~1x&{J4yq&wGhFrS-*A<%FZYt99fuO3cEr%qXAdr2_0;OSHyj-6}9;?@;PY zgeN$h3YZdnn`K9bWuTJNz0A~UpK(J|mJTuqgqGl~Tjd~rca~U7MfH*xXvi{JUU$nl z-Q=eI&9CTqkssO9`PT?N{PdlC6L`h6eWLs5~t#*gtItVxfx%r>l$=+$us5R$qgGjo-RQ-dR3dfP{^ zCtRbks_>LlWf|_I+Zm@LX)w5vDyVLZJPouLO3sPDt zDuv}xou2(}ro!`2>w-F0n#(f%50l2}^_!j%mL#W}PlG0y`*qe*y$qG8O#Q{U2#j=4 zXNfI>M;2rZbZaA0Lm)G#mXI+FEiO||Qf;WzGy*M;_Kex~SD$%&72{nf7-ib0_yzY( z@4X$v2<3!JgaaLU2rkM3+dR5F=USh&);V(%aoVN-vX1#U*rl9zikr(>)UL?$ea$+D zr;HiJoC@-&JzQx>=M{44;cfGTcffSt5fp2zR9Ih>W7&9~SdB41~Ol zcDS5=J?su4KOzRQ8j!9)5X$v9vMkW?9DsCLMJt?=2}wE7n|=l#YN#(>Gn6FBSK;_w z|8UQ(W(3<#Z+3xu8WzT4RCjRc8QP-`ZgkkD9jj=;kei8h781F*Hbp4Qh3QP$OGvF! z(6>hrDt?Qh5t11QGu{;4ub5Q>QDmRDU<5TY+0U-({!JeC7?ZDSr)}o5`OUS7N0Hra zvz8*>TOKsT%&i$UlU=M1bBG2y)Qk8KRWAv--ZiJcJ2JN?*;KF^AUY_!F`{b z@{h(-X?;IHOjnDxqrmP)GAt!VXsgf?T1=TBH;!Kzm*7HoZu&_bP^7lE(|;mL?viQf zA}fOQ3aR}wx;(868W@%RNR1M?)`3LG?5P^>M}2PNZqZUS2nt=Y^BE3107Uf$AFI&| z&TA)nzA|zdn)YW7&`yq>pAGkkKSbizTE8m z{EfM68GW}?iB%+09)Q#K*}_$g$T$(sJ!x`iQZGh{-7{8fHi_JZhtvgm-Uk$*rVRU` zLloND!139*ew*`*Ac7O+sf9q6|Ecd?(^&ahEB_)<$eskkSQ-&(j65fJNU9j-HE6742I59HB(2Y}gy;!)w zOU3u@+#Q=^C@x0$vj;H^Lz7)_61(G0JUc!gk0E=I;YG051H~yg54n%4HQr0fhn7)U zZXbCB6Ic^uCTd}fEfxm%v3+MlC-8pk@DThL7fy9q^fXj78J=APrmZ_}uu2#nD&PVm z8e$j=NOu6z+V5xiAJjkJx_-ij6mBZ`-zWQCnh+jNCun!c4`d#j^|0toKQxCYfxc`u%A2;i1 zFMR>9fv)2HEY7v*RB7TN#EeJyE|96w>HHgYlWViA6dZeN#_6J}SVrl!28`R{Bs3&J zZ64Pq;;o?~43Rghtsvhx087s}VD$js;e#W6fjCv={qGrh9wXe6(f9`}?xMQW?3I$w zSm-jyRe);u2$C72PM>sKJ9KB~K9-S)clsR0IO`SVQdmRw#IDjEKnx2AfzO-ZQEF!u zUVarlSjf5)K{mtGj*YT}B0K7XE*-;W@M7T|*}>Bzt!H=G?u>p4(pOG6V#ZvN04(pE zWR7ugKEQvYgS@UumKjPr_S$&&@3clnp*lxk#Z_sC9B{-}yIsD*#L}P!wO+N*AO3t0 zB=d-=2jb<~soSEt@^HIgA1FLJ|Jl(BjHd60UQ{*ONLyZyQ65?Yr=|$7cI)PKbinbD=N;0`+}xbU+wFgP zZTcLZYYAHcc9MHo9ClWv8j?ZdK4FHOP$knaQsj?G8CU1bdL5Q2qfrN)6HZH@E?|O= z+|J>|(ZNcaJ!A2RaGpc+qn2<4;oI>mVCT;=`u6)D-1qXng~FVEnL3J*$yU_7Zs)vm zd5;WCWX>>LIt=8QQTp!Wl3Fl3I+g6(t9Jm(OlRIg68Q|iebT1NqXSO};?Z{~sy|7V z>u`4LUS(=BVS`_ABkC~0l6kwWBh*j6W-7;mQD#@rW(Cxy$Bbi)G;v7tR25+$n&lKta?>Ys3dvfK6B~_BkE$;$VGUddYqP4*I#N#>UEi;M z93T&g3vx1#c$#rXjy~n=*&)^0t^7BeVC(l5vx+mZ?@Ox7QJwT$1a6uaW@uMYRmF`I z2_}2LhWZY&@Mu*L<`#>k`%HJKSMY|+E9UV5C%3{x-43=;h;-;Y;qz>EHaNF|v)<6& z*TGvw2-GP3Vdfm1NELV)mT?w##%e#wEZUxv`mJ*?ZA)3r)h7FDCW!QiLQbp$Mon`4 zu61=y-lyQtVIh{pr>>tf2)8@N2=B0jJ=Z%6YGq=8ho!_()*#oRh|QC+eU^~bN}pO% z^nYgoC@(JR##yy7CD(;gJo7mPr zwT%V%_>TT%BoKTH0D|1+f1KqX$A6s0_u9PqfZ|4H`#$Yv-Tzg4nyfe_c(7#`HIpoL8!9ljdNbW1)nLFs#Q=pPy8bWsI{xJ)QPbWXWa@GsVU*?^*7z z4UuZq{b{Hm`!fV?qpH8!TtYf#qHDCKJR=VBB`yN!QuUMj@LluNN5zDDz_3*&5P9Zn z#zw@tOml0BJaZHCh4=I#Ma)G?uf8Lt0U`#f3gnSO$Zt?3{q%0hb? zR}4VKmd+GP&n*{u19C+uCBG_K7kg34A#dEDI=D&tpVJ|Y50QkhM5T)W2`%l zyK)@>bRX2HR$SoJvV-{MdI;D0 z?T&%G9@mbb)OFrz4j^c1Y;5%XfMfi~{I4;gUue35nkGBr+hiegj}f>Zv&ugBRqO~| zIwUEW9=~jGraRPQ;%WGR7VC)Gn~?%1+{`A|%bq~@c=(8(<2$SS2578C6lUfj*^R+< z_;Tvcs?j8_K|rz|E5gLfRDmuDjdqo#_8Nw&{(=VVAMd_u@9;~5YbTrTX~)Gq%k9F} zq#?HBvoY=@`@q>a-w74l+k*WIG5yghdPgO!)^XX0(5iI{D~KST)WhIe_fluVC|p~c zv$Ym|hVU^Wq~HE2E**a3D@PEZ7)^1N+|ycBr1kY_9kxolzdeSgjK_J>ZnNw-PQNn-cqBQ`AKSz+f2kT&kqN zf!;@!yl@m&d>Ld}+NbN6W&AaXZ^oG-F{{at0xx3cJqKX;s~o!QMRYgTSb|5zlAol& ze%3okt*KkZ9Gv6t5QmnR#?XMEljVv#MXgy-*!?E3!Q~Jm_D@~UINzB9xm{1VRo6M76n-`I#siE4Ac*oULUUES01m@>C3V=}DZ{h(-I zd+x`zKM_0dJ|olO!Djbo;;!oW)iVYMatin;V|qq(++K66Hlydua`MD}l&HE;2bx*~ z442e4oQ+tKxysCGH3X>HSATQmWMLBzjp`LU#7pR}iK;WY5#$DHW znE}dk;w08An2Edtv1=4N-9E&oee!Tc7@h}xTnUOZ=-w2GW-3S3eXV#T3$kLc2GTjt zDLn;QFqkBRDYobKyacSMa&dKr-m`^mtR}!>sW^5eQ~`GkQVL&7<>-+-%S)|nc4=o+ zCHL=)B4v$LLF0ANNIqqlhRM5-2!pLs4h?%2=c+`uk^m+xNjD}Hg^RrYNi_3g>Sdyz zyQ@9U{qi;#`@`LbL>GxwQ4e<+?8(G;&8o=rh)F?Glex)*p&R%KLp4yW6o!=43m zPMtjdG2Zeb$SIYD0o8pU+AsAhz58Q^jQQy15S$%oViYu=Sf8tV=r~WDKjcY^k3I9@oaQZ&4 zv*G-M^?%pv@BTq6<9!cFzkq%S_bdXQEjs-F@_<%k06u z|A~jcMe5*xClg4zNyhBY*x%gp1IL9gGbYob>_M|7#fN!({J7>aqM=VoFk;svIq5Z- z+y|XQ<^Yq~eAX>F#SS8FXw>IUN2Ak-S;aC;0xjsOxMR~=u|(|czppB~9F#G(7lD33 z1#J0pjMRG>>lmdgSW3x0a^?d+v=vTlv#3v|A|}PC@Vf3YK(o=UY>bCPO=E+1VSPAdNxuTWREU~TGrG=B(S{x_{qL`WV$Fs1DWmU!EdNN2pXEYlI_^! zDRnFi>uAV2k+@h@E+mOok^349bxz+e(pF{-y(xqiMMe@IkFOb+VP%T{-YFSh9}Lkq ziQ6T3m1yQNp!}oy8x5zdDsJNPs_Fqo;n!GmkGo2VRARTj%!K(_R|BGKfKjTC>XK*3 zMH5Px<8~-4vfljnuf6huYJso4T<4dQ9(EW)dsn?kb!&6QDEh2NdrvCsWtzi@EpB~! zyt}xRCteGw8e_br+A1dd6s!RuXT&=VJ+lunRxsy!>{ci`xXT1FhYX0lD zf9qa)Y3rT-b$<4Cc=Z!aHDIGj;rPbNgs$i!i4)PmwU~glX2JuR3L1L@XdUTTN)ML4 zh~cKDI+rVc-s#SHIy?JodlUy2%Z-gCZdg#U&4H7LHbG-1>?E~g`DX`jX|!Ww&OCZ3 zs>;;(C=x@#llm9rCfUx~Et!kd+Uts1cyg=rLaALy`M|m$foES9VVDtmKLXZZ%XQN( z4hYEpFp^+a2xftswWu=Nb82Nz6eSin>d1;LZNtc?pu($L-PQrn1|;pyK^`eGdeC^i zjE1(MX9a2@a49&w|=>CLlS`%F3JqWkTSJ7U_ zz4<;=P5?UEqb^pUu8_tLMv%Qp8Y3k*Mu;a0aCioQfPGoNC6~Ynw}p^r!7)Aa>*c-f zQ69~2lWa&9jD1UBT3)93jjK*v=s-8jE(AWz3@f5mARMx;yvP>Jn;rf)AdM~R!eubu zAWarUobV=+DG_)t(E}I#o z)9o+M191`AVij{qb97Llnu3c{F+TP=5iZlUx)xVY1~&TQ#3v;hkPIWwEDkGvy=!s5 zeB6FbwZM|h{I;Scg)WK4f0H~3`F#19co%4ipPd0!Up*pMnMLM?_em6YG7Qcuof;b4 z0Z!iGGxq$)sju9_(sf~&ShS~}tUMnv!N17;0gTHzK^p?QuDTY!+LZp+sBZL$XeBxc zb~rqo-tUw;;dte81nw);F!6No?Y(||10(R4O(AR?qryn?L-(FFNhANME7e~MZVSn~ zA}1@y-hnV!62{DiArD2MeGSx2W*h4yac~D=>u`1Eo~Fis)MBgmAYS%K7sK`>AT?go zB|Nx){*-4z(%dUMjYYiLLe_bLeu0G4?Q#l33!@x527+ns0VNCuNs?cz8mC3W*?LkG z)oou*>RvJJf5?y6`iP`7;HBD~(}+ZdsnDGG&x%cGXt{ioNyE^ZCT#!n=)ZQwNq4J4=0W6EH|Bh7SCfyed)z0ipZ8 z6v0}UAmen8qf51eK}$F`(xJPh_t>Q0ndl#Xhs1RMeg)gTSOAlLXXC5E!`ywfZK1}h z>md83BBmrO;I-egn|1xT_Q0-6=-0)Nnk{+63_4AC5j14mO#2q#WG7coNNPZwtB@_} z?LbZ+W+vSV7xyDX@8?XhZ}b8%6fI0ZpljmqiO#op(r#=vSk8iUdstv_QWs}@`vSm3 z0MAjkIV0`sni71fR82F$&r`66_IM?a#35LXp=wfeSS+*le|kocKM={+T3pw#85)jCS^xg2jN`%ZA3T=dr><}w>-o*u)g)M8D&Anh%;wjnAkTnRCqzOC9!_| ze!7_xsJP?Y!gZybp5Y=GQhd!(u-Vn}_j=RA>qAD%FLc<$VM!<+(K5-9r~_MR$D%EyYXxIZ4&hr74ZARKJW=C8 zaj<@%st<)Vt=sR{{S8m&E%X5|Ka~43CiinvIJSkU4I3(`(M%gN#SO}*4$HXF;7cmc zepS@(UO@RU!=kJHX1Qa@%F#8BD^YqqW%W>OWbO(=*9~a=Wc09;78oH92vc0>8ZBdjwOEq?F9Jx5Drpnqz-k#v|vXuYk&RE5x z@Zk3Grzd;W|3|G271>^9f7C=-MOK&;(!<|j3LfD5k^VSk9l(N-ppyimF|;M9`*v1) zR=~Q^rFf#}b#^ENJKrdktH>H`y864ynQyfTDt$6ELllqC-WNLv65I77z@#$rT)!}^DL_61oOxIdVV5S#0+Gm968c%{gb5H=EG4KltieGs zCROWLvYtQ3h?-}5F*skU>iWPlVwDU@nSClv;vH9ldtkyBEsz%CXMvC8ViS>3-3X-- zp@cCFV+fG2H)C$2I}JVOb%@VSRy_!Os%heYdf|bsBX>MPsB-LR(|6a3?NUq<<9^wk zw!jgZ&g9f6Li;tjr!vyZOkfs|sY zXz?UgEOI34k8E0j0ty!fngDEvvLBfUpll$DA?qqx1um=wyjH06>WC(7BIxUGscDX~ zUnAlqIAGb=-ZUG*rORHg`>tmnTK+1mGM#!+2^}darLcmf4qZ$`!b#Be@nhaQMV)!+ ztH*}LH(-&$(&}AUO(pe6m7k6ef-olSSlK(R4#ZdqB4sJDe`-hU$;64m9ae7ONg3o1WKuGm(t_)Jrrj zC#sqf_Ijk5e))*5N@a!MRO{0?1uPP2nEu+dLpg$7V9-YNAFD^t$97QS@<&f2>2AOJ zS4-`Lv1F9GeBlSpz;f=6s~Ub(RYv%r)38F>G4~GA2(2r{*fZ5Twu)i~t&@h<;O*sI zLno=owB;M}JcO~*rhAQK&xPdvy~}yW$;xX=0gNqE#~KUZ&EA#OdD%A)(Z1w46>lHu z?0m3&KEHV+;Bs$2BwXEKQz+;h*8XPJh%3=KO3}mDS=79%zy3M7(^_`@#~-IlIOa4@OSTF~yl(@Ka4pfG^l_Y=j$lkzlxU|@g; z@tK7(+leV5s(=%vmYi|{9iqKR#inOrIXLlT1Gc$uQ*!ppT{+V@HIyn0o$yKKAUVJ} zPy5=>UV!}#-{D-lbhf!0n-z6es%^18q_B_$hozXp#kVlM6ef|1JI$_4O_BsQFZE(m zp^aNw=Uw;>*#v*?Ue{?ji&N`b#pp!3zKA7C;x|R_tg5(k-jWq0^>EbDh5ehzvq+n$ zowSrb#GnoM_@aa?daJ$>AJ=6oH|)9Y85|ZRGX_>FG7HD$pE%Q}>h=4Ue1(l1xpP?y z;!eVSxx?-)S;JJ)1O^H?&rhpPRnyF5ZI?C8vPamHV+i2IXifA_m^XLq2@2Y_#8j{v zxB3S#RfImpgf@DfAfUNYCJ}$WgGFw@%7m_(qgMLqs-8>Vug>Gnq1%n<5YDt$RFO4R z8H0K?MRvNm%96W9q8Kx0qA}jMU+Hc#>?jrXg6>nKihum92&6T;f3pJ{e&J!#8*AN4 zU*)*56F2eaUjfV+2^z6utSaETa!D0P_E%6vL#t^Kh`Mrq&sJnK8t65;U?L>2Xx|MiQD&&yS@CC+TaJ7l#l*;D2uyVV z8McmWR>;*!16t9PJqWzD%v-=|onpQD@e_^KoiZa1RtiO_yaHBfss|Yo zjdE<=ft~>*ya(z&bTA_v%EcvP|8zJ3EQyvg(&MbUvvLba-5d^^RDt`uI;VRl42Vgt zqFNFH!KZ8uzJ#SCOmjP|RMb(;M`Jl0qr%av$rX_1XzTDSacm$h#^taNzS3pyg@kR7 z&_7*>oGVS++YQRIQ7rKX=SI92#m<7A{e6to`9~B0^#}6d`BO|+`rr1ue@q0#8vGDS z(#l_O^1DXv!DB#qcxAZI8}?%U>>5I54xZ4Ue?$J#NaN+cUFg!Hz$**NL$p}TbI7b$ z>pjxd$D(ZJMWmdsX1aOx{V3x}{#v9c=si`#UUR>QJga{W$V|cJWg_ed@D)@5iV6geIOgP=Ckx}szar48^z6)Glvt|q) zE_`8jj@9Zk*X0iRqSIcbr}Trf2f!!(S5LZ@_e0nqFZ*Q;WAH7qUb7uXUlFO+ch7Ao z8Y6WgHsq@r5r10>{4u|A-=QGrz5S3xg2TI`zj(M}<&?Dm8|Bcet4r70rc-Ndf`H@K z2L@aPC5uPzvytFozb_Uk2P?%1O6X}w7Q#^B{Gv5kzF?&xy$c~$Cr?cstQt(t>KwQ7 zVx{2OudziMk9q;xZD-p%^VlF&MG0ZJc(0TAW6ifH$`o2^Rb^wNNLphTmfw{g7qGk1 z*b2CF5n7$UD1qWB3B-upUYj7QbuX5eq$H99#OY6 z5UCW9KI{`4{O?1j2EFYXOdO50@xS(?qrP03YI*jJ(4MNfQ3QvS^{T>QN*67Hb_*yQ zi0gvxQO~N#Rwoo&MOUf5AGZ+B-Xrc8R;^Pc)% zq)bE-eWM{e@nd0u;^GQgrvg5jip=O?%c$ebfv+m^yH>R}U_(gV3FZak=sVtP4=j zP`nC1I&=~=hW_GT6W)bEcX&|%F4L$HgmEg0@`%<_Eb~l%ocRlAtfh3xF1@^u-I5zL z(pKN_VIqXy8BTL$_H_u0VufyhJw*o>({{vU``QkC_Sqsuy>U-rR((FpK%!JB#|*xX z%x^lH2k{T?;~)0PRZ9LxOL@VO>rVQM1Ow{!E}!9cM^5obgZu3X|@k(@AMwA!_siK^5N$FxP`RwMu*t~raQ>No%-Vmj~ zGSD~l{u2j#!F}OLmpI?RbD7wQ*)zL@BQag<3~nFt(&VuIq^Cjr{;>LknGcy(RfK>i z#5|515!^n5IQ`t=;yA89TduM6^>k)qR9Gu8FcTVNOZaLf;+DHJtk)`E9l*+ksOW@y z$vPnuwwSlK& zw#imxK-jsC`W(eLkhAF)P_~}R76j+xBJHg!ab({hqiIn-n+TFoiw4&&F0~WhTxP5p zjyRm2{8ml)acRGYQLmH%@)Hz@6u7PnJcU(UGv}^|I%M&F-I=5t2iaNK^>~RI1mO<$ zq<#Y}-tld3yjZkQsa^VUkaF`zq6d@A0jOO41aNxm!sx+hzZB;#$m*zTA2VY~Jl;uy z>*0ExX)(CByNQMx2;|qgocrbu;4lB5ii0AQ2ioYN{34mQvDO<%?-NUqqMhT49w>;p zqcpBOANPt3OiiEIzaj11{UF^cn18I=Td$Vz{TYC6M^^8SFsBYYmTSjw?U;2-FEQi` zQ=3e?2@4U{N`l2Cbz|ir<>a4YA(V)K6 z!VFhV%WB*RNU7K9G7pht(V>u+Iv&r#2gs7iuz>~dTE~{+yefOji*$U8&V;V?fiS;R zSu*rqGR8T&$I6g4YzYxNz;qeX(VCYUJ*yeBcNsK2zr-J3cQ>?b>y!5$0fiTO3u1VR!-Ab56KK)sBJ6KwC_ON<`#*jmF$qirKqv56Vi z#3fJv?Y*&LxgeML=ftkE1^T`}0xA`W+y6TYz`gfU_fGHQpYPG6_i^GBtCOwwWw{9Z zM$Z-`Y|4_@Hn7i_obOBsPFIK8GadbZQehz529dmI*(j{amQAjIJy42ygj)azN_n7+ zc>TgXLRgoy77{vCv&DnM5+C~c^722`9r}mKzKE1NJy)n|n!WNCOp0T!C9Igo-U{E$ zxu=Q*oW3qjKt4;w$;7_#-O>`h^X7U`0me z7xEnEY*Fr7udRCIAj|7&c(V>XCNRt`H@@E8=_!-C*?s4Z5NF^^ax{W~$8AiPPq}Uhw6Z3HIQ#hG zNSZuPTj)1Fht>NN?)Gu`0Iy2D?yZi}keA9fSlE6Ag-2Ys%FSNSV4$Mg-ur6G6HexKUq0OI)NtBmK77LF=_G~-NC{`&Zj)~MjLql%9 z%ULKF-%@COg2pX8)T$_uylpav`!!4&&Ya>mu^e9&=Wh>f;dxym z5rujTotN@=zIBR}f@@gOu}xGR5z%?M9YkoNlj-;Qwe&e&E^as9D$VcH4*2^?a@ICw z$F%DR9QD}-zg$YM{r~Bo#wZQ_S0YtqWs+nHnoQaO6D#q^0tJoFp41yyxUMwmussbfN{>>W1iWvZ=zKtvS{C>jC#CS zwFfmN*i^-TN-Op|Dz~J)y_HVAb+fM>EiDt5s+FY946%JBV&uz%;~n%DQ};##6IYwG zXZq%7rz1!L3v!z0X_mX8MRIR_`8D0?&+ocVZ?~@5K?#L)vP1u-aRaYm2Zx1VSaPOF z=B(_rJj#$N4Si5;Ajm>6Nb!3$x!8HKRlH8DOWX)2R-E;zt^Xx$psnhwkeEL*FAFYc zt3CNcdxPrkl|1nvWbb)q7Qm<#eHeJjEVRV!km@qo@co=CE zg<~j;a@V&YLtFgBJd6KB)i(v#6{u~uG27U-ZQD*`n~lxJwrv}YZ96-*ZR_7X=Q|hw zMP_o5Su;EPT`wPe!0c^mF*udm1L7qvr~;#qM*4Oq!8F9TOM**nONk_#$PoO7)O%fc z4uNfMcj!ta*}7$>QMFVdLtwpOx$r5K**tdKNM>DFYrBh_38^dakV3XC{^5!@US8VM; zoQ;Crac0|q4KMj?st|6J>FaCQ_VK^-AoY9y%??RBhGjiL1D&O`Ve$!_1D|~{qKvFW z^H#3z1ms*LHI`4DI;}D$8qbPQlflbhy-!zbaHG$5{7>bD0w|*K7_qnY6|Tel@`RN? zkSl1mF)kcAixThgF0uKw5^$z+V@OH!N|Z$^z_&kHDn-!(`!f~je{JKQRnRdgZYAzj z={V3_(tMqmSBheRhwz4)@s~1yrubqywvPrDmq@X`nrwea90uL-@zN>79+RmGgf1T| zud+qy>dwYD;*&-!1OCS@Uw8cr@=}Mhu6QDnEsdmH=B*`)%u{dEMl4!V57Y^YK5PS3 zt{O?9`yaWawV^gP#tLwi6F*yq&!UH(Ko=W}KlL~M;T+`k`5<{g(h?ZZyA7h(H*XhE zLm{6f(rhkbPzGTgFnSh4t;~C4FNLdiSjv3W$j&+w>MOI35o6jPH6$m|XT(2-Tu$bb zTXo7u`e;I%bym?U9X^eg#!P3s^qZ(h_!##NHkelh$9#Bls~rlD?MP3N$Kr!0IB2!@ zhxRm`>LPzyRbWm>us-g6AJ&Mt`cdP^^xNV2mF}TBw^Fc6hta!8-`l${_)3Y3jBEeK zI4k6X^_G2&B*eeTxeVqC*EX+e-%0z3nR}YzQ7T-vH;cLi=Z98d!#Ary+>U< zWJG9N9&F2VkBpn2eYYVh#3=&8%spVkO@e@$s(?cld*bvvGcpr1p%RA{&{;S-0^ks9 zy>!LAKxegto<3dGJ=|a&HQ@n#-ns_=(ME)9V(t2h6D9l}k+JG?2lq<;Vs>4%w%Ap^ z>_w+j1gkGh7qMqvIdGqVjEhteU!2kqC&P)wdLn0ezl3BHT(YitcKbR{_9?L|t20%e z(k8B491 zOrA4|+BeOXV){cg7_e$S zh@zw$duZl7?S39(15!-iAnyLD-s-dk9qs|LJ! z9UXHuuyZ-#^}meO|DO;QWFYXk1fHB66qJ?M7#=K@vW0&f$WGqwMjTXY!%zkV{`p+b zAe8FP_{Z)sC?9&M`#IIO{xSAz2Qp{a6K4k%B&jW@jQ92#eHR&y5AUvSh>(6s4nwt$ z`Wr&<(@@5{alLRQz`}#_>@zX!$E-w~dzL!qE;5v?aM5_jI(9Fo=O^&mQ1rkd0b#sq zmMD%x0t(Y0mxubu${Z86!sQ&!qd zYTBQ>%Bl7Z+F~=-_w0t)XT*tW6>Gf<`x?gF9C98H#~3dnC{_`j-UK(?Sy=OX9e#=M=I0Za^bNR@Z!d#E*kW_6(B<<6255j{FaREmv^HN!r3wa^AJk4e!Q+3 z?c>+mr_-0p$=uK~ckp>Cb*g3G`Oe;ba@^Bl!!)P*e^9P}n@2FdMq_k3T3FDm+&B^@ zacDE*P~#JjS8mjo339#p89GWiVIW&HbvJo9NxjL;J?G+1@3LbmC)*px8H148kG=Cg zdJHL^oX=NfV{c~?-pBch)~hV-^iS~7$W*`%7kWR|h1giu6zAGbXqH_IPBAD(TB^XW zg+qG_DGa6yW@cbNG7eR@6ahMQ%eA2aPYN%kNkzPJO%6OPuF?1sC2^~ z&m<8Y3n&1<0H8_!{PtT~f%I;mKe?MpM#eIz`_L?UsG51`Bk%H8N4D8vRwpr|7)tmf z(k6r~v5`%=zaMBh`xEMeo7{r*J{LVNb=Y|9cucjhn6*tgITAnt1RsUkM`k= z;r7HM#?P6Jfe{d-?T+Tj=EpUC@Qc6D?D2FP56JoO697-n?U{lEDgWh}Y|ZxR;(zhz!yo z>CFaZK#S~0o`V!|w6*Ld>ibaA+j~t2|8POGOV|(yea4&Ak)oPVd*=EIN5DTp(tKKwaqzj9~`sm7ps zI}1Rx{o#Un^gU;zW7~YrkT~0+yS=x-GHZbPMdBkBc%N|1H}cARu|7jAQjxy0kuH*P z8c-PC7rQZUo09$uD|Eu-iazjGbRDVJ`N{T`|4yND8K?W#I7y_~rc7@bO_Mb0F;Xni zann{I3FZJZ8x6O5$@9JM&}b9qGQX;jJpy+JyeXcMJVSPXLDzKNgHnOhq1{|s>$wDd zwikS=SYeUIWP^)I+wl={ueE!vM;lGi+%L6-gYisDWarb`a;gBkro_5=$eP>;OLwXT zh7)_Kj45ZG+3WGtNcZQ{?A8gvy$MtQ92+8M{TUQJN(L%q6(jJ}_~F(Q%&!Yz*~$Tm z@fa*!C8S{lY3SxesDz3)IDejIt&LR6Ur5B)Xo$H|r?(q@-hGI7pyb?bT1SwhTNxiQ zUbv#D_FX4{Z>Ie`Ll7l3DWkALV~rc}GsYNRu)=I!YC{>?)4dDio`vSs*~_|N1HkYB zxOTJdX#GpZ;*?lpjMf-SvoKwo=zti9J*kB~7dN1M{ZSRfM#m8Fjv!YIKi6kg#U_kB zDp@1R38z>Vq2hSw;Gg4w`aiJ4G#tKWeZ?V6ajzYMw!-RojAiT;df2vU=lIV8(06g@ z!A7~d1OqG7lV}ny*VdXnPtvc!VV?;-p7zOo16cknLMcgaH;;q? znnE?Disqsl(<|08?!c{p?JGMcpSeS`vltqLNPf?9ERv}7q?e#?Xf8dprB3M{?S04sVuo?2l0nBZ>4KF6%-2A1`NaNFwslI5hTb3A!%w01~s0xr0tF6lOoe*427j1gQWb$A?6=2-LZxdV2hHtD7d*p3>oYA$ha zJ7y29YoltfPbbZcmw18p!GHbl$gxStgjo&|3kT{ zsmX0Giv8R1gU36-_5&>jpa1an;p}}h=N&pr4$_JiNP+YnY3_QUjVIZO`Ff6d0Rjmh zo|Yp9%@9j^nDo?kApi&vQN~I^_hVSVy|!?Yf-hBS5~68?&~WexDngb&z4v?j``V>+ zWHgqDaM;)(AV@U1qN_6hucfX(L(be&j#M#v#yx0siyho(-b+;uSNmGMN&lIibO%QDZoQ^Df<{1ltbb;pNvIwG*)(9bN&0trM}^{hG^G z?h&}`J1&AAn^z}Bn9HRW&Gy7mq4nw(Dr;5AXC}#o8Y;c|8m_=Oz6C%Ox3J=Wl_?ASpc7r&F(T+M34>T92Slx2RG%M!U5tl#kIrIScPS>9H zpRP9^c)bb;!E`!#o!q;dLzJ#(B@_lNBgm1c9S>gU%uvtIX3;Ipo_)>y1@7}>ZEH}nOXftR58 z3c-}Em-p_xgGqH|WF~BcP?)eCdQW^4^?|}7c?xP>$sb2cBdHV5#()wnfIFYnJhYNm znT02_SJ_MJp;2T~r1O9;{^aN0`%jbqUieTyL7#g@FaPOd-9q|aLwcP^>uK^m{bMiE z``ko$9Z>7-{1XV!`#4p5SzYQH%K2EyvH$w?zTE1bwyNnIy88OOx?8oX`3QI{K^u~x zN^GG?vKuQSjYUNd;M&ZrBpdes<#{~daIiQ0zIurbY{8=Ut}}BcbZ08{3=yXcm~ht4GbP*P-UVavh)$OKn0%h;vY=ltv9A$ zwBNqdvJU=ad7A%isXJxEpkHdl*YFwGUZspDztp{-qt*L1Fi76tdv)c9nPfo)nXTaqTf_b^Ss%2+(+yUPMhZ#$hHfk**FlVbZ zzme1v#DRN05Xy_;wjrmm%u;V0kO!K0dWIq-_mbqnp+Z`LvK2r#pPAhiw+A+dtc{a# z{w5*+2*!4xCS`ljrqQTWR1`(v7}TH)_}1qkb*#1!;2(Sy?YJ=wUDSX+;Uqx=>z_-c zN*Z(%suD)d;+&L#9pjSf;NdA`dI|-~^-YIegj?BCu{X&yXI>-V4&VB&W3|r%Elo;< zG*sOGc%8B`Vy|-WqxsQ-?^o#9i}&INqvr!Ah?{L~FL$S`&&Me?n3Ut= zD_c|vNEz)GZ_AKv*F9IxmPZVC74zqNXM2ZpqcH6#W|Yw~tBj4sRzTG=3Qqm z>n7JmUfb56$#{8d{M)!!#3894{+qY2&*tx5tz7w$?LAv^Pi`M4sFlt~?^UyO0aQE4 z4<#%nQl{RYZN3rg)2J`^Eh8XUQ1M1r1aJyexU9eX8s8IApVqaB7RTk}HnK zXC~5k_^PPkw?5hP?wWUkhG!!+VJjZLXwWgP4x{FmgGtwC38#^b<5V+RGbT~RXKqCKeJk&W-=Gl(d0 z3lZOuzAVE-NPn4|1{}m@4%ijU9?XtHoN$PML(o_Dz|2jQD2|(pVOs3$xu-w8Mh?(J zsrPZV7I7Xz|3qX9$M}4rEVP)!1 zMolsmfeq?p-J=J)v6`({Mq8W9xoN{wAHnk^;4J(N!bB#Qg{*cVo5JbaC)_Txu!E+4 zr#npF7R3A2irM;0TP(|~|4LI(1?AJDe5ohrmZt-}Hy$E>q$D}v0jj7hs)(8Yb02V6 z35v_yr}eR`o92Kma|ptD4aLUPYjMtrQX^~pHKwt$P4WBY@rCUqfQ+nZz*VfH!`_b^ z4jC7S#RKBHFH3D+?R9lW7;;%Vz!@&V*#-tCyfD3{yDZhy9`&? z0R^D@bvI#BdG=Io@8ccgZxv< zNupLuUc<$~0sj8%8o%+6rS0``rU$9NJfBjIlH6AxISZmjp{OZpK|0SQ02WMD2S&V< zpHzccy~Ra3&$s3Agz8j&J?&M_l<#wDX&i^}h=$sDMW3ZE;`oA`EPX}~++sv5EfB#9 zay?2K3u*x|vts*(!$V|;n#({W3V$|kF2lO4oB~FoU2P7fMqX79L6~va00LApiO3EO9skB{42mP(C?Rk!WI7HF2aJb;iFV`M) zG|}dBF!ci3fX1TEIf|g*gt0;aQ!m3;nrW=EMi^Us)@taO1XY1K1f_G0`Xw=TMEPZal>ZH4dmU8bb6L}mER=hMbD}_C<30@#o3SfFZHd`uTK-X*N!A; zl9J%YLk(K{D`7^EV}i%ryuHBXE$MEtYWTUg*{?dM8e!b;j8i5L2eK;0h^xHX8UiJf zCM*d9s0hzQ8>2Vsu-<4lLtR%Yezqb#Xuk%kPVsk3;r|yRvjf`44^#g}6o>$I^Ha^c z>-~WK?ttDG^G^ytUViO3fF(eCDAtcU5yL8lI9&}-Q3+uqgQ*n_DHxTuX7}U-D>Eon zZuC zt{x37S{#MqoKiw7^`Jt$i&3yxOFi6qJ%iyez8%7SsIjE%q47{zaoU4>qOFoLxJm3B z?P(#GdQ-!qikJcFY=@@1V%H9=EXmkQf1HjlpTwdPB_uZJkh{RX+Brb%{w{En1-M$T zyQ)OXh*OS*t#ad7*|w~ju6l<1BY(+r#2sUk3%k^03XYN_UWVGW&?qGC0lUXIOPE)A zjLMo{YD}BTNLOGInNAL$J@boxL14+NA!a%$yXOh$I3edUKNy-7QxX*$G+q=bVi zVotF-=}et?+Ya-J@-uQoH2A!l!|4U4-m?3UCd0v+c=L@oNGYrdo&B8)r5{ z$6IH{JE!YQ&1L7*WtHO`do$)ny_fwSf*uBdZ|*?s4VXrF#bEj;z<5%B$6LkZXj{+n z|DNjtO5RQ)3!T^?44I5%OuNjY6W+uLq1t^Nk!!au9qI9RfKMBClnE@*hAip0R5SX| zwIm`icVmXVhjTwL2Xl!TT3E|d;JZRWCch$&I<^j8TZ;6L1Gkd6zHDDv+LZrQF{Som zcor9QX>M*#c?<*=HsGl6ZFy_!Xr;ky{34s*ck1)=)A#z}oM%AUV8aeQx{?-3$3jQn zmtP*kj4-=|(;U96rro6i2niRnt=W?W*QmspFf4SL)X=pFn?f-aZ}=J&ezdCI-m#m@ zXRlV=$8!<}HlE9_U~YmgDR_GQb4UiH+8X#XiJ0G%w8aX(n-k8AknYe_HRH5Ygn>}P zDcW_tS5hSZw*Sq#M^su6xZ_?oq_}y=a8-*9mxjqs+kFzHt(=ww=Om;xnc1v?kxr#` ziQc2$Te6fhwN;`lJ}fFiOY^*(9MQm)-dOs^$y&2*zM9Vv-u%ivP@j8wPzla#bCu0V zDJ1s_&oix0gCaJYhP)_XX{ypw2q)R$FJQ^EH-D=%WD;11L`lP{qCh#?0vDG(n2Nd?&M~c5M8@N0}sNb)H z$l^(XYib+aqoTs`DzTJ1i>OUgk+wVpu0AS12DHGQahiE*kcS(>ulJ!Cw{#Z_{(^;kDg$d=;4cIx@Wqc^&J&vFABoyxCPjAu8I zXMbT&sg77W#ZcP(q)4@^nyysV&9&`HJ7a(T4-3HBp>HarbkU%Zb8B7_v|tn4@F>H0 zi`8*?(XfT#5DS-j`mLSle~~5dFS2|;mVC2pz4oyG)74{dJwtTgV0QzF+W*7>o-ejO zf9rZ)uxeHTw#I9$5R3ujNH)+O-&vnp_l;% zfp;zt;`fJ}COQR#%tK`Pjd&TG<}W^IQue|hzUQ49vBoDl2QP2Q?avRieMZxv+SFDl zQqpB4B2SUf18j|HshA9YJy?Iif-&Vik_efSP z1PXzpEi=WbWpd}5w?I5UhZv!Rnr8vTi@us4t&aWQKSIiG6e(5^G(g zIXQ>2g*@Gmm%Egzr5vwUk4vr0MVr{q-1;icrigv5aD}A%TQ?U$u3;R<3C3ZZul48T zgpGgnTp&kWZ~OQ-w5p2M=Oo1^>_6%}&;9s^u0T#Mhvy?r&dY?^x91)FPlIglM-4jN z4vBaYp1TQV-x_BWIY)-k53nn7Sz|F87>5!G9f^`sh7n>R6ZM+M76o2IeIh>J7sP>! zRQ+!TTRS9R!jewA40!{RUREi8tlp&0Ygk(m@RZbyP@Z)cyDk?%D zT~2jWq?;wZs3N2>7aqbQe1)97!a`PMQ)S1pqB>j(2aK!b3s%z$-H6dtK}4ll@H`sK zl~_ANN{n=J>89 z@31?e>O267fW04W-De{BZ@pG+ zy+YOqLywnVGB+ZY!7@B+-Ai#qBJH@aoE{j z-nB2&eCjQc;47a^0>*jgUCEm6#VcB%;i!MuPqm#;9Y1I=DRqEzO0?uR(>R4P_?B$C z8$+`M*au>~s!PLbjRyHf7xkDn;J0J1m_>?ZZt-E4sR%Y^XH`2QHb?x+)J1xO;4)k& zqD&@##=~Sl7m!;UuYhf-co;He9ES3PTk-pws0^Zq zwt_O{7EWe@-GWIRxYdc?4a<29HK zraUXEbu8N3xkrd%bO+Kkks^?fUpZ3oN-<1$(jJwfypIjR%?nPXa{b31pu8yO&Dc0r z0o=@Dst$ce=*u>28Ws0$TSKx#72jcd&6ATENiQz)$0m1(iju6!bnt91=cX!9v!f(+deSd%d8Jb@R$><*BCSX8yFXnf z{$d%NR_Iqj5MKRS_`wdo2a9Q-)N?>po^}UJVtY<@=aTz6CqJ3Fd$AK$zZwWt!C@^& zin$40!?gyH)&_}SEk&I31%{E^`|dkk`_~g_2+al_qYB+#-?8yQe~HSmatOglpMrRh z6_dhnO(Aau%emLuOBi^c1AzI2osrrg$7G{K2QX4ujQRt3tfa@!Dq#qBjADzaIcKB- z)!Yd!va>6xG<1+LOhbx@U%GXUmXWXok)oCa>7GW_i9N%JV0FNQ- z$(^}TOfg=jNxKriDeAYuNZh|gAo{1x))p2Uq1THjDW((Z$fY*dd0nE z)PZ9^>67c{;t#i{)!&~UPjK#K>T+UWW1a=w9uG80zePXtGHudksExW>yt9X35%D3lP*wuJ)b=ZoSprQ4T4Z|VbwYchG)N; zxQhht!9}kmezyyq{pNBB$dmd9_jWX6LMV?e0Yk6i?a>H!^(aVfJ>V`R2p2EP)l}rk z#*iBuZBO@Sb%*o=JXy_IYT%OC8IB3-*r-(nml-FHf-sEeEe&tFxfy(0z7~Et8$+EfV!$Z(Ou?8`uSHXv!pec0Q(NhM zc{*ts;gXCXA*@p(p=dyfLtxKrYpv!%ggXwhN7Bi(tFN5{C*LZ$kgBf@p-yftN=%b& zH&mX9+nrQ9JrgLgK4C}@MB0EwNmG=BG9?~;fiBzB$A+q67YjH+XS|>>=-$XZhYSrD z{3QS@o$m+?3pU}J0r`(jVr(V`Msd-sIjL;hoWs{7)&&Ja)=cl|AM8(>mGn<;SGVw= z&kxOaUd|DMScs?b3H@BKzQ_(%w#enl3o!AAsSf0Y+T&%kkuR5%R+WLEUA6}*g|#@S z&VT|sP-JAN{t*$U2$-~4o~D-Jf>FA#3G)o9GI+Pv_TF(dc8kW~{UEWwpkmm`x%3k8 zk%HucvevL_)nN`#JdEfnlWu#%b<7moCGY|B8^6}{FM>0~Z{c z97G7A6ez4Jjg~Gv#U{_8%$rv>oCzJHF$W5w zsKjw`L1q%A_IlQ_sawnte*Tw?1_OZ4F90(vHn-=|7VhXzkDpo6qFcaRuFUyo(={e8 zFHfc?_y=!nB9ha1{9ts1*$=nI)?p=v`*M3l;?%~rEEE-+64-`2E-K;8jkZCt<-D@s zLb`p`)!kG5G_5RfDm5XGGLfGsbI*k_wZ!V>(HQVXG6b=$_)^qVAV8+$wF|_xt}biv zI3%@pi(Me2KegUk9}65h{_@_hB57F@r|>{&@rp!N>1?WaX+-fgs}Z4Ew+$qGbPie# zpYLMSb6cpRpr7MA0ht|*GWB~Q{Qs*mT7GZw=UiZAcZ!P2^=MEL1CtP5T*YHKxZPPk zcsJD%>~1@UXp7#04(6k)AjpvW@KBzybO94!ul4`pqRBEBuCj18Lm z0{GBi0@4!s*Q@U349F18$rJj5(x)gZ)7+%MgH+VXd7!hO8A41#i^i&Mh>*lpj(}DA zDhVYxT}nd<)G*BxJMdd=YC95TaS#>^JMo_1wG?w-jc>V+nkXN)PaTE20#@}UZw&O@Durd0*UQ#`6{Tt-BphaUDo8~>E{(1sY@!$n8xbRTTSVk%# zAsr=*!NpG|0JOhkub^;=#7?LQqh|+dHo|D18h(U-#tM=jOJxu*jlaktPLgxtwXnsc zz6>=EB4u|pB(~2CU2>3KG)>3S8URXUlzLCu>t&m#xhZ7^@_QyG@f19C=JrR$lKKyb z4lZr+2bBJU*eUjOiti?i`ApyY6wA;G#~E#C3(kWFJi`rE2P{eHe zLeUL@bCgpg%VIA zsbQBBzroD_Wowa2;G9l9NcHtJ%iXfBd+0Z4lw3eazdes0Xb;qEjS?qarNo%X?(a|P6B~DA& zqG6u|Nwk35&)+I9uj}e4jSGKZ4T9$FBaR+0v+=WvJ(UJITZob^RK%@Sxt+#g#5JP+ zmJVAki^GhsmFrZWpuQI2`%_g-Pw7;{9Ur2?6qpAa71}v9z>sV7<%ZhHT@UQCVH>1K zpfQ`QafKy;R~Xoeg&vUb5;k<@$-zb-MJLtDQ)7U{j(8n5X^2VoswJBhZ`JC0$62=1DGL{r!k_;t6nWO@nqjNVyP=fxfad z29W-Kg0(0Ow%Q zP{#N^sVTmW;T9+g7*RebN__mi%ATkW)Eyl&8~gIP1L_bn4&Aajn*}ItT@zH*8Fz8P z-|izyOs1|21oTPM&lk|2w?pprw3BC9Ch@uYj%CvHQL%A?9HH_!WC-fC6x1-tl7T@x zl;Q_MF%On8zv}`g2r(wpF8@0=Z*i@s7^~S0x7iJ=ZljK0IK+M3J-)SiSw%t0Unwtg zifbe>Tm62VvQ_FPoGl}c`3UrwwIjeao5s1hntCTaYvU#s&t@=PDC#EH0zM^IL{R!C zg9HRwv5snM+F$b{70sO)bduCmtvyk>dNA7aLd1#J{D9G}XSg*Bqvb3E8rt(nFzOCj zL1=MPFO;PjNiNYKD?pO`?W-Db+YB1Yt2>IqgWIgF~DF>1~hJ}Mv z$8m9em87)g5O*wer$q5tul7xWbR(}|jE>lJJ(TSOx& zOvOYV_fkl=s)w^+BDXbwgW~*n3xTR~{qP|hOiz#W2*!dtnjoH81K;9Md(PV{R)-Mj z{<+OE>&O}pD(yw1&|2iG%EYHa1S?w?-=ID^VjOiyddx?2((Ni!m3=GV-6M8R9R-Wh z92}v&s$=4A&|~TRN7U{BKy`D5xX4E!c&IPz_LpZeY0+dsnw1Lk{P)1IGT+#whTplR ze^n&W65JbOzu<&mQLwfvaO8dn;w$+)S`#VX2kv4}#BSUwCgo~+Hzl(SQItGc3*9#u zIEs#o(&r@c^j7ys?rt0}3b&{Qd} zq%ZBb?@AW1x{2^uS;gC0dE$%yt7;a(HHsrmO z4=yEH>}mEn5Hl!Bjgz{rGD(}2*rCYGECXKbUsq4KO7?$Ig}AsPVHMZVXOb|dXH`P? z1k7$)b6*%gTfZ(}jcX-ra}O^e8bKXk1mx~0#gpv)F0pmw)jO==LO(uW1de*lmkbPu z{XnINras{tJj-2TKp%pf#JfLU9oA#0XzxV_YeOJ#JyXvSwxtR9kYsi6DKW8epgXnX z;lxi?N0Fc@!!9vCYghtkE)aQYT$qqJVVoulu~@ z^)cVeI6r{b?fg5niOw#$Boz|;!?cVZ9$ z6%zfYWYnSluOonYoJ+DDM`gX@)!p(To<>=#PyNWXX2KBb=&!(>p}-x2)+!8i=m%bL zOxSw`eH+zTVn1FLgiNfPPv)hUu_;Vo>5OoQCpbC?aE5qel`Gr}RwuNGVh~e8OSj!z z7Pt}t^Y&BS>|WbSfA$?tx5^@&qJPF{TBizhDy<{1-3_z(PUZS*747<^?ZJwH;!K+l zy|!(g*q5ZBQ@i9j;p=eN>VKtX)NU(Yr=`NdRmh2d$sJqoEiDY<=hZ|!^-D~PDr==_a7>0gzkQ?D{zUbm~?bICoMq0 z$qYzpm@xC?m5EoL&;iG43OM`o-_V4gh6T1p!EEX0Mgn{{glZ;Ye)zQs$kX?2mkJ!R zI?5-Uq*FzPb^6XY4R2 zb&qWvOl-kd?BJ%=%h`dNP5R#~2+etB1gWJp&AYC4)HpeFYB8cYWUS8N(w!hsf3&k= zEhdU(&O#}ba~+MZ9Wl_eXsp|pE(`~z%^YpRoKaLH;Fyy`L!cqM*PkUeZyp=T65`V1 z*(lT$Izd27s>ddO*C>wr3$pa1?3}V?m1IH?l3|r)nVGU6Pb?BuR7HUe{$Yt#kl85p zHT*&VYe@7D9F1Z|n2uoVIrq8%0vwHpHD&pyo1L`&4=SABLy6I|>LZOX3qRnTvdQyBX~Q^>$Br`tWKApdf7p}^Lq3-L+o6Zu1 zD#ysyYy5|jpxGl{`pi+Kf{Pd-dBVfcYTX#aR>-Y$Np0f2f*0A-#8H#qD44IS@jWlWu)s{9@pZEFz6)4qcmAOB<>U?^-$?;djc%WWDHlCzdI9U0>-KA1g zjtT^(gi$Vj_0K|3!&V8MfPthjn{+t^nQ%lItec5jc#0fbi+4*X?+-XhT zEn^+q&k~4%9T>2}*68p>gu`F)y5dIYbK*E8s~5bT{jCUZIScgwEWL2aQ)Gcz zf%QFqr%!u>t!KIkug8PJzk8s%w(K$go%Yz@DsO?Y1RWgRLUqiaO`JF#A1x<<7M&SeT4qwNz| zW==$vbU0pH_4n)3g&#rFTAt-)N zJ6^7H@&O&EYFk=D9i!#Fc9D7B&KpQ1`+x{V%FT~USJ3MddEa!smn6OK+go36zSBUf zp;_A_n}1=nCHC%3)csks(?!x=l(0^vMMBh1^it6)+VwssO4STnPa0u$puNtq9WY*# zU)xBw3A{Cfv4&N)d3YpQ%hq=+?wFU1TK*QGiSPv66`MA&v%GfA{(D6U;63-aHahzH zCqaQ#Je@^tIgAQt)PZdQO?hUa3vq%22wX&yi_?&`_~=ek*;jo7gER(1`W|H$4xSZY$>jhg?VR!5`5vws8J!XyxX z>+*0&9(Ta3gD`0qI`|uEJgq1O;%qvi=_v5_;M|vO)UmtPo9(gd+=Y~V5MV}klhn^# zSab*p(9PQ@WuhT|oa18mj9^I)Uf6@X1|-$s+Sb3l!u+)gKOhc~qvdK)KY;8iv@c!v z`-5aR$Nq9M5w`@cF`ftMUkghX>?Dbh#gV>5BTAfWzk$>Y&xUf(&Uz|R5EB0?yM^R- zy%GGn`o}c09_1&ec4_`??EVac<~+y2v^ek7vb%RsQH}I&bWy2<%yAWJ{h!*OsxKD_ zL854A+?blkQ$S{(@s7E!>-y!_lke0eBrqs)wnKc5L!SHj--T~^%vi8)az5vMcLVU> z3I6#exWAs1{QCh?0^eBwE7+xUeFpdBfpt_sM=y1!vu;z7!)hrMiMo zshK6ec?xSIOJ$X-x?Hfam?KF#*cd}2V%P{&Q19&_puQ}h+Z%2Is@6WdD=dx!K<$mB z<3@iOdG5aE@7$HF1}$v~T4N0pkybi%GhoYw8!!D^!1N*V+mY(@>L63aF*@U(q?ZPX zGz_`f8_y(QGDxim-k&lnMwD}{=?hOL>}+G)qvGJx2!IMDtg?TvGpNNJNJyHBQxV^W zrHsl6(HrHJrezUrM z6o0egE2jQNiQ8!}v;6eX&f$j#ZS#QMQfn_FYm#Z(_(715wV~p+(^6{}iI%*?J?`}Y zu#hRUBPX0xL#@C5yD$Wk8Ncn-zH+}yPy;(u!B?{s96fXff(#RG3auJUUX{Yy*JHQwRR()D13ZC&xC_s;o0nF@TaX&z=`D*IxchivwNp`)W8DpWiy}WL ziYxUioNE#x2aiKYRo{L5(9cF@&;{%}OIE4PY~8XU?+9=RF4M-fKCGD9$hov{(D~k= z`}Y1z9pCyGNZ^G3WAze5@AdspjL&@m(3Ay#d&%cw>G|A@e_a0SUYkU9z5R|EktaR?u7gd2s&zj(Lh-nET5r zr3hIkq$8!#-^IPMqzoF%Es5elQNu73IU;6Fj~<5^vlf(DdScx*4NzipFv>cLT8Z0} zr$*&Xk3Zxo%-r9e0QX%MZ^n`;W)wT7(6B`+C~_XoXnsw6Nrave$}ACpK1B{z;xQO$ z3hDa+G=;@Y2!g@JL77;Mi;zPy5%hQ3FT-6USzrQ#l{-Q9XRmtUhE?{b3oh+k(TBMba;MP6PI;^qHEW!wsAn>)DfW+&V@H|^;Nu$5HwM(GxGyyT;zyNUg{0=jA z26+4r3qXJz*#xp#*U_JXCnwPke-Aac2U9YQU+>)}h$+3Ez#DELVSplE)hR~<3&_WV z82vjjTp@`Qu@fr2q4L9nRp_@ltJtsp%!&_Z1ce1J6=%h#3vYvIbUqZ;-t9(WjwQ1) zzWrKdVi>r9Nq};gfIaSAoZeA3Hl%> zNyp(ahV#S`6f|;jhS-PNDOO9>b@laq!+ej7x^6q**l+ph`W^*v$9r&UV1|>(TaZt@~r`8x9`cr{m@7e-j4^Fmb?U_juo2 zf2Ygl+zt!+&4jJMG3v3f7dBRfDakVBOQ}W9dx8oM&w0op-Lh$+82w>4b+T{VbZ$We zx^5wsfkdBL2r84fTlR%=^wZgt6*y*aNXPcoVZ4I*wbT9_f*v9h2(%beNrnb7&LY0_g&pBvF$e^m?90u@Qo=gyt86yc zqOE7`USIqXtkt2JYesD|=>w7vc#kK4U7fu!(Ze^laH;RkO<_g7hPq~UkA1dGot#2{ zmD{KFS+to1eZ3dCDs>Z4R%~Ktpy(5EELq=)T(FT_p=SH?+)I6oD;1&w&V-}? zd{UUQTg|}@HCS$)aIWF9w)hx!VL+gxdk=*^i#L@ z%jVpzhdRhXKo4@{9*Yf>0o#zVrlEo8N=nAMyUz2fllSs3 z$?+`P;7jW?P4*U-Ml{CP`0@8aOG-qnq z)r2lngWx>S?hIOzF0)VlVm#@ohJ?dWK!P_osnqQr%g1i(QXKBeU}neh!ZzxrO* z8`loRnx~Z;flG#lF%Dl2_KEc)0gWo41;w}`*m?yai{c)tKDpp6)#RcNF^b_p)z^;( zULt-XCxh7t;vsab$rT$NKiae+PjX0O%6% z_U*Y2|BW%*=hXrL04#58m>3xaY;5SLs;PZnUSI#`0^abn)#aTrIVsD=&TiHea&m|N z+ymK_)Xwyu@_`!#EFaOoM;h4i_r#}s0vvZ{D`~AgtUS$$mCzZ8@~N1S(q77Z_GM6c z)T}^bF(*Ms2}|yw(MFTJlCWLUL=HEZxh%*c$Xjca)N@Ge)L1l5L4w(KOG_OcTSk1k zhth(6NZOex&}0teXn?gU7K$NL37_oK81xdwatzHWDEj||owoY=|4 zwr$(CZQFJ-!9*>>H*RHC)OTPv+IZKo6Wi|P)rIfHE z=IPR06UA?Pt`Le)a+ii8FRa6DmIo#z+X0}Y7$+%VGL%Fx!-0-C4(ZBfCK#)s$Y-QD z<>dQWnaDjjBIaTvbcqHx_Zp|}lCOx(OeF+#Ej`bDKn!^XfDveMANc#8h=!RC=wId) zXRCWu`bPl`OxaNMV~J*OaS73>U{kz3;|Ps{GngX7QOs@?&R{fE1-eT>XNvU$zj=}I z$3?Ke>@J$OW^!;SPB6)yO0_hLOd{a+c9%PMALk%x>^8z@nd6{T8c|b-AFELyYVb^6uJU9SahyM7aWJ>a9 zq1LE|4I<29E)UrIenbP@U}D+E1d#t^O90NCy--7Sf|!C1uEsp1GQ=|W%Vb^1^b_%9 zojK*}NhdL=QIU#neP5YrD_xZoby#seX*8ZmI*{$NkVSo<>u0-2ro{k1jQ*q}O#Uov z=;@g{oiF#i__gfuyc_=VcKmbNIG%6l>-81+&HpkgfBV(!5WXZ5g6s$r{`=nhlHEHh z{}s0i%&42SVP9QY+4-8NdHKq*laqVfET8thbbbS7v!1m%FaJ*`E_TpQ+AMAv>R&{@ zlB(NQjrXS9qDg~b8l;1y9Y|myRvt3%>uGjNo`A#xj~891t3dX}z0;Q`IH+EpE@~-E zE2&w844G?4b$QM^q9tR_CPze*n`YLvN2mX13UqS7WQA#yA0Yr&YvNq^`tAn~xEm;TJhYUmm&nwN5m@hNz z&pyXY4DRX?u6?iRb&VJ7bGdc=dUv6cUJBf z#XJ2K&-#^NxTMAZwu^Mf(|gC0!{?ng?Q_KP?d=-rlX05=l@9ZV9+@Ocp63zvH?3NX z&)uJIPd+)sftLnG_j1S z1#NnIoU8a8lzB@VERQDIQ2*FAy=TE@YA!j-#lFK95dcih_XD-U&^Ao)WY(~#G4qcN z>dYLwZG6xg=+I0Azfy)B<@N2!bA28J#Dk@XrxrUeHuWcsBvSohpXEQ=aYh!xF?X&2 zcYTKq+fWbMjoO_@8JTT0PAVJ;ykXH)H$77Yk&r4A`xPR3wqjb@GoB=yKIGo+{-<2O z*f2Su&u#jG7eE>f<+D75pw*Xf95-DUGN=_O2XRTX_t|m7Xii{tH}zoKbCYsdILJ<@ zVG^Z|xU5nCL|t1lf#yg*ya4+hr<&OQS*+;<{2n^QkxZO?KdtO3fXH4;N2y3C zdJzW~b}XwuM|#(4;`)I?I4cBS(ihqkJ~*0uwnq$0@bJ4ACjMxhz$0rFS6Sm$`SIBd z%xWv#ijE)yOcpj(xPyUMRzaFFkAIL_THB9{xgVrGNxA{Xu@d0HvXP7mTulr1=?83s zqry>deN0MRGL#4TBVqsWgMr-w-jiJK z_fT!`^%Z{kmYs(xbgc~xfwk|*iT8io_jv=J(qY@T|FE-f9Iz%b3>i;_xtGOWp;37h zturl3qV$*S+7u1QNn$fLlD4mUE0@0$Ef9%m_|!Up$VrZ2ZLBw87c%5zsjkRLnh;5E z`%qlanbER=WJG4s;uW%vjJofuY^FXFH(Qc7=B;1{XpU#4xSxfVIw@YT_M7N~H=N3m|vp17X z-7N(G(1NOd>j;S|^e>jIPb3nYyCBiRC z;3QRWjHCwpj;KrRNF!pBw5BE1oYa(d5A4m*l2;e<)@bhE%bL7Y8?TYDa~7lfugvU zI*l%#r-Kwm$y83?_g2D{i=uh>g9-D@Z6L~ZBV3kz5UPMWemn#@%e||jRFG$G-iF}An*yQ{>l~| z!V=V90NLgJqOpbupR>TQH9*D!qzJRXZWlLFPKv5sX*5f;gc)mxYK{pE@O+4+6or~n z<1tc^MvZ zmx|`Po4N%dzIAW)LrlOT(j9aUjH>E;8~)-ts3+S1wcrvcCB>wvu)kk1CTbA>f*U*q zN(NYDvL2t@YgSQ$-)gc8W3ttOgyIU;rYg8ERdte-#tgi2fF|nB>L9A!w{lGGzes0z zv8>(02+`JjQv=viT1|7G?ko|LzSzyLd(l5`Cs?MhzaqGbfBq|eTabT8(|_B;d;tdY z>h*j))cbdG*nde!`}%aiv*FEg`8fS(8@do$b3P@ro1+C)mbW;wZQFDFzB7)ihizBj z4V(G0oH2rQxbl5$Gh{kN9td)@Mk_*qGiE9-fjq+4{gw>%$p=SqPS&|4IT|=lj^!WfTMz9;UE-_dtQ(5D%E#TK;ikd3FU+CJT`TJc zofvhqb6^<#Oxv%|)hez-j(Wx^BCHbBId9%bC9;uryFm99d*_aapGVyJDGJbcdgrZu zFNbn(7{Qpgkv0xNp&9`|vSdpO<6Ug;yYNX=Rt#U7OSsbYjg8$os0;ee*Q{E?P+)6C zcTRv=>&3$op6#kJuezSO)iB?1+n|b zGrszsOuZBl9p+v^fdVlVZtvn-E~JV(9YDxim`GZ1!_7oC&|!-+~n?O`$+6x#>>D)(k(rAnl%U{&+TnWfV<}9G40#)CD9`&QD-3%(G8X zPNR#Gn`{PBzo8c%96^K`g7g5iLq(+2*RZP@rGQX6Tz=d#@xB}+)6vmge`SaBzTeM_ zB>q_N*nZs_2F~u5+TShxrz*XT4*?}+=kk*b6CsP{$SkZGCK#aeHR<-@4}ba6Kjhm{ z1@$<461b2|YJl=#v;M%h=E@h#iomfy2cW){K@){kRx#BEG-xoajA^I$^T z|G{l`FGn_=AKQwnyq$AMKJO=Ydqt4@tt#_VpbRAwHpMMtfCSUI=M{jSXSGpaO@l?r zHF17F7V*QK;d(37ItOtLFB?bNN34_`B_g2vQG?;$o5*MeV>F#U;Ia}01I>}h_6f@=mimij?3r+bgW5pSFbf90gtV>ZC zgux-lF6Ub00i%(wVmw9P^R2n2>ceK{ue~tS%}E*Ry2Sc|hiAj+WFJZAJNLUAI+H?$ z3W+q4OUCa)*T!+J+G!z9GvF4>xHDNb*Li1zqfC|@_!d=D zvF)LQsbxyq-G~zT&6D+v1qdp-<6>Z!L+zS5*Tz&2&%ry(SJ&XyI$2!nOH;Mu_FJMi z#;g)MyqE^lO8h=L!w#7=^ezp}aCUBH(l|^sq%kQx4N-DD05h$6!H!ymVJ4HZw#p%f zT_6?$4JAcTYTU?oU>7W^3l-&_t#3wgs7I9^OUve4ac$C3H4dLsNH=IsvF9Rj%@2o) zOSrJ=sD>-xd?T}BN@Pg|^lv2XdyScPc#=CSr|(!zP;_PLrd_H=G*O|_abt>+bZ>s< z(f>ZpuO^L6#xJ?2r!_B8yhZAMY=7u=GczpjZDyQeXJO2w@kM}m4H%KBt&X642GDns z8-qhb?9}g+fS!^*Kl0AO=bR^ip_o* z!*H!+m5d~6FX_6#f!;V50=eYH)pqH5xGqHCK z8G1m)kjktwBZ6K!^i0Z3A+~$SxY^VFP)EN`W%8S>E3O0hPA>0vmu8ZK0;= zBg5NJ5^@^Uc^Kx$9>6k28-9aL(&oSxbP1I&`VZ&m#xspUWO3~rji!*pwhQo4R$FP& zcJ-G8O7)2u{4(}l8my6=f`A$*@*wKD7?h~WXw8hxSb^lYW2>89_VjBSihW0KdWS4Z zsOS&?V|PlihN%6>QLnplsB{HZuBRiu8q}`FchGaMzqs4iu79en#xgGxr$NP*wzNX` z|Fm$?y$_#WM|4T0O4y7n+9aEYY4fga?z3HJ_c%^TK8_BiVCoNloFD_JBw{1ziHjenC^ zYGY|)m^h?NAX9qI?~e@oz|!tEw~I6eCYsZ~aGH zQ{qr2a(C|i;vgQbPwcXpz|E)?Rd>2n#Z@?FN-I@z8VM^An_be1R3g13HGtic0ZH*j zqr!X5DhjuZk(XVzeO0bZZ{lhTI2jc-7#^xML`~?Zo6&Qy!N|jQ0#T`7_j9X>hQo{_u&PHqnuV}TeBET44kwc1WMJ|sY9=!gYCfQ zDMGpy%*<58j4htyikS%^57)i{L*8;MCen5W&9CCht#OQWm!XmB&9NeG{Jlv046v4k zG9I)5iA8qqC8K<_RbK-KTb+TE-*vrVlWe`uCPmxP;5Sgb$;U7N#mmDpXnvVrihkI2 zvtV1tw%qRNjy^xdBz9f;j-Zvzr9B&=eV4i>*MuRdX^@NROwT?v5}Bv^ zOph_O7Hldkz%g(Ff&H51au&4*TnK^9I{$&vP)@L`Is&nqO%UfqC;W}b;1}bk}Oj!#dlQ7SnOv;bGEAmB*YU>+!TWUA*ps_Myu)F z8*wvT2{Pu2+?Wpm2|?G$wJee`yk^>>-sX#sT$<^Ro2oPoqe$|!fb@XBA77B0@bh{2 zi)}nD&xhPe2M$C&1Bce=mzI}7o_C;rj;wDzvVQ|AseZ9v+f)Rp2kqa6?61?>x(?6z z!|5ua0)V;dX||xdKaTzF?BS^C(zBrM7rNr$#%WS#h^$gu2;`izB+}m2#q-HKYp8Qd zT7c>X8^|5A0c$+=<665&VR@9pNh)o1A1l7;@H&nPMMI#vU*gvCxe;*5eXTOsPR0o2 z?Raw#<~dL%-FOBWDgmyQL2U@c*ApmcMHmAYuOTMwYA2xIC*d#Uj z%CjsLdV=!PFifs+IigFj&oitYX|}iV{mvV_IE=YNE0zH{-VhwDe%fw)Y z-(=)vH5c&}cBj_ATrH-=$-MN{$}jiqHAYr?(Q~51$4A=znhs>-MY&{djMW;AHJuV% zHS4_}bKOM?CK7DzKHRZeGUvINRe<>Px})J^tB=)hiwviJx& zjbBR|YMd6z%d-){PiFe3BqEWMLU4jAepXr1Svx`As7Y0NO(`Vu54HGgw4^$l9PA#c z^qY`~4|FXLD5dXO&;@z|4gX!GxaH;p!KTGYMm=0k$P&Ikxd2W$KaGN=^;X?d7Y;h8dUThmSk3r112dNE`tmdkD4F=IHx8OL@6qcoyyXK- zvZefDB4Pe~b@g9{pEq*7#s97;lxviP&HU%c{GG2j+!vsz(gc0J4$^=6RlBUy;nZ+Yh?DPaDour9DT^BRT)_PZie;OmJ#Wu)7VWaM|rqp~nTL z+wm^vs&J+QxPJ*6Su0^i?`ibeoIqWg=Y0Cm>YK{S!_=h!PvxZv*d>{-o4IY+Jfvxv zquL*`KXQjRKfTUX^{~@Ln(j@ZRJlcTd2~u8>8?||n&8mA3PV~Cf}@g9;8L}invnyk zI#TOz%YX0=9=N5S2+U@AOAq3{N~$FyyQ0rkh;l+11v!mYmrCi@0#C+yJ@=` zI;A=YNu>hiz|~ZPJ=4v3n>wbYQfB6`-wmc-P6E;Uv*-T z+OY_qpCTK;0ST)CEw?X_00(ydy$YLKfKTpl*1C=j0q{HZaqO62;HWVjzFq& zu`d{frTb~UIye62kobwsc=s{)l>I(f_{}aDS|5jnw_sW}4p6@|L z7xE?$$!90u#i$2}p@6l~-`l5u^s>$Wwas~dDAs?@_w(=cM-1V|E+It}34`wM0pPZt z{~~tVeAnB2Cx^KpnpyIQF8@Ae)QS$wRj1TjZr<`Ma2>}G_-VQWG-< z;yJKDr!+{=mET8*7r**g!%h4_>ZP{aY$JZBux{G+VKvUZf|Vq6uC_!}H`;REpPbfoX`|p5+8+ISPa&LjEU0m_9ALeUyq#2!u=LTu>v>4Lf6L$H2^^*k z_4Hc>R)7jdrQP|(&qFkq2tH-W+cyA59q9L?QBYxmGD&eQa;~XiXo7)L=Ej0sH+gz& z3o8#f2PwtQxGHvyrm2*CZ6h0Pw-79%PrubYO;1w|tI3%a4&J|`dOMw$Jf*|!`*;ob zu5_{yZO*yu#l)tyB~C;oTo|THlA7g+b5gdi+zdP&?FPJAr9ZClyNogX(cb>2w)JnR zt!H8Uzlx}_C+e~4;pTtG;h((y+P%GxVDAC;h0(F#Ave0c(>Z!yCLesK^7zI#JKcNt z_JQui_}kfdKePbmT&C@o2&EaqiIEx#CSpFma%vW}#TF~^*E5l)aVy(ud5rKX6$w&0 zrZ{xA!V0;7rn?L)*v4AlsiEzOLotbDx_RmIC@)C8^HLrX?B9O&muGg4-yM?6e7x6G(iyc|BLWqnqWA9GD0LGNR4+93S7_*cgAh78LJdm#qF|Mn;(WK<<%^hky<_NkvsE zoqJTItwGKo66?bywGcj6L0|Y+8e;U1SJ8*-y^{R{Kb$U-t#lYMuR*?gnrtYqp)i8w zkL?9WmxY|@UH)^gz2egv`MndW{22#soH<3y+Q)x$kx9dAPp2m_KM**uCXJ6g1@vex zC%s0}NdKCn)do1xz?7$12&HDzO2X=Tx8`2wH|Ggq^b`z0#C?p#q^ben2665ppB~wt z=(rnM-F@`zSRFM&+b~$G*;_h@udMQe4DfanNw%Fb^dz_DLZ*@p40#pv>O)(uvSXiSWFBT)%uIxFr;Z9!|APPj*&^xC_)T&&P?P7}%TiEvzqC)FhsmW6kpgt)9sODf|T0B%yE+N=AwRFMtL@75!W19~fqzzvj9cxD`Kz&p?kTcF@z? zG-J(m>@J!yWKJaH&w3Jaj(R7iP)C!xyZSNX*gJZc`_ty+XE8zlkyjswb(y_0)Sqq` z>Bdv%m|6JTs|OSoA3ZqgEP8eiiB=5;w<61HVb(e~(n*X(4E$pb15jr%iyLY#Dx0zI z&9q3?+UHs)E>%(F6%J!mMh zmA3LdKc#>u1C+C*MWo84f!XwN2oyO@=A#~j=B^TU?i*-STtSC+fl~eNED2zU8O8UC z4UX4UArjbaKp9J*<5njRUu}k719UO8S)EewyIU!UA^jb?DEsv&X`jmXIJ_b$M8yty zqFK_>F8B!5zV?_^{$h*>+^_kz@A$sua5;yqx5X!ayWHsL&tx(0xqNi# zB;w`RU$k~VJwrPOw@q!Vqa2t^#*g$+= z4`5(maVFoto@zIlheVSk^pGu>XCn{k3?=^jwb}$Xt%>}*m;qSi1Ua{J%O&@p;~4_} z!yOf|wq%1Ela_U{Hn=0rkx3tcG>C!5wh|e=Y~mL3D7dm>tQQxFt-#&XgrOetoM%*8 zL*fh`6}!kd@FO(|M&tv&j65hlWoWR~vOu-bd!2zDO?!O-k7yxm7?}!AFF?_<@__44 znKE;T#sCjCqqm4bE6FaTwkJrk_kh=RuzSA%R7M~2l+C0e;J)R=M*o>YMS%njmoumX zg4Uj$$;nCbS>3N*%Oi6Sco=}IxmMTKKzHOn4&*)dA}PN;e+eC1ACGN!cRxSxHagwo ztJUjo%Q(7E&+Y0_O?+NMk58eTvla`Kk7_i#3*@0BFLT^MEWcLL&&I&CaEsfg4vAHpr+TT0A5hxU6VmDX90a+TTGTqv3 z+TXI7i+Rfm9;I9uc@p*z;w20N+24u60O36=Jb&d`U;-%HD?ej1g z|6Zfr2vx>Qr7ts8DRMj<)XU+#d(%ue{_Af{4kmSc&yx^8jz!edTV4)OvK z%?YpJxuytSP?UIITmmxMiOvOyFD7bR5qt8iW_G6;p7zE(EhiYOqGePYTA zP-xS=-5eAuxU4z0|Nu8Z$(=T9wJO+3viZW!;pp{%kf8i5ly)Q+pa@hL) z{n^W??I_h`R{#w%7dopm%SH7it+k_gBU&;Wn}&f}T`*@F1}vBg%@QT46eM?gfc1$E zdSu-XtG+JKTjDy5qbrc`Um@Y%YtPl|*)vlBP(&y6fKmSiEF?ZGyL-K#NcvCw93SbQ zH@FQ+;YiyKO|PUsZ%KV_lk-jd{qvj6r*Fr5-^Rb*A2jE`(+NQXmlKVM^WP$WBk+H7 z^t*=gPf+hZQ?;mlxeovN=9-N44G5s^{w}AN)+R3&%m?r0MOSUsAJ~WfP&b#~I$B@G zSib>h`5xA2yU>>FQzK}Q+s1?@=h&&S+p$VrC$HvN%!S~>t+F!`&-mmw;T-ALs94&S8 z>5}goESSu!^h%fu{2Q4FnX49!End3Al+YOaBC5N%L^rLW4cyooD=ZlOewCrfXo-oWl5~&LnYF!mW&Y)j*(X zG4H>)B!|&Nm?|c3_7{Z?FtHF1!AMn)q?FYHp({BPv9p04C{9(yqxzg0cDXm{6nnUj z)f1=?=Ss-zECmr2VgBvFnw{>IO>O}rEXVu=3PNIGM^f`r9m-NIidB^FL1WKdPSm zKVP?}U$;L${Fj{ZCbM~2Huqe0^ScCGJ-u!kiSl+vaj#89un1%XH7XLL*X89_=|)`i z$+0M{2+sk24OF)6=?^fa>eg4~x*u25`hkCvY&@G*lCV*%>MtY#-bpsgJ&R-Zzegf$ z$6^rma&uNA5-ov}^=47O^FD&!iat5MXhq_q>MvjEwp4r!OvdHDGoleU8+xsLA}hSfc2&mi4igU#~!)rj#rAgBOCwV=*%>qt=ry)Tz> z-)29ePAb0HCD*?$xe^Yp2|pSXujF}`H8ei+yn3LVYXr|&)U@=PlA13!Ap<&+v>7Dx zq0uRG5luC($u($BvTkxoGrA18e}+?17(Hejnp}vv*s`KXEx7*vX;tp`2G3cdE!I?z zQMy=a8nRTdDnxOYpc44Nde#=(_|`eO^|852P|Ajtkt!aNqjk(74}y$iN)azW~{C!p~8 zYfR`}ncncf7FWG*958hK$st1g+$sN4?1OtU`*oS{S@X<=uL0e_D#?xcW~an;mu!^J zvsYlnShd}XQ(N8mG8M?D@!~qlOnew#(Y=b}moTHvf9F$6;Tyhi2^|p0L5%Ox6*wUJ zB`po5*Hn{1l39&6C8BN+jsdgIU71RZRlwY773U#|0oBVWZf6;V-g!R3u z5<;YB{td}I=PzPNMRoFe2xSI$R%cYkndaX(8B#C|ITV#OXol$8tpTDa28m-?DZ|Xngbk}K?sDL6CP^{TU;quMWdk57<%1t( zxFv?F_NSbA7U@)5yoS9@$11^hOaB}p)0w$~ToKst#vq41I6@t&jH5zA2^I1sn3k3l zHLokr1Y{cFbDt@=8=7Wsge;z@hNwFlNscK-ul1Mt@38L*0szvV51(0$p6ZWPQ zf&lJyssAb3mDPYqDe?}Sy6ZU3+t0XxqiAA4# zHwsC*lmbUV^4skJJtm&QSC9g=7z{R`*F>WbBU}V;+^3tqOc?1Y=~o?g+Ig1DF%I}BIo3!O)O>-+forVPy?DpI?9O> zbG_{ks#&im78Gl`he440E+woK#_BrNat+(;m=s(i$uqJNLBR?MfiheXAvs>~F=>4g zq!7M>XG7$WXqpzv8XQzMB{`O$FiBne#6LWiysVI>v%+}*(KdGAlkCPetjP{BYAHT5 z4&6em5+;DHm1w{mpJ@)VN+txJwg6r;#9~*cwZ|vAT7&Zm8pz;V>fj_*6h$z3ft8tx zMjseSoWVJ#>hBZc0AB98%^c!b><*t_n@Gk@kRe-qrR%a*(^)3|&V(Y6*IPd*9 zf18+ogZ~EPwb1PSU)R%3+`syXJ<|YSo-PT#5v?fnu>UHTtQ~s&>DI15+o}R;7Nyqw zjvzT^PtLa=45ZpmsiV_-$8bD-6JjkYdhZh`$`0f`)BbIk zQ;OR+l^n-9k#1H_=D9U2mi9;1!2cysC&_-y#6Z3vDsD-VByc`=5a5nMjuhfdu*NQ5 z64N=sb983jk?|hTVl`&LyR&fVeSFCyYpJ^J#0mN2;zwO(L6y}irFmWezX`DS2#mC4 zWR?9EH-?c&cT&lMOA~xm0+JSlvj3{mED1k@S{1#GmVYR|$3E5Oi z8<@RA+gWqY6d8Hudat?%Cs2jAJsmfFn~6Eq%$zYBt6U~HP-&r3JvSs-G-gNQ*y1Xt zS=kV+wIQKO{ap=6z(>M!Nobd-j*67PSHd^QIc5CPh&0QwCul;Kwj-5vr0{@}p{O?u3}o>jlo^OYGp*A=~)ksaI> z@Kab%VlQ`|R{*!Qf2#m(>Jgz_Oii9aJqm}BO!8U1u317l&R_nopxd+a=J>}#ocw8+ z%Vd%z?P=*1R0@mnLLji-*f(m>rzH0w*Z-^DFFEHuC*BbNm{pI=e^yW4=hXr6&AhfS z4##YA-BXi87KetjxP=L?HDGI>xc zauUUnIa(*91m}MnAYbj@%_E;2l(>YUXJIGMD`}hBR7WX*zIf>3tGTTX8~wW#Gp-h^ zLz!*}G*(*!)I~R^k;-1fBNVQDW$JZ9M(x{)YQG&HpSkSo+uC5Oif@qu3iO%9uO2B* zTmmosdO9oIV3fE*%O>6X>S1i)(SRK`V@IMotF`$WqtsHx7NCUOf7WyqTxM+{|dN%d(-SqI)3wQlufW}rg+ zYY45GVTGR%1<@D7-jiEYI+|%1d{aYG?_Wtco&j3Ha8HrOWT8c%6#j0@?PsfRwie@q z)s2mGk#Z;v-tK@oIFGI_eg|QrZ_oJPBXM>tjJW-p;d4GmpOg%k3alyI_nAaNoT3tsS_w)|IvP ziC&&p&AbSEbM@IoeQeLQ_Xq|jXz#yzdyeY6~I z?fA!kuUs2mi2<;;dD}<7T!I0XZcz;RxVgJi72y*Qh~L%Ad%EhED9A_uUI&y)HYW&-ADZd!-BfALCK$^ zA@!VjD;Yd5u(Fx+YSgg9hFeA%Y!+uZ>n{QLtA{@42`3`4SD|2sRHuo5d0R4Jv#0uN*qadpnVn>AH+-mD${#`h!&J6H>Os`jVChLK@k zYj!dRxGZwxUtx3W6c;WMh(&cwq9r3OX-UH`|5u^c1ObgB3WFck&YbpMb5`VPW|`gnw8)9e#eOQC>aE>REQNKh@7d4p{>3BB{8X zwa&7=!8IZ&tzR=4AO&j4q?WLG^8G?u%^m+vR&dLm2%qLb%9=H#X_p>SPG}3cr40c< zU1kn$O4oh09)Lh}#dWXqT?QQZ^DXUB14Tvk+|J?ckocRoNA4-;5;qCc?~a1KiMJN^ z@%=x!J~lnDu6L3AGu(Uba=%96zgQyabcUPP-p|(`4^97*Yj=prJKsH~-1Ge7Y8?i) z3Hbqkt@2M43dsNdwY%;m@Z zN5_!TFAn8RruoOGO49fwm(Vb0XCCVKrSq0Kd>_NK(4qLdBDB0yXnzacQ43{z`tNYw zwXH)R4Fo?`ApC;McI9tgQnRvDFGKRM7B=K{L?Or5R53-^a?aurZKJW(@X(M)IZFOG z=pyNFBJowySn8MLD`;i8V*cT~d0Et8sL0wVa3Puo(b%wJMMSH%mF?q1B?lv|d}NcZ zr};om95)aqBct=lTjettdWWouGVZoz{#p=j!+BIrFVE|lT<+z5T9J}@^GX0MYz78u zczRN^m0xS1LA$~+pX&8V7qp==z?s1^x;7zw#TA!A%n{|eOFAYePFhE9y-_SLUT!mJ zTqZi;=ANr&ABTYv=}$=Esqo^AkUJ)YED44MYRM?aIAt8-V3W&jlqCjCm3PaSMeIT+ z;fRvUXymX&CXjT2<#ydNG7yx9sP%5`;ZATTZ$Hx!6JVs5Tte$ZtGSK8*kU!&m24%U z;=w?LXXO@9tZ^}aJAbGKdRT;E$BC|mQzBt3Y5axmm-hxw=eIZ7eO{QqG>3j0 z_I@qt@_En7^p^iHzDOvrxL0Oy@8DZPq3JQjjG6Cd5J{q=KhCZK;atDgYHz-O4=DQLuC>2xZt3&6T2# zZiU`=t$#vnfVsRL1xWe6*d)If$!eSGM7p1Wht%a1gK8s`VP}!-C$<~V#;i(rj$5T9kV;bz%Fq^N zWBn9qD>63$2U0-nK}@<_$5LJWFR{Xx;`lxL8?JS%?$(FTlex!{rhRg=$6CMTG|3t6 zT>)8nOG{zzO|dA5=UuvmrA|h=j2v5?zde3D6t&2yWE_G(X~L1?g=N+KS3eoBUV+l;YJ96gKv*tPTftyj=JBWde7cP z?{jqTGlJge|3vg3L%=+BVa2)h59ZVT$<8->bEOSMu%9dxBg+U*b$F+}%U^vg2eCZ)THS&UU)0YWRCos2AY=42{3c9#^} z{(qsQ3{ObyGrR|h9_e*C%NG_X+O)-$a1t^h$VqWIs9jX5hD;Hy&%YghQ;bBLfYG3M z*5f(QZ(hHmR8~b011(#?4M$|sZnq3l8YG$xmEu&p`Qz0Ce$Ga9^$&mp@!WVyQx z)xc+_BvN|E!pxHxsr_sHt$>R-hf%!o8b+$>h2+dgOfCGkfG93%&3GL_x$MOeRox17 z$Wx}GD~c}y#jCID5grOqR9d?|oJePRmXmpFid3421}6QKMV6&uvI{Lv4&YKzG6Iv_ znhz*GfeyI~HW3}pciwhl)AsTPn(?<1Q}O@30Oee%;G-U%L|P z4LK;*b*@MR>{MCyU`JaPje>fVBqAg7tXTz7TVrT>ogqE=Qu>tnNZW*!ipPh%8YnRh zin6{!%P$64MT!W%5&`&J3}^pvOG=yDgcz$W{Ox;!Oyl@fmtVp3DC>aFW^RPTn{TVc zIkxTMcwV*o$2y>GIwJ^=Wq9i&?nab&O}KL1^pZzQxAb$-ZKAzf z*X!n$-_Gk(*D+t$A-%n4q+0X;7#>NW85A>a981X1V}1v6x<*H2^C|rb*PV4WD^%#Z zbQ7Vj*1lmYFk#2B z8GN#wGnw`kuARz9{H2F>HG2@PrW#bB3`vOr!3C>|U_{Oi;EWVuc0`a5GZj<*=LBxt zZPj_bszpgXLzTE}WgoDs$F&1DYWa=1_+`!{xu$gWZ_LR!_0u?iA=T=Pv5E~gc%DO? zOt7A)O#KuGHaLuSUxS?DNks}Jk9)U!`xpdb)k@R;oN0uq+%78%?jrhx;bK6#7NL?^ zmD?}H)dRSFWirzd|6aG)yewxLJRtE8dmg?XCoROA*{gpaVJfI>#-@26ipIr)dn?r1 zC%1J7w1wu(35%5pT6JF-_u8n}TETwVJta~@nnctFQGnYk|Iju@!|RcDCsBt0^Q#np zi_&JB@SHdDSSC-9G}V=%n;a}rva-7LNep07Vu`>s(o`8!QRUVp)5(Y?D5EN9h+3jU znT|}(!oKq87V!|*f~!Evapj~zn`h+OGxOIoBD>gW0xF-Glbm+%L58F# zEC()UICjyKp}ABCy!|X}{ra33t&pjOe`d{pnStbfN&ugW9(p-&AYlGk3wsC&3>ext zmCN(vf%yybg~MZhzWaMrreDiOhNt~yU{)?|04neloP7P4?g`|6us=~({v=*$E zGo4!Av9VH(KG`58Az}Mx=9iVc4Uv=*?o854Bmh!+uZY{T&|y+bQMZPcvoMdwkZEez ze$r+Dc>ks~(%2dr;l5q1+wVkkw0aD_;Oq4|Mc>VWG|~~Yhx~AqQ3(c6FFg#rT8=Y7 z_6YCzDbx|I3rf=a&=VDiY-Y(e#=}` zMb(s2K5|*;QZq-zT_QM*dl>J0tS>GjFgw*ii4_JQ&nBQ5MvEn<3$Tl`)o_ya47 zeWHy{j;p;cLJTG6=u(?5+Z=Ia^Sr1DOLd3VH@6>>@u#xW%{@pVt4?=Y)COE)X~7BZ zfeuOxxz~|2>B1ezX_VQ*i09-P{*-t)lE^>$v*v6XV=JQ#VKKLSpW9Jxw+XENt*x!O z`p&Ow;D)(RSlW$m_2!^}Ryl8F?da5e9eTew)rEvgdnaZmx>y$R)%G{ZYnEDAXb?{$ zlQFJyJ(dHl_TlO%#duo>Q-8zZ1`kj&(2W=oNdemjn0=C`)_SuE8*sp@H;*qjZ8bsdGq@Q_iT?4*2)D}j*A4XgBWAZa0U9X7jLPm z?gtWWb%<-x)>6xLu!S?~b6*Q@5#c1TeU!v*$aP^#{-%k?k=v1qhi3vN*+}_ajd=y{ z=6TFFrDenWkj9j>z;_rK3E`qMt*Njh)rQzv@LZt)_2)sPD!8&B=j|du?&Tg573N4& zz%Kr?hE7kMnvPSF$obN|n>+m3u@*|2VpNenavfUYRUn znQWBMZp{E!;7Tks^KSS=D>FcDD0R`d$M%q0yAN46b?M<()oqNN%-{2{QN_i>cUQhL zhpbmqq=2%ilW}0#Z86BHyqwNh0|F3^T@Gm-?wEQs6d^u95MG86e)>~q0Y*V zs*MLvKGVlUpLx1(OJsRItE#pBt3}b5A2lf7GHI!7ayWFiVkcBNtD{c&^woM+5lRJp z@foB}Q)v|?#Kb00Z74P+Y3uN!i-}lp$0oDQg-tyF*w2dXq}WnPZ>A9R+I_z~wko*| z8&XU>ep2-1grbp!LS2mio5qgXdKhiS0cou5;L4$l$x%l33>T%OJltrFF-I&eHZxe9 z>9x!eBpU2^IEQH5jVN zf5`(OYdh{Yb8zP)Xhl@R7KSYm8#}xU(`}%o^(fA0{=XA|?qLCBq_^@%Y7aoz7N}-L zA9o|R?7@Wo*f7jDnRNe-j4YHVYoWb#1G9ne`LJX81Jcx zK5k2d*ZZfZ?QD<~OCfhA8#DiK?=D`dmve>u|(E4o?ZNJculrO-^r)y zq@K}$vtQ{L+?3$Yc)X)8?I{jW)FrNVbY}|aDgCTF!LdBi$;Y~~b5}Rza}JX*t}8-1 zLmo=o(@bdPJo)sq?_|-g5pP@*fvT#4Mp^R-B;n35iu6+K=D(Ec5Q6dVr@Ge;=zN;( z^Ae)CYh*t}IRY2k8IQKL(3Zm-gCYB8tc{Yd(LrgK96=Cjl`Z#UM0p)-`Y_{)piE^tP++ItQ%eLX0hm$`oLY=e0X?w8x%n9H#@F7 zd~0#jfhq45SfW!LK@Vmlf5 zGTVEQ$JXDF3dzi>c?+MbVNR(T#Al%&m1K8Y?pg65G zm#6{a5#_>Dq_fB5(Ushc3Ya!gU`o8S#g`_v-4WhYv5%$AJGj5xm8UQh)h> zy#W;VkFRu!}8&XxVTi|O8z6l31b2N-vgy<fi($4>84+9#Z6o_YC`>^If4LOtT%62>#HK|n&{npLgExM;J<`@-}iD61gPW*%o zza+fMrmMeLYO&MMo6~2?Rbh^wWK%i1g{kClH_J;FQ6+{gl(H3p_AhA- zC0jK#XQ;FAL7sgD<2d)~7UWvZG?i4Qb9#*fAKGk^7A`!MJu*EWu2U(h7qs-f%*{0ogyux->awH*CSpwE3)p)?H5YctY;q?US_ zcyeD~!7?fq#(?QmE{PSSD#QvZdp^is&33SV4~WizscknNL!&zql)(v zb;8vb_VyYl^*oDWXecO*!V?&mfmxXtI)>|oPOc6EZh%kg@ zKfYl_%q})=1$z1VGL@o$g;L@+JYxyb*i@HdYhD?#vBdLh+22RNs^UD=;ZQWvzOkb2 zzd}zpb~`^8pIM5_V|M_+k>#I=MTPLZ zXGZF94XE^^F`<)7Qf4lu6V3ApvR2ncrt=SB>~w!An=7&Ia`g`}?erp{ChfcVGo8Il zhyS9PppTiP&S0>wz~V6g(Ix;JDWZ5@QWK?l>4g=HgSJfNV|#t{Kb19eU8}9kp;Z{~kdG>(Qr*~r)MLVkJB(vS0Uzo!Fl{LLWeeqvN5BG4Mrsh7-4ek=2cj1 z9Hi+CMykdmZHKx1-5u{mt*YP5Iz%j0yjT!ZXw0*|ih_A~2aFnRjzGj_HxY$$wi)*) zm){d3tFTlhV`e)bBmteX1`QO+kX1Jr$&kAi7_s=MAu1EU45VMTx%;W|QXyv4S^0^w zt}w<>oj?kG=aJWcZuf;kVyhB$AtC$Iix>sZvZ48KgE<5&Z#&jgWS& zkTIC!u5p%>{U(D26F}23&3QKQ85vsb!Zt1BC0Q&)v}=?^O=@b?En_vNTBK@LwL3R9+XWQzV# z0sF_8dFd*_oSvH(s|N8|7A;<~Xcq9A5nmCE#oHMEk5QHb_5y+t&tdit&>!qX-*Ob| zkBh(<>0G(Ny2@np_M6;L_qlWVnpusrU5ZG}_)yV$rdc9$E#?lBm>PuPr_U2+GWA+c zZpOlenD0~V3JqEEiWy~Jpz(!ET$+#rZnnZ&8j>q$+maA8G7`jUtw=Nfwz~Ga$h)47 zM&;9MEya*~$;vra!RqvmgW)@q!L zdB$WXUj37vZlf2a4pmGq(Qy)?r#zFaW@BCHODn8c-C1DtOFE6}(8XNb8WUjS>Glq7 z4kD-O7#qiMF_p7a7C%ZdKb8~dJ?s?6yJ$l=&L-RlsSVn(hR_%!zoLOJfGIU47D+;5WLh6uH+QR zW7ijxUy{alQIoT#%!*WDo5DbUs@O5(-&=7RF=aha^%u&tl1DmN3fwyKir(od_)}1z zK8fvTD?p}}JK#011{>X66GKYDACks#mMjuvN|qQV%CqloY#o=1PeB)5^<@G69GAGk zYSzLZwsu|$KWY{sO#+gqb&8y~V~{&;d34NOPKLDl1fM?Kv55Q`r!18kG`dJIh93AbsiD2& z(*oJt_fQn{HEaK+ENF!;kN?LKJ1Zfy5vH}f$Q)J==zyTfchWT6XKXUcRv{Z(prR@P zDa$DCnrOZlNMnK?S&$T$P*Sj;k}1wBq|k2I6uoR4Rb+)V@(ro2}MQf>T1d z61DUY`ln!Pls#yITvMrux*zXox0L`62@58GZh{I@3zQre5bo?6)fA~71}XxZ`3xGA z({ihpti#uA#BHb$CW|DPp&7ExEmd-BT9)O_m9A>U`d)KZubvsFI3+_!Q}GHZTTcX@ z)#Ceqf6nqxY*^gCw%A=82;`oDJRk%o+0gH>)A&y;ZC;SnMRo{lWPep<0ZAn zqp(864Bn!zFRHYDD@lZUd|oa>NB;CuX#71WHHk1!thV5r#3!= zO-?C`f8PF$A38G{bdQ6*o>G2b6>6%%Q?bF5GV#iPN5J1>E!E`y*ZH+XdY+sfb(35W zBc@S#Lh%5tj7pP3i%A#rZa!FwTIwIG0*tBG24UKbxmr3yJMBj!uI+h7K+A;2g`%uT z4_O^Cpr1Qg(HWg+7-JU87oufGEl7B^pY2{gfcD%|$mmUo@cSVm7pUI|DvP7BSQS@d z#=U*$cKHgw)s~Rb$PLB1VdxBaZ7e9RgeX&EylDmr6STZ_78G0^va=I@8XC2I3~!1M z<`8%^1Ug4mViXiN!SQPiFMb{o8%uRc)@?a8QF+QqDxO@fgdxa8R@Q_T2yXp4x$8Oh z9a>oJQnFgH-IO{faWqZNo)|7V;^be3;~^g2kCbot%K3!70zx$)3s)}nErjJdz&MTV z&W#5HXBH`Wvk@!cxhXQceX@{8KRRS}f&_U}jcR{PqIFvRSM|>t*0^KF_;o%pNA5!R z!oebl8LDwF+?GTPm?#&^ghhngBlzZoacn5tQt?loDKA}`O-#W0(Ty8SevOrS0aACKx4wHx0e@oa4d!s5&Xa1N?16-6$ z1pHzK5?4#;n59W#2I0*;C9%`4jIj(2{luM2naw!!#7}_W@T4YVjInc$=H@x3v(fjV zR=FD0=tc{ueHpFYn*t-)1!@nisy(lw4aVD@4ze&0h}-nIV8asTtY{;l`{OyTzI{s-pAA-Gn2Tq}6* z=MEZ4>m|||282O@w~}P&)9r(&>biWsJvSUR&iPzFc>&CdbVE*3!A?@p0#-6c=Oi`~ z9r&x07-99=%DE&x2+0yVN`Mqy4if=yw{qtg4Q}hoZ=!@SJ$I{qx5KoK*<7D$6!V!u z5&>Er4Fzm8=K?20GfuhMtuqljVJ13l^?<0_bIJV|gK@A5xum9Lk(wc7yEPPu`|!CVP`~+1Zs>+g%8Jv! zii9-tRLP(wzKJ!(ooZ7mHaCW(kV`2CDh2IpCQQ&vS@!lE$297Nylm^X#LQCCC6k7d zCc10jLH2|qV4pvZ2BRTsW z@SuznA0M9&yrHA({q^E-*za^0%-j{|F&DVO-FSbyzxlBI>UO%t+CP=p@6-3>PJg}O@>5u}{!cltC8_W!(;#@`%Zzrt;LzoGl6y<4^<co-OvnnfYeogyeOBNNue?}<56OV zD&+~&UD~Qgs_onl-;k$NaZ6eztf=D^$1LoiO@0bv!9NM>Y>29$3>aXMPK%ifk~1ju zHtCpCA1rB6baG^&t+*0(w{)W2g{KeryYK4w)0V#Zn@NAsnIe9=J$@7myi#L1mXFvw zJT@=P`D+$3=L#z43Nx!hTky*7Tb-?P3&N|rQ7_W$Qnw;?M~m+!=-~tgt_A!IODuiX zp&qTEqSF(BJl!^yfNt7lNvug@1|4-CXGd#c6+p@;RZK%tO~v2Q%vh6c`mf6&jvYmX zcrDkI_~z6pQ+oAWbmcHnEe_3{RH#1@|1k{~Eu8Vejx?nCDb>&GfTZ;Bv#u9lBUOwL z<`bkOREr%pRud+_zKo|T5is&*s0As9$y)MAIZFtOR_AospVnh*!j7E^OzinZ%0tO1 zD4}4=DKv0ZbNMhC`V9^DPzDWZ^&S@^EPl~|JvgLTYZQeo6>QbF+>lH+0WqwBI%7`t z+Z+NvF#oWm7MWprkAS@G{BWWt^St{Hp4Cm63i+X*0lEgcoU531>R&opLfQ?5P1arr@(;7Ir=ZS{rTZD zle$i)QFEEO*cFz=X-^ii^vy3YyL_jrQ$^*$*4kuqF*U9sk~ZW<2$jUO{dORJ~6l)>^f2{GvP6Zo=-sn`~* z{w8-YQb&9{Dk>AY`h*NB48^FzIS2V2yzE4{gBULJ4(@Yc&zF?bdOBG&Z3*YYi{W);)c;QlfbZ@4XyR5=A9S-$ zJ_JOIb-3@(vxd(eL)mpz)uieWF-B89I>m)lduo8gpI_QikpDf*srpKUe#^0;(|Vck z&0fYa*bU7z$DR}Mc_LAZ-PdSP+1zEWp5K&$F0GFttz{N> zwq@(rIrDLfjf)1KX^WPwq@ijr{r*;al9TnoOIPuFHEQFRe5id|=U^Mq8Cyv8yO8#b z0^N_L#p#R$UV6n*u?EBV)OA%H^-9Ec)uuw@)bGieq8(TqH1w}UhRbFIYB{@k$<>)9 z^cGKbT+~`?n-0fosQ1Vy%<7j9Z!`xA$hZQeWy5Ldo9|!z=YI_M77b4>q(tWw6KBdu zf|GS!;~X9FWnS3(^?;9^HQR|2MBB&nmD#-RarTdC_S@KCPw4yd;p+!+_s8q(j|m$N z$e&;n*OiBCQrpzoX_hqqnCH%3VGvk()~Kz{~?_3?P2%h@54>9D`)S8{y}qn1Kuy4$$I_^{c*ps z0L8j41lP6^11#3~B-Y=3KHLZ4u(3E)3MYvu(J>s?N+c<}Cj28+Rw`8Bt~!c`Hk5TX z|2kOdSQNESFiik@!h8$Q+*dL*4$`Lg2W@p$-JV#3fBe3&qn` zUzQo3A64?c16sp6q!n$&8%qP`mGI{mr-LPp#lS*6Ay3e3GA0TJCvGL>inLu5c?$jO zb0`&!0ZCC5xFp)z4dYSG8fn z%%-h~MPa_-2%9=eEL{1p<{weA*05!r3wVLr)#%%5Tc^fa@^*G%u#ZYH6^QH-*Q_ra+WD4(LOku=D!NK^RAaiFp=Uo%Ew|Uf{{%h4{_d;8|P$?K=JD1NtjL?3=RKb-)fw>Tx7vFbc+*E!G;u*Iu=M zO5GzNOA}ns}eCxd_t1&7>hK)G@Y_5)snl zzq?2aUxH)w4~v0H4K7yoHb;?}ppuy4d*;Hwkvvp-AueGKIq^1l7xw@gv?<@39EcyX z(s+d#Et4(v07jgLXF}-h4*kcRlb{ufy^2ASj20;DC=m{4b9*lS496N?!`f37{C%4* zhZM8>;`5F2|vR9d%0whkYw~U(^FPT)^leQJ_GPq zevXMrD`ttY<} z!}y@on`*J-$a{h#8y62xfvpZ$ukrzgUTb&$^l|Nh!=uC7i|0yXtz30@N_jo6M-IE3Hrvb>7tR z@q%Y#u?;4r`%RQoqgH5?q^7Lr(Ocosqi_LxD^f+459~CQ?>85Y?#P=!|l& z1i@P`mgY%LaE77VJ_~|XyTS)uoejmzH8F*iv=@;a_2QnEPBBTR6e=;8*`sER*cpt? zQf&~Ga$jwOZ5@gct&@VP5 zb@#@W6gWJy_vig^FMWOh+mOM2rtzuE5ANXyI&t6K z@6i3ftq32OvF=^oZpZ-ehf`k`>|e3IdoPbYfSZei-B)y?a?aGD&%L`p=f}2|VF#|RU29?3fj>-HfA_G~ zgQqUQzh^9}QffNsWK_S_4&^|4D!L+J30{$iF8H^pnu>EtbJ%{Pz_k#w7N%_V>4B!O z+$!ca+q*d{Han)u`WiJl4)5iV&|ZxT+LSsaE#!YKhCk_T+O01t5l!Z78#|Rlwy14o z`@ZQ7inpvz1gQR%Y|~Q;A+M6?7!$o8@hwtsQ!h=zWmU=MDvc7S<4A6|4|Qe-O5@zE z3ar4xFAofZ8`B4ytOpzLhs!Q+Iydo>3M4%%(j^=i{9MA>1wspsLSJo2LoJr1N)iQ2 z^?$p@TEp?rh*B;iodPwh0xf8KJ`a{;s_dPw%rU-=4{=gKWr1cBRfO z$y$7er6*?|#KNlUz?Bo#CL1dGM|QbD)U=Jeq=SQmsWrZdMi|bcQM|}lj@(3-Vd60I zixS~TjXzKGU;*UC_PyW5y$86_5X4ONWdGjmamc#~>__=A9{>Ijf1_sbPp#|RwH9*A zwbq;PgF5fI6$taOj^*{j|Hr3~1sR_6mHLCuxiCntw6z<(Y~F9UP|jKY{mlv`&4P&XF4>cql}P-(Zi zp8dfhLKtwXKmd;&U(1&X(cch~J4s8>mz#K{234^W=|ekKzgFeJ%UP}|E=pD}S;N!_ z_O5J?3{uNV&q$Iyi}UhMVG?2fBeT4S^VN07MF#1%@ayEL+1U`KI}8 zeJAiX#w=IBc4!_xCmN)HvYu{1uYFBC7bm_()q`$`xxI9zS^H^pd%tlAOM_h2cWN0D;sc+JIxP>4!9mxlAx(m2-M zkd_W2V=!m7H<=uL{Z>Hm;diu&YjhCaE&f6^&%bc3}0Y&(m9sm$rjvb8orLc~`F_ZM9}aLP7o!?cpCRcVNH@wZIizjb7)_ zU^Mn)KA5cF|L>&hW&iu({&#=wE!CZ=)DlGuDDVoeKd;<*?=7vrV_Scp*}fm&8+=?H zZCO`h)SV03`u81+SJNUW>-B@!Eq_0VP;Z6RonWV}!Pa&-@qsb%Gfv^m-@Mxsh#4Nm zh=p{rZ)sE_QvGS!o#HI^_L?{vL^H|k2+2w-*@47AvvAGLVFxZu=Bw_CC@IK_^sC_g zlr73_g>BLE{#aY^CBn`(@!O-e%_D1Ri$#$i8_EdSz`(p$uGY9y+`qkGwXTqc+fF^2 znvMyk&7d*OLZwo>zFY5VIriD1O0#wd7-&S&u5bngo#_{v)e^RiFl={~E5SjhZRj9~ z7VGGs_MgGeIB@Xq0lW})rzjKF67Ek{Rw$a4W)7IuWiIaJ1e*w&``Z#=7pcou%H7n1 zhOk8f8Wm!akcf|3BAWkfuk~5u*gL|~d=9n18A$?B@zHhmmYYPOh0#r5#n-xd%HL;_ zzpJ;Uz+3=0)D<&hLV?S*9rUZ?%ZREc#{F!+%0%|R4>LOetlGJ_wvKKwyc-1yt5>sW z4{+#!uhuBPlXxw8WU-)h9)tQjWH`$`ecmyu)2ecD6DFVUqo}hA`7!r6S3v_ZnR8XeLIQzJ5T)4f+aoKF)zAWcL@7 zdvfAO*bC1oZx8Suizx*CONdYZty5|3{#V^~tXBJ9^9f8PL?M3Jg8BS#XaDXdaGQ^E z)dPt#edhMDMJ(3;j-NixCG2GpK$BrzTC`ymKJFSQ&ZJCNHwkl+(iH;M1;FN88R=>) zD%=orrVyq}q%1r;_(p4y3^9(5CHB-*^`e1S8Vb+;BN_n@5()-kd&e=p(YM#`BcbYl z&KKsyWB|7|=Z$PBA(g}{1JJ^h8cb>skXQ8yGMrsIAuQu%aIqGUa@f`DFEG0jE)X1w zyvJ`HH*C3JV!v1yK#A%|G2+Kynt)JbNXadc9{-Rxo0!3;tsu3k9Xyb0N@C`5vWksk zyWNwT3i*Yz5PnrXo_2y(e6j{7U`5Au0Qv$L*CH(DQcbV~W<$sY{{mG$^s{!tB=7Iq zXWiQ2IjXCQ2BFAZV?~^_mY)Xq?emD9%LmD_D~z0#qyQT|;lNZ$`W1NXLdl}IJy7{G z^s=qi+F#OEduDl!@s*&VZ?wq{o#(99PK*kiIGB_uclKB1uZ?SM%;H4FBjO1QBuxP% z&@ia;-}!1d@%I`GL2l);eO(ihzB9qsVwmkVzJ&EVb>|Ipp5xreZ`L&Qzl#cLY2^=9 z;5G z1JQId!jI8-+bPoC`)N6cLtv5(_O;YvK-&%w8W0!lI|72rgq%)c)RCIyjBGS$S2WG? zLt`%XQ;d&PV520ryb5C86ltocJ!mU}sf{P08%zwqJzj5m*EqDWbrUqYI1w))MNVT3 z9O&3e$c@{6Bht_vikMWkvWJ!9FP~Edm`N!VQ}kmO+P16v*!Ze%B*oX8Wx6!9ojLeT zW-IH!Jwx#9Q_TSNwUCswx0qNJQ8luKY^aFT5ag20E|!7AexQ1i7Ftdd+Q@t>It=}rW3?2FG_^eZHi}UaOI!~08Gfnb9={NeGUQJBk z(g{bJDeDy~AP7H(-e`M%M11KU-ies3HeS@NQ%BYDzxjciqxOnRh10SY?U&*NTIh&KudJ)$47)C&#g= zQ{{6=*@&q0U2l2BTj$v3dL3W{H|_j7WvOMUpvtdNzBP=~mPE5x=m}DLoBCqov9=|7 zK4Rn;zpje}&IByzz*S?F%K-zltE`lwrX3sq+un6B{auIr@_9>47=nJA^E{Gf0nm4Q zxPrS|f;#abuT#~kMlQU|;<(0(7A&lV8#u4N*F$GESW1X3Dh0=}my~-8;XL40d&=>ASxbQ7Tqg42bz$ zLPnaIF^SqdJG<6y+ifjwtbk6~Dje5+$z@S@y`(^0rInbZUB$Ozpyu%!%B!l-FUJWmUhD#_hsG&i+UzSHV5rD$HCz5rnICN#N|A;CnEx7Us z2dvSh#e`+GmT=2tM{@}Wp1EhC%5BI2Hbply-(9gb>56D@PK<_#JQiHjJ z*=ZCd;2N-shD*Py=`t`(*!7O5(J{-(PjqOrhN+9qv`eyXQN_kYjxk12Q(tO3^#&Tn%?9IFI!W$7e+6@Pq< z{tS@~Z}n0a7b!}Y@SA+Sn1u!$gPh1Pe}Uytr%WZ>Uz)FEy(ACt7mMnsrAf5IDqI%e z6b3pQuC0ny9E$50*L!I3RBu<}=2^UK@hfp8TM5s?=CZx`{xR4J_2zguL5q@=$d_f9 z&x*8GUsQkEZjQBg&jQHvQO7nSei7D=2rHhnlq3+^Z(}N`9hIcTrYdb>oHt6SeXwbk zk;k_V>No1&CynM+UAAE77V-!lUDw>#p6_}Ug+s@t1Ls5LjB>xIPk3P+x2q}GllWO( zqEj`6NqxoZBNwYIQ}0c6kXHmck0`oJ1{|uvR)@1ev5}I@;e5eJLo=Q=E8RJLMxBoC zZ(tK};t@z&O2SIN!8LODfY;|G(%Ud8DFs3+xMHwAiLM8Jns98$+5Se({5`O{;=z8$ zlfVRzhGD&_m_12q)lgB@?kDm#J>^lznaL2n>!J^x%-?721GQu$mT9OF@t^35{P%#| zR@{{+E|(S%;Lj!;U5*m&U~;l8nx)6pV5wqX!@SNlcKE%M|GAUL1=iI0f4@S!_d7@M ztTkcRlP5<}XHaE6j!vyEl9~h|w?dxz9u7gs5TU(x@DTR5f*5{fK=Ah&ElMZla$~4k zW|o6xh?F$0B`h>Dw^?%OWO1l}J-5EQ05PC33&Nx_Dm^s#TM-X6j93U&BqSi4Ca{#< zy@GDY@P0oA;8^vCN6SZ1v@FxQ z`HWK-xpN2xKYw@MK#)!bH;}O#eLo?;km!0S&>(s=Fw|eQDdz)29Yw+x5-$ZS@GJjT zCe>>X(d)XSC>Oc*sbj~2oyV>MMpW`FvGJIT+ z4yGzYfo=X7uXT`s&Q+CjtH;ruiVd|h@=7i~!HMcOOVqyWfmjuX@@Odr&Pi3De>b^i z)UM37{70Fe@C{}OY8GYO@(uv+eA~x113sy&=ifb#7TBLEoLUHyr?o>13RvL4^R#)r z+_g=k<`Jew40fxGoC^oi^+W5{ygkVGOX1wLrR~6-A;RdY|MlD!9)x#lC_1avWL>B^ z99_XWCiJxG8vvsi5!}zkN~cMz1kZw%q)J*ZWf4ZOJbkAJcKOlbpUM%vkJ^0S&!O(f$m?>rhj{=vA6VIRpf_%IIkb#}J23+zCx-HI z$T3%toD8MJ#*S_yKqzo-DjJRWB=t4F1aaVJ#8GT6C15UG4cZH!Vk7pd=PZ5xfQshy z%NcElG#M-uP1cU^kvKxaD3X2}Lm^~cYg9fz)N1^R8e449c_-tH3qu53ke^wJ@HV!(ed1M*GLV&@MB@W13X|~2mS~fiWToROklg?zRW~b9 z>R$I@8&w|e` zrT)V~PjJidYYu;Rfq&@9F0(Ywq&Wj;tGaoEVXJ7 z5#%kW&>y)29Frw27$b!KbRj#Z*W~Q`wJ}h+F{!@2(%t8;bkhn(QBYFhALhMH@4?TLS&V96VBZ5bT~j26iT5ifq{VJw0Ht90H<{NsWv zhMQ;~?DKqyusKm4znA_P6y&Cp&``%{7_;MvL~;jM;Fe?h`?>_;TaBdZ;76!`Jq7lm zWHsx_G|n=O(7N5w=#=YBOC5C`#S%_SfiJDJm>bOWe^^w_B)=Bva49R%gR{CvMBFp} zGWx1H3GhZN79=2%H;X=TG*N4mwkaVmfA?PVImIBJl3~1!`=%OgL9skwgdV6iX?Il) zin}cYJ`aY&gnP0_(uX+7qz_j}oDM@y5qQztHyawU2w zM3kykQM@RE)kPBnj_H^MO+v28q)Rx603{liuD8-T)WQhb-UbfcuV7OLKPEM14&FG_ z8dIg_j&tv?w81vMDyZ14-$@LlxTAXTQzRjy%%x*ZQzDlwDNtKXtdY)olOktz?0zFgp$inh(6#Pj0oXyRT5|rzAfye#1#+cZ38UybGH1iwsJN!c+l6pE=Tq`z- z$)R(GWg4>#A8)l~|MRC$tpbHZ2ODgNE@_LIMVolFJWV(v1$FHE9mlEfo$q$zcxQl7aKv7~#@pus0Fy!NDx|4Ovt)3$G@ib;**SrJZ>z%Z2Tw5q zjYikz!)E3-#IO+N3H-O5FhphjUlhF}M!xUh;G;~m$RO|0pgn{Jt*y#aglaqGe|@;D|FTH`1sog z9VGYdWyQd6w#TVMVGQgNLk~K@*=O_p=~GY;vHu4KmzAW zUS`hjZuFNFPzIM zP5HD9g{93o-bm7_+gB+|4LC&b^M-|Of#7`IOl6FovrS(#5$=R#ky4cimc|-6mSnKB z=@aF3;{QsS>L_hS#ReV_tiUTgHEm|PLm|iYK=*w!TGP7SgE#UDYGI@-sD~@(pUjsF zH7mkGR0GDEiE1p^P~CV`4_R$XMpAd9K|=osIl$QZNeFv!Rxn49KM~Rh`^8#ZvDSUI zP_tS0L7XetC1fR8n-Y<{ndD}V3FF5nu;g5=*`9K&;799MhH{toVWi<$yJj_AOOD60 zQUl3(iapCQ4LgHfsNgZ1a&GAK$j(LN9d-s=JamE@Hl6w}xyA*FLvoSfmq0~{4EL8DZTh8UTrRJOxNSDreuI0@c1_0gUsGA)<= z=AS^iF)wBywL&;N4v_y0Z3cNTEPvY4nMWKDr-*EXgJ6m@IYLOG(r zK2m#RcnhS}I%30;lgy?ih>(@kn1&7W%NSn%?Bk4+Nr{VgSbOH}+QtGWwxGO1@uU(A z!_w8#S6AmQ9spHbO-ER()^pXvS%qMA6O>!6#80uyk(xgvUnxd^8dHI-0?C$?-@! zbNkYSsRWz~DQSr!UylyX0XI9b#o_zGSriwNf2!Wr=sdEzaK5%%11_r`6Fse&UUUW2 zM9(V?exNQ_@nX?0+TQv3hxa~($N!Zx);@l1bikVCpgU1#?O?Kh@Wv7gICNaeaz>-V z;Gkw-H!5}_nL0h=_BAX&jmq5Me)l{kjN$kgnAZKcNkc zl|ltf)7uRBt-9-L`SUfaowAGAaYABHX-h-Ex!w=&KM*Z`S?mTdDJZ5(0+b#I)|%+GDain^vS$B$Uf^0iVhZ;#9(xy zFMES*k2-!%{x^B$d%bbID;7D1D3DIXLz&$eq3+HUX6>Xcpv))< zm*ogPw?cfqTwI)5SEBwulL4NA!aPb$N}D#$-U z#{+ADW7u>uV#etjB|4(9Sj@UQY>%M8Sr+NQ;BCMPwh|W?ey=Ka8T!U9z%h3t0k)39 z_yEWoUhSlvq(9IIk61x6p0Ou{!$@Nt#0b5D z!-k`T14$Qs$A%-?Sigl01=|zq*tqZSP})2d^2ls0wZ&#>8Dru-j)qj~FO4{J2BuW4 zQxtX+_L@{VB7x|J+o|w`YU^=U4<+k=c0Wo*kX5vl9vByNPI#)4HGo9XLQ|c3o0Q3; zAzK*)tmwfBJZ||bEwme1h^1+om`ag@fXDEYk~=e&JITS7&CJ|-^ek4uJPHoQwWj^# zjDK_cNBaCJZNk6EP$5!$7H@(@Djkn&5VF&G<~q3J)PT)5M8fd+Fo8g?&fTG=YAU=? ziQ3n|uj_E)@D=m&|1VT`!G)^)a%$5?JnS^ypx-QcqFvUD7r#-Bv(s{JgrSqwt|Y@> zV5aZ7d(pgvp_tP#f1Y7m#R;n?(lB>h7BEOk(zY&X-6aYmtTJ^>Al+yJcnhSGpf zfA}i7Va8J00w+NcM6aJJwe>^#_3>ZN9Rc(>tZ5M%zklMl6x-h_}--A-v+^twh z{5mhq1%buarKiO@LwH~-f6f|+veHdl1X{BLPvAEg3s6V2r;*v`(3EIK*oim)j98ct zKHB7gw3!AvR%@z^l}7Y=O=KpxQ^&!gr-zQ2UENH3r>0|v%^`s)V!a!zI7WmVR>@JW zwZj@?5i&VdPZeGEf0_)&s3M7M*+44YS_yDZ4*N$M-Z{`-C6f)yEo7lnF%wllV@TSL zLqx#SW6~6d6E|5+Xr5wDElR(=w{r{73{m=^-a~sh9PfyD2Gun2^FkPW!XfLc38M}^EuVgiuW!4Gb!3j}IT*i9( zrjc0`FLX^%I;V#LbqBg{m!S?HmYU*VLvX?(@2r@rD?8YY0VpTKLi$44&PGEysa{u} zZNP#U9a<1MM8%w2b;l8v3@9f(`y{B%35$s_bV)=?&6)5rt&g>`izj+Jl}2TnLciOb zs%bt0Tao8N0~1TV57}H$D~-HL1gSLyfn zkdzK#hyezW7Nn#EUOEf}rMnqo=oIN0x*H^hhTk6F?>guAo$EW-;UAcpXP&*;&sz7o z?{)3HR!D0EHNT)Jb$=s0A-=ptQtP`TB)N81pH-*k!kd&8iRh&ptQ=Pts4~6D^+yhT z;`g}M`Pv?SppMNcblA^n*@fnC7Ma!6FM^C*0Q^o|do{s8LP}jMK{CHK>($AyxweRD zmJUO?bm7aw>dzwKfhZqi!razZ&4w!n&Sd6c`G!3i%AU2T_Is02jWr|EnN-t{(Xg9|K~A=K4%4D&?4+qd{mt-z>TdKjzHP zg`5)Y81wP$+ga_*bBbuxata!?sgoyIv7ypfWp4#dDz7j(|K(7<|8jKL#`>9ys-4!u zV#oNKc3<9o!aeFZxpb}}y6IkBFk}h}ly@V#O9&%#muh zOdV4ZY6=QjRqriI>}c31MMQHZ5nq~3_e~s)$TlR$_{7j5({KGUG!GeWz(aUUKi5uFRzWgraAjyUW6{rmfz9D6NG^$k7%q>?p=->e>eucKBb8$={;^QSDZ*Km_+J-7!eFI z?ua5Kbq^h z@Zb%HBVFI;_7Vn1rtYHxBngfpneA@hGgB9>q1%0PwLQ-5!ve#Dk0YGhQ-qNY9<)m~ zO%5L7lS1LqbZmSN=fO;p5=MWITxMv^NawjfJ+W$VN^6el8ZVARFzt>`Pk|Mm%hnX~ zVl<>aVT^mwcv$dmIkG%>#2d|^YKbK7ZlohCxL6aZ+Ll4lYdV%*2VT`#$E*fd3 z;=!oshaGuP8j#U7>sYWJ>9c zI=T70WyN@~N7(hNX}VGf1o8|0cuzEHLW1p===A82gyPsnYVv2d?*WXwkr~9n<3?$) zr}M=pzRG9I)X?T7XQ%dv)`bc^idQGPAg&}yHAyHFeY9!)(I&umO*}lm$X9ICAWfI1m&BelvX}gE7kFxN?>$Gb~|24edbGU=ffH^D){pC9)==L6T6B@Nv4RiB|n?3R9;2RRW;V5 zZi>*7%;h96F;kJ5i>Tt7>WAl&cKr*Tqq0o7`t!$MoNwpodz;r?v{l>Ek(SiaQ0ok= z%tV{IpD46M1@BJ)O+h775gZUfl6NF6WOJ1fzC2iearHt>%Z)ZH4zW;Kq8daC?RkJV z>JvulqPY-WlAs>tBJ{2b>Kuz_-M;T9lTIl2i(2^nU=P;*K7ChJer1>JfikIV^WtaW z2!>ysgF7LbGq;tI$x117NZLCS_I;Tf2HwcA1xBc>YSJ8AyD#d_T9F(C4T0P0EkWs&Pi)p`oEl zoi9o_foVeSbFzGxs;{p%3AyQ7OC(cEQA-4Y2vomc#CrpQzyc?BfGo1?~6*JAUXP#br<#0Yz78>gXswdW36fY1vGkr^}^R8U#inM~@a7^?=&N-@ku1=}!~a zDQSeFMIJtUh<$x=dMLHqgx5@5(;?14p5cSh1GgS8v!>V>E%=(BZ?7>G5*kVj-$J#q zXL`4EF#D+}D_;l21x!bBU*^9md4~+4prWUL?&~Xqb8>Rh+TIR3-Zj<9f7P7(GVfhl zKxk)^=-l9y*P!1msrxTCx2Njvf(2|1qq*GRO3$CuyB;+!{N}Ul zzCFLNkSyuWqif_w&Cky-#()quN3Bd;GKn#efBE`V-1pq$r`cUf$~7n$Gye>Uj_A)6q_aSC`s%ItBk7+YTK|$d(GUg$i z>eekW*kb5mZEkLOP*Bi4#o;Q&NIJ^~?$=sc^4{K3H&I7zOEBj#BX{Qk=_99=boXn4 z`!YDKt*tQ`8U0|Tf8^zXJ@j~t`}TemlMbSXhldd~{16-d55VOr!2mhxnQBj-5WMy| zqz3kN`_7%%iyj2YeIIq4WHFMYgK4@$z&dDZ48}+6z>$shnPB?o=7F zSo`%&B||DXgxPl-C6ly`EHUr+o|lI=d$!XE<}z)%x7d}HlcS}rjqi#ey7U5nv~Et6 z$s<+_6ch+WpBCe-DwBr<0xwUFh#-|>qNu50qgVQ-}ck>wEhN;4SyFHRL#3egoTICSBx3ofE`FLfL+fkV0SY;SQJLB zY!%#Db-&Z0Pqh@n!ot9!Xrem;$2M3wIX|Es8`HD0SnhDWY67j{+J}E=>D9V&;DFlR zmUAud#nRP)G5*EHMG7MXfYI=r^Ltn*set|?)huhx@6VRi+Knn zFgch%G!%d0TRslWYPbK!Sdlewe1FGo2>_6f+X_RKZXS-1_ErU%G5D6Z_pD4VW1!ed6R}7k9EB)!|m9)XlwQd{z6EdQriIbC)Op)q@ObwR2FbC|l z3KnwfVI}=^yo{&XSg2NN8V=;bi)7NEqNJq!81pT|2>ix9NI(R!VV@5qFeqG)HsYU4 z8^5*~zI_&byDpLbtL^8uqZYo^;_7dv7dcZR3y`ycs)EBfwLI$#J9Jw=-ttM5WQXZW zZLnuQd_^1~Y`y;&D$(Ztu`+QS(ZI6=8^x%_u^ZXA4ec8>=8ehh$dsWyT|u9c8K&SX z`4!u*5`~*@;HQ4gHdQ-@9p$ptXJB2>1s5wQ2V=fF3k+kGQR2F1YGYypHRosjF8$AI z6wkCH%20Zl^s`rMF54LE9lJ9_6CG=%{FH zpFj`L4o!62Y~sfWo;Z=%nlHh)U_ATaP*nd2{IarTOsr0N>*z$r@oXHE?%qr}}wq$e?R5dguly8VxP0s;lhVH4{|X+>#+G zre_m5KSMblnIR8+gzCqCzed}of0g&DXN>;5b&7ybkBT5RPKr!(wrDo!3RX(1md$c5 z4t>OrF@xJQ#q=f}HW!mNQx4@0g2nWNBKG6@jWKZK5y@;w)fljc&&o&|0Jycv(n*ku z%xtEAnGG;|@bfq!9BV$5*Y*CGngWZ(k8$dM?CSr#fExI$Lccs`Rv4-G`ozC~ODCGt z{8+P{;zz+nDZ3hV3<{;s(|Er3TrzCpbO237d6>4nXq9$YBD?Xi$Vk@h^W^DTl|d8F z#fB9QCW9oW1E3j!BtD2RtiS{k;^PlmZLcMyq;w;E&Q1?fd|2aM0)O_a*N_?h`0=Be z{E>pf+c2#AV>!?-ds0Al{<6&`_}FYJhuK_SS|X4PGN$UTd1SMaGf7yeF`%ws!6&FP zBoxRP1Oi3626G_eUx%CF_`3hav&cICxE19`Ijq}<2C*DYh7%v`XH3P$-eOZt2^w0n z*g{pLV?dA1e`72Niqce`1hmV5^wSqFZgFsM^d<|26g6H-5NpB*+F<)$8wFK-q~=Wx z>2ylI;3O{_2S?cAqQy4iY+EL(_zZkibjDl$?OO@095ukk-UIw6yx+b3-#iSHcBVSC z2u>WgtYIlu%jLz{nb>2nP-GXC|B)pzq83+H0DtM3Lx$*;m=WaZ6p*|qH=L zAbie`8m}y;>pjmw-`E@fe1bzpMpl13{~_z!Hv%yF4VK36aFR<9C-*PUc3f6}-Uku> z{k;ebWVVw`&H-+#9O1_7eUA~;L&GUm%xE$j0HLnpOeEML>qd;~%;z~hwwBBoX3 zDppJ%piN0ZyY;p;R{`gF1so8hAdMtyX5o1Y^J=;Vw9lQ}$-$VTSMNnn}BtJ)mg+=Ky5C^H5vVD`YC{EVtdnf_RXYfyTsJ$NDfdq$iPbLO@M{}IvPw&+f z7&oM(IwF!2jo*fWNKt0q5rrTx8%yK7T3>%dUDqJjmLGcX&DUTvd>~sjb-c=v85FHB zE|y=TG%iX6v?Pg)UIbq<-gp6C_v8EbPoQrY;8|AvXh)uq+vL z9WV7da=61|*x4LNR5Ee875Wz?CGFzrmgD!JAp9r>akGZP++4{0`*Zcs|Kd_#)E73R zFTC=bl^>QyfBtL&_evJFyFFME2dMrc=2@7i)7@%{UF$r>4jkhU3 z27H^rY^r6-qyvjXoUU`;x^)X{SAC*0n?KnE1>+*=MPUn(qA&iTT4xs?M#NlIctqq* zR~JWGFJ1_kw0pO-xqOI<+SXv`OA-EHo#7cg3~DI^p)CWvx3;Sn$Vo^@s*k3UU{q{Vu)M@Tvm)^{4PC#SU?7o;muR1_@|{YJbV5e{4cEh{2ztwMrUC)ILF`sN>@SE zboXe1fwM%q!jmVzQFcWH;`4<7k4#VYmOP}Gd_l>S-PNzrm}6n>&hSpTtfhBP6bQwD zfeMcqA|-b~#cVSOu*jTGpFRz7{pCAl#PbSpr~?-6yIc?muB|N8(8Hrz7@7v~bHNk< z?yV%b>_~$~UuodzM6(}w5v!wOC(|jzC6$$xGwQUS9FN6imqeTnL(X4lU5ytk)Yj(a zgV6Kw(LG+?=s!}`S#63@hhHNI=GzUOB{@7t4e=3De#BK9$_@)n%fw!bTX<3K%*N(w zi-SXSrmXNt`yWnEew?fh0zf!60FXMZq>4CvS}j6?ehz>A3+{`gRi)WLB!t|5{wEav z&nS1Q00dtgn<{|RQlO~R&QeoTyZZav0m3FEC<3K9Lo}g!w`U7<#(MzpIzImPa&Pj` zlIP>VEwhu8hQm<nI4{zV{vXvk!Ynznosz!(i(58YrjaR-yLaJq-J~j1rcatc7H@c(bPzT=< zP|uWsrexb9_PROo*hGg&xnzfg`T(3K%bs+p_m-CnftJ1}>Ng=G+w@>j?k!M{kim=8FYZvDbRmnVPSFe%Vvfg z%Q%%p5mfYu2h0n zy`QqOvWk$Km2!Iq4R3{0MW7Ji7g!+$5cUW7z%AvErir#km52G9VSa;>83dB?Obdr^ zu?09LicRGKxKcY*r2_cDI#zD38F<#-r)xPtbmB{vGihpQG{v$$e^moxt#jY80#b@W z%Hw7#x9h3AJUgIPYgO0uepUO>SD{sXe54;JMyw8r)jjyRl;XZQ-mIlA-3GiJ(3I7l zo4j3Zdv-Q9v$M^Cy#T1Ny2*NgNkCALs8#+Az^YqRR9(HjEL>a>oJIAqc7-*;;o;#3 z@(P1%UA(fgnfdu#I1cr{6;o1Dz84g14T*WBVyWDkTL71BT5@t1P+GWuJ$z_}*_@yW zri^f^V~Lq0XAo<`o|*-7ARJCoulDdA92^`T9R(=>WlKv|uzn^z3EWxP*@XP-P565i zbqi6Fe{pjYe5$NW*xQ4#sin~b+0^mGoEKKllfbtpuQyp|`Y38?Q9XDXMXFfcpa>u$ z^q>~=oK79cW-!Blq2YL`*d1_=WI@YW5+z|aSz z_DLfnBe7)Db|~9<%56;3&~S2X{MWA+4viP^jl)0+na*G`dYof``NwPOe%)lElX8lR z!PIe`@4sUiKP?L|igtR(`bR!K7f;Y?sUndBvR4dsQ~gHnQ*9u%gnPUqd({P`IgO0> zv1c@xVG4PgPTs5=@p7BtOnU zr!nHySG1E1&E#@GJe;=g&LQ>6Z7BUtdS25ASacGgD|sKgz+lJV40q4oQV$0gmj!UK zyHfD=;UC`M*4}4ZRSc5wi1G1Pz`#R#mgWI_l?K(98cQbZwRLq}4puc4qnUgL#~Y95 zZ;&%db%InS?yiRv;Einl`Ig06*bJ#aC^&W1Xo@Pgo%GsixNGk|+l2c@@muU`@HyYvQ*cMSR&KLu$@9LM_KgdI_g3tyvUAiy_)+x`R(XHF~x z88Eg{VSIL!nyn1rAArO53j~C&9TMVPKi+Ln14F!j|Nb^LH9r^^OIX9AquIeYAeh56r>SBcB&eKvg_*Z zHUkd>CnzKYo9_ZS&}!g`$pV%n*cEek3?PLB)2?uZ|I-Dh ZSIR!Tih}+U#5mwb`H7lB;bW6`{|}&iuCxFE literal 0 HcmV?d00001 diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 000000000..250f5665f --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 000000000..0d49244ed --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 000000000..7918c3fab --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '

    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⩔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�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 TXAzxk5qyw-ItANWi_`xf+$gqg literal 0 HcmV?d00001 diff --git a/.doctrees/basics.doctree b/.doctrees/basics.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ffddf8ab8324898cca7739d868c221ad7e03b7bb GIT binary patch literal 60290 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 b;1ZahIV8J1x@3uKRRG-rpU9KQI_>`hso?gS literal 0 HcmV?d00001 diff --git a/.doctrees/changelog.doctree b/.doctrees/changelog.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0e7282fed841a7f309b15e2c22862393c5422b2c GIT binary patch literal 245195 zcmd4437A|*btvpbvgENX%bUEL%Lwoc%=D~Uu?^a6%UG5oSw`UBnZDC~XS%JP?x7b+ zL%^6V3mFKD43EWRBZLGJ60*J|1QN19Ucw(B$xHI`5<*zAC*&oMEF}5QsavPcxplX? z-7WI-A(+1RR@K?-)TvXap4|A-Kwb!W9!Z=Ngp)oQa<4Lax7H&(vgzys6Ug zI~{lke{XF1E8$<8tG!kJvFKM$w}U18rnkPS>o4Q0^R=sMcf9D5+U@K2Pt{s0!Bo4~ zYzFPAv#s{&sn%-H3|f<`Yu#F_Iaz7c0np@!2kzhZ(0zv73W2ZP{!r}>q&ZSVsY8%%-@Ng~gmRjulN>jpxps^ ztv8ps<4&-0CTN#h?d7S?YEYRvGmCweYTcE_cu2{y+P3u@Qy@Oi)VW(y2N?`91t2s* zl}Nn+^{qCF#H{!W?)pC2bvohKFM}a_?fUukXSt9~G3pR7YNKY9!T^MG+xo>5sffYL zk&KtOWpN_4-MvOMu1jDRktp#UQ>o%crP|5$?L?jo=4Vl-l!i!9%QL{(xUX6bz<7n@>t8(Z zn~M#6r5^Z=df>~~uUPCg8bNoVQSb0XBxjP#@y$ZL8>|RL3dvPtoASLUdaJ9gcGqhL zXT6gL@AW!$Fy!4{JJ{=$tHF}zudX)M7OH;Nuk;p!G5nvs-a+`euif_7CcH|k*@fw7 zuUD;Cy5rvDJ^ZpfGWO{9xtVFU8q4)=t+%Mm&{3ESCJ!A=w*U1`rx$dlpzZj$A|V=+ zTQfivlJx;eSuiM@8bE`#-w;$-f5Cv55nBiDhXvvz66|zig_8JVAcg@+Y?a8L@_Y3NN zPuQULKC&(`{rM=UxmT{VKo^x$w*cP8YS8Ykjg6PRTF`*M(GdY_RBx<#i#_lQL1pM` zZzbsZs9WfysAe9xA|S3EoaeprffjgAs^3zhphf;0~jg z?6sD>;2h|39hZoH1B^qh*F3$T+m**Xm=xz{=ZmYYo)n>Ny5c^5m&Hq=yEmm_LUNJ* z0n5rktN(0zqY_^mDzSk~>G7S8#1m4Qf!S3N5)(SsQ^w(u;oxv7urdoiseQmS0&4?u zU$m<^Lo>kKibJC7fa{h-hDa4OtfED0z7|rSdo(h63td!1-KLhSh^PJ#dVR!i*IT`g zS6_jt@=SorrIx9SxN=$n-Gt>SEb+TFSkMOEzOz9G!VlgFSetgi`ST7p!9RtC?NXqe z+tLU`3|ePVQycXPgk07cPxC`ry8Y4xZTe@b1xZufF7=*UWQ$10pAYNOP%G8o3vI0e}NXY%MJT zC;)2&rKNUjB^{l`pbOptVFT;+p5KV$0%5Cq8%&h!xP>r8R*2t#pqyy#+OzwaH6-1ddk9y5X`Mtl+lJLB!pgT-qFJc z4|skBW-FZFP6yypHX*uOo}Zra9>(8?n`it+y;}C*^VL?f6L@0~$o8w%I&Ldq$MEf3 z^jqb2?wH=)x4DP5!c^Zq5Gq1!{@fB9;jeDB5hl@#zhE)^d#k^6m7++>O_`EG&T_0G@?V4ZMC(&$8F zA{uR@lJA&OpI<7V(YlR;M&GSgh{s?{3IaK}9kPf!O}I8(@+;j|do2v(gpbQ!cWo8i zN&32@2#=9XEBf;IPK)wFDXxtVM*K^9#j}?bF&=iN^vj-BV5B_4pIeUlKlJ5~1V43ak?uA^Ob-y}K|% zw`+v{n?b1d-4q+uq2csU@mE3!U@_Q%Xm`Ih&V2m0CoJS0EXWw=))(%3VqmO zslCoic>mxq$(IF6blOdIq(5e%kZ!04ns(WdeufrmqK&fik!hFSkZotnBn^^GVxT@h zWE3SG4V?Zl9z<<^$f3>SUHItn9{dlsM&n7XSv48T^-XPU45AiPJQlV_D|rE1v+>^g zIkq(V7u%V?(+CmyvPpr4b5yhBuMH^**qQG;jJghSq>kR&#jT`K3~xzuGYT;$FdIEs zJ-`+&MzSHErVIrJiq_IYPD3>jl_Xd}*==ai5cCVL(8)_LjXKztE1as6S6J=RIXEPp ze3ljf0ywUd^oE3rr9Dk2sn3fvGA<4cwfT1=i0P=ub&^`M7&DaX8<&*QL^aYp6#A%@ z!O}<3(@4)Ge6WiIDIfg!F?cT0tk6@UR1SxXk{ceKF3s*JO+V&Mdb88BbCWYOlhd>0 z&ZfL&^*`V&JZQ^M{qNM=f1%-2R;Gz@)pV|j`OP3aTo{CL4Z=4u2=1QFUmk9D+pTJ^ z5_o0I^ElMnw^~2e@axS(?RKjTt0S;T`;Hy<0{m%~+7RwQlLQHjn9BzqO`|c1f%l*~ zf(^o0H{_XgAkeNh#lv`ixOEOu@9^8ij>i~|5QOnC{=KJvUuS*~_&S{GHo`aygHy8z zFIIBbB~XTBD)Ak&bJglKT_;hZa1-u%nw=$UcE5wr^lAW{uD5 z%`Jwqiq}L``!Un=4a1@5B_IymX#xQvTMqm_8qkhJmiePFeKay*fdmq6u&D??c<}c* zV>G~og+ro%;ih7ufTa;cAk1bwZQ7!q1C5f)v_)+e9oodFEo#lSkDC_nbJD{+lB}QoX97@rS(=|n+_L~WfgCR4bigk zDIwroey|0BYmqAxoC_e+9X`UH#XWPySCJ}J1X_wf^OX_~A>d!J$RP~tW`dTKgCDSh z{GHW4--OO+a?;4kgkC8L;s)N0DP$vPQ{OZ27jKBVv3&x6NhE)P@G=Hlu2+F61Rt83 zIf3eR&cJ}F=`VW-2P8w2$cD&j)kcJsH_gOQpI-W#o!JBbrYJ85!UqFLYL62heZ8 zrh%ec(tbe80#q2gn@v)e-5qfu;|u1*S!;xB`A3g(w<8c75*9t>#4Xjq1EFJB5ZqVq-rrmF_NmxR$McsV z-~;CIm^$z2&6Q?mJ-?&EIy5)+-JTis_s)z$O5*{`yELW$rT|r_4O1muvE$wz&0*{| zaBKATcCeSG7L>2B7nJ08klW+5pfqv7^tj;l8;dL?Ff@6OCf+r=C5Wlz0cA|jPalGu zS2!f?l~4J2dW?LRG6eM?p*KvQZ&$&};PO&0Cl?yH%v|VImoTpajMP|nLRpB;ga_x( z&W(@2Go2NzPO#PCK$<#D<1f}Bfp;y85(ei~+;AD1R!&a_u*V2(8Y+)i&FCEt9z$$7M-mZYN`_y$~at~L^U^%uS=jU!JYVyf!{wY z;1f8R1-unrBubDm1Rv$TVaWj_YmdTeo3@lBPCeV`M>cnHHm5eD4sGJbg<7*lGL&ds zc1Deh%)1bqETq>l3lr^Zo;wTIlkvr0Y(1&hY|iV+x#)V*+G&ZuWp=%~kZhtkJE#@w z2}Ak;){}27Jp8?S`0wK3Eo+*!p8Q=p5W5!m?Wq+wh+BgU5ID>Wi8WOZ7Ak5VCA4m; z)B)t3w(u|nq*8#p1sg5Ps*Xhm&n#t}H7rkfWir*J@ONxutFxppCc{*nODyARs#8`jl_k?*q<+@`3cE`x?6zb8 z1S9{^Vx&;LjS5T>SN)4c;Okb)e1$r!6^h1G3bg^r;0Dmu7O@Dl*mDMQ%VkB}Y1H~e zAfs`4g5PL;L}_+OrGXy|jOPr@AW8#6lF}sN5>Xl(m3*b4KEG-dAe-^%PEi{trP0TS z#Nj`znBjFQHK=~0bcPeI)tW`dX}$35QF>#+j{O!pgy>%r8-ipl;SDqR0jtMs%AmA8 zpjCokaf#Vdn-}QOT+9}=apJ%svKphE-eMOrQlS;!*@qy;B=vFXm*&?lAmdLWF!HHW*ub5petIvFPy-2f*pmAXr zwW$_h7qww_r7LE9{XugS`>@;^*B`ri$$-I)#I$wtgUJmaR(#`Kg=mfof+L#d?=bYU z;~QBX`P2KuJ%efsx6L89vOP&Dm5`;R_7=uY9y~VgVQn7xWUA7J^T@EDuoue*!0F>K z1ImObI$;KM7|s!$I9*>gr@1G?GHgw>R*m}0 z6*s5!o)T^pq2Ymi|5aR>sm%Od6U)LZ^%`csXiBlEGt#J^4j}u#rH+g5H6gK%87n+m zu8;q5^k;PBYz(WwFA}8y$o+$}ISUG2P2P|w3^dK9yk)ih-xhtd zRS+GMV_I#A^2%3#R*vv};mP+$67Hz6ag?o)A-|83HIi`0A0;K+&6})W$bx|%jPuu= zaUR6mh9Sw@P9#~x+qO~RX*q3)N`3yav4q*IL+eRx*m|aq6L%iS_VRSgtu7W zr^9H{F6KVafiT)0q2J8ZJ2w?s&!PKpQVa64bW0FqE1;J?x2$*e_f}Q|sAd9(wO}%# zolkh8x6r7>5CppCO1o6FZD;@0_2zfV>Uz^f2N%Nse2Y%eP1c>FrW}kZ+8wakrAyl& zN&`cZ(!5x+hX7V~CZaU-hKvY{W17-XpSumq)6qaUP-&>m4u>{zrJ>d=WDMo{hI$o> z_(e`tJpPyVejx-rLBHJ@uYSR%bvC&6L7gK%F7fign*o1@| zeer#_*hZh;Omp7ogObtaNY(W2$>}{L(kgK@{+8wX_nifZY|S@ox&B>4`2jZi{-W^k zWj*|td3eh&$OQyTxWz_eCW)M4%Rj1?7sl(3=#W)r3xP-?{BcRJ%a zz$Ae~(j<{crpP2=qrxUL%{in#|JCSy{v<(dzGm8FtQlTM2dK+xyJ|UTVND1=r=t`( zwzsc8!-Oi#=Nwu!(#-^o;NxM7kHV+9Qo>Af5PisU|4mju*@Q&7547A91WN9=(6TDD zac+R#Z07|S0ut02UoZ-l;h+%RA0+I^bBQj#((8`)oPilYzhvFfM0P~<%SI(%zo^f9 zH8L){Q`E*uzrKqkI@GUT8!}$TU>6DE^;qCZg=#zFQJIRV8?^d{sM>+5&|i28Jiy;4mMG3i-8+i z@}z6qC!B#9lC~vsCZcUND*4(*eV*6IxM&--aniQe!g&C%{D@L5QFGgDg@jskH1X<) zYP$~cvF$T^b`@|v!$wnjCj#0E*VC@b_9csjLc4Cu0+|Fh`y-ayzp=*2*TQA3g#@9} z!l>NRE2CyCw_YAS34#0%8HxXNMxv0s$M|Kuw?rC5O*ciUg-qOD|r_L#zEF&+ZUH|GWYa2`m20%cF}Dp&Q$h z;U=Lhe11XY4Q(5nP}zyj^EWH0<+V4m*`Od+|}m!Z*)C=5xfl0;l0 za&4oMFW1!P9U2)IJ5Ft!5UhpD(ghmFgp=4jOq7c>l`K=>z@#!4H^)w z#cgzY7P?;H(q(`^!@LMIu+uTZrkq4nK4MAmoh1QTiR+QN7R$#B*&*bxEtxz*JKT zv^IHvZU|Uli|;pu%Tw0AQ9F1U+zi+4?DhNxBrYH1N7`h_Kazv#3zMP@nhr z#%8B+KOJv4MJH+*b^+nk%7iz^k8w5MS!-4xxvq&fjOep*P?jtlN=3BicMNdmc?X|) zX7e+`ei3Q5e8ie`=}6SK%J+X(G}Zr;slILfTmB0vDC`2kWM(rfrkwO%Ub7Q>AGJsF zK=%%Lp!;@bDh_0i_&|3e6C(D=Mujy!Eu2h!e%&xOTNrT9k=p!=Lz}ogqSmay45hM1 z;zXd@b4e=J1MNdE1J8WToE{5QD43IxL zC-Wy?df~tnTI^f2j|QE0$TT_l!M3b!wM!S@L9}p=)8yKkhqh87^S0uqK8^YZ60-K6W2m&&4SBNDlN1s2yk&#vGY&TAJajrFHznu-1?92#K*S& z_4c~+*8fathPVEAP0pBIK(+NBf6Ef|z0MLuTHn(m@Logu%&mXWpNv}0A1OTiSv~xR zd3blD^EQCSE9(+b3*oul@>H2l-_jG<^4CdF;Ny&{f(Z~r!VGQ*9*uh8-UY^s^rE?s z6MtcCz8&(s-v$IuDEF^fv=Kp|Em0K6;jtexn?G&!m91g8x?aLxIMxUDk-y=Hm`+;8peky#?EXx4~UU!r_OI2*)`b8I%y7Pr7`AQHh6W&`^z3-evh@fj6|?gm&55J+#>7f%Ko@5pyHKkvkb2OXrc|kO#u}z z-+xYbMD8#zDUe~uWm6?+y}TO<+Y(zh5SrljkW2uGGP`6bI;-Rd`gdU{ebo*+`w zQ!E%rZ;c)0c)=~{+$5;8K4I9uWjL_!?O%kl7-WS5Vg!NrG8_k2{c#JEp6 z6Jd~rh`6pWk^j+HdNwZe#z)4pM>5p`kymvvrJU-S*`o7 zV?|>tWA$8hU4Rq4vcP8reU=MV$+o$D%t(LH8EH`PJr0-JCv(o|M4V*#GEZ%O-N!rZ#PyI`v*0q6sE4!G z5x$hFeI);dG%+Wv{%9et<2k->*IYkkNKrrwzr62EtByL@gR^)L>hjM73ven0!t7-@ z&;mEthq3cYYh@8a>UbH2@PozIX3ivyOQA%Gi!Oz-ahVr) zR)cm4sr=+O1Q!^RmO_cRM3zD}Ds1S}rX%XJp^PR^O5$ZCHn{+2cSqN|EJp>NU#^xqBX zv;5$kJ4vo7Jp7yW@LP1tLO$>(!{w&mgBywA6eu22UxUP#W^fkjPr!kCzoLp(bz89C zt@o^t9zJ-$3td1nM@$}5oX+EfH%%~w+p(xlTF~Ur^>5X(LU^dT zK4PutjhP;;Nhs;PoP=WUBa_hFPC^@IB>2I&+~+O;=NM?kr*svD$XPp^Ki~6Uukai6*?Bzt(7Re=8 zpbbm=*O%(BwlD9;4G+lFDPwW8TC3WDHAdHOcVWE%S>~9q6aED&jY_+|7^q)R*KFj$ zVA-#%LHbS|4rNfQ1<2uves7*Y8+COl6!vR0WMBYmakrXx@;yO5WGBMOd$5XFAWq*J zqyi9lX^=WUzq|i(B(u9^Ig%>`Erhy#r^OXv$TkzjNLBd(tLxjW_Sqti%ZztuuF}ZL z^jvP3;s)C$%{l_j{AS30U^tLP-BAMCSVi8JxhxbRf{1=HKtFR~0TQ-JFmZ&%nIMyo z7`jgl2fB?DQ1|ZrSxmI%kr+j{tzT_vTvl&P|0|S8gjz_bMxHUQe>NOk(?lbg6I+NA zQ4sCN4COx!2g(N(N3tx^7oL2lt4+#cMJi(@J>VnhCB(Qdy#z2|#7L+K0Y8{FS8s83 z&Ij-ka7gkJ60KImVX{%-sW;6*pgzA{GumZ&M{Qnj+GGT_-xr3Ay>b|KhQ0r8+b?02 zYWV-gLcLk7gIBLo03J=dPs=+qUBbIP#we(*gV_*=oAS>Foz_Y)Nj*;L9@AgI{SX1p zqElUec}jK6J6@YKw1Uku7Mq1(yFC*plAD~bSfKV;BjwLy@6z)a!Kmi34Y(Jcg#gR< zGjb?SDCB;}NW91y3DAlcUm%7Wm5CE5UnQtbNn_%o64ZuOB7K~=&rAx%PA0cjKJz>m zz{<#LCto$@HCw&Ka%$rth*-=+#}!;-9y5EQF^?Iu*20)a!dn)gS2+t1`RGq;EqH}t z*Z?t)Hy0lMyY=vI3d%kJ?Ud>g4D~wKzWI@b!6#@#JMIQcO zSbotNmI3?*9H0D#I4W!q()vq^@518VbL( zcC6KCJRF{!gQMEvT^98U?Aca=@ETpz45bHE)yAtpBX6kz#pYI_sX2A0L?bzc<&P}# z3qiX%6&Mn=j4znMU$jQZrW~$Ezh4U*!KQ@mu7L=^;83TuUd(4cf%6B3k=ZC9^Qny! z^Uoe_!d(O_m=_AMhcory>|Rf2M47w2^a}`ZsN6nfCE*e=-#hh^mwIrS0g4Ql2Gq$= z82DYSsf5#Ny|dbY>hiv~;;+Jo)#adT#Ny^u0EB{XygKUO3rV>)4kn36(ko`hRaT$b zghknSpOy`RM#;tlL!=1t~9(d7-()y0^N~^ils8_mh zTX^?u0BO?E3Y+Ih*k{$@?Mwou2@bVGE_V{pMyI6W0F}NZg$J`u2 zg!>tDg4(ZehGh_s1BN7zBTi;k(ln2Q+8oiqx|kAb^MGlS;c+~1sM+bY;bcBmt&RB* zP__HCy30l#&G$Xnb%fHki&Jn-3gqy3;6Tq0pepl1Rqh%D4#CxTSzL`CbDEdZ06$nV zzt3uyt~G;50}M&h@WWc^2w<11qo~b03}@59#BtCCp*AcH=~5S;SV)%G8gpwkvA7&$ zB9k7QSggLp5m}XXkgy_-Ey49N*LexPTQ0$OOwO5eZ)yo1f6Ef`d(IMqq{pf3M>LB+ zXV^8s68tNLhySo1{);@kwFJ+w3qMa)#nc2nodL$p$KI zf~GeAY?LgUZ)lRK%|AJ`iJN3<&1%h1DwFJTK!9umnWka*`bV7kMF#Sxv;aS#TY><) zTc{re=Ni%n;Iclxtpg$-O}c_dIpnG=qq+@^E=*g1trbXIR^>jza{1=25A`wh(1q=o zvbu4*-D@uNs!QRbppPT@W>GN1i-Iv%xP_ki7HNeYx;Bm-*`B0VY;WpTpV@MY_U30a zy9gR(Z*EQ{r5pU4G{FgI^P3_4mf=9U0a@w@lxDmEiheUtZyXL#k);d~)|ldmrDR_P zmooCG`dI3j5)8`L3D9mM{$Q}7do#Pun2#M0xdfxc{9o7Qf!&Chqoq;tevG=X7($%s8F^Jj_;crTgof`xdn`(FJSFD z6?N?dU5K8ZtFQD{AWcj~ToVHB%5;ngLw(1AOy8JHP2OkBxvv)@9UAbDY0~{OlMa%4 zER2PPr0a)_``dA0`S8z9#Z3h}}Qr`ggG8QLlr5wHERrEX%R z-mElwRcxrXhafe4MePB>#t>AXc%Zks)`i{CW~&?EdB#qd!Z=r?4tq4rIXfrous<|h zY=i_(S#kr%Eh95#!u#o>wCHO%xt_67r(!V4SsVyQ$^xlV@PozlJ`2}$ksDwZ$02DJ z|F|{>1hDewBB@jKh73Ty=1`v#8X1>ap4vER&bROPI}mA*NdfZUFKu}x->L(dh**$a z6-b#KRzdb_;}8k1)-A4z89|f+$SMx-GOLGlxj@FEo&SVpERC%gy9LdSIxC`R;|5|{ z?RO1t+G`f-*A55xh|&{UB$a3sWbR_@y;Q)A%JJ`XhIIf1#PLZ16ZsTTKpT~O1*ATg zG%_vA(?6Zh@nsG<9_$cvYqiXY9Suy_{3WlNocdt| zg#NY=!7*a~>zd$yWr$}7gtC15hYl+*DDXx*6-YuAH_W0FqypLMm>kuO4ihEP4$75C z%#KsHQ2I}G9JwI2zphy-FS)jeXFLf+`jjTpe;OiXOENmA)aL7^O@?#&Efh9iYWpgd zk2hTh5T}8oIY7wr@ukY#+}xfL1kO6aLKSpht&P;IIy1m2{26%)|Bh@R#PoHuML}Ur zwk3l~oK1Vp+y-AzCV(%l<7aY#jlP{*w$&=N)oM9bg z`hp>8`btJs)@rm-VZ)TR@}fSsX=GfcFKWZWojy+7e3ELg&EeL{e2UEA)LM;XxMJp0 z^mPM7ZYHNEXP|uIGH+tgu z@g1XJ7S$O5lCS5ceGYaI8=x7aCaf_nXDLK6LZkm%T4Nf9tC1e0;Z62dvCJcEPhd?(xWBwSrT!>;P?UVNRd04X>QMFEuKt(c&{iC( zevTU)!fc+mC?(A1Wg)aA2=tSg{2r@qzFGW?rZSDH%;FV-99fWAi+<`O&49+MJ)VAO{)lL4&|3+)&-nWvywM3BjmQZz=G*D!r(M*MN-R(V#;|y<@6K02TIoP~TF$ z)N5*QquyQf;M}dMx;1iN(0cgrz4uN%6m$<9yjLp}2EkR?{%T8=|IQh#<0~mC`XX%_S!?t1NG~5k|sf3}#Ctyky^ zeoh-bVwW;{n@R4nfVM0ib&z?DH-D6HjW>uXAqr*>elT9wUgx?30khX%g>M{?j9wy9 zB1X?fB;V*!pTBDiST=Le=usONqqqKC74)EU_a(@h*Co(83sAJchc%GD5Z)miE*tTb zg&p;nx9BV;-0coM6Z@RLW$xZ(jhamul-l3dQcLiLD;QY^i{8)#oX;TYb4Eks;?`3e zW>ES#akrl4Gje4iM zpxjZ+$ZH2MK||#r-^1rB>*XYPu=j%B3OO)~k3%*euKGLOz^|%$L*_dYd=E2fU~dXC z_yX8jg4SM{x+u{{`n(DpXNL*7)vhnso8U2+mTPK93Vfr!6Yrs|nTOfr-zYX+CElb= zsqa~VUR#J)s6cX zZ7t62?!QzTv>hKWjXVria!f9+#_?|5E>vgpJDmln<5q30EI^I`T(pRQ;&Mp6hpm`) z{I#yDG_uk<10e~h7}siJt^gF0gLDeDLgIR$kfV)bkQ>9wcU$_-%vhM+2tH5tN34>6 z=PaV=Hlk7e6Kz!gig~+j{R&}Jh4#@m3C2|36s+T@@)1LL@%64=aVCV371E4A><1@fXaQcUt{rQyC|^KhqN(L86x5F+HWX z2~*sbC>;q(`!U1#!QsFdnM7jnS(8ZYePj~ZBkGF*8wG!U$r;u`CJ`8tCXqyTL?;m& zmwfG`PT!=laS4Y|8z=4iRpXJC_-wZE6vd)A`W8G}@TgwatG9!Z)4|$V@Doicba(*= zoGtSf;W9Gx8kg#Ah!~huX-ruK-?0tR`>?A2%m6p$&cKbiq`PctZy=v2f)z=4%3Bun zuQ&@2O`2cQ%J^r7QQ+jpl#$*hD5DH8NLmxjsqY!;e;E$cSE46M+!Y!X1Kyf86W-rF zkZkldcGUff_@glZr74-8kvAQ~52ov_H@JHE1DFyVpG--jFhxy?jZ3~Mp-w+9N7^MR zwqJ8RP%A)U_a^$yTs`m1RkZcEU-LKQ#TydZ`!#lGa;#PwfA#rSo*%1iTz}$VyS2Is zYbTjl1hu~=XG&0(($hzr;bz#Sa6ctXtJrt!Fy=DM%+2?`ivn%O$M-5q;1=fYe&G;m z`T>h}wk=C~FKt=uJ!|j=#Ff|<{$QT{tTk??opRU2=s74HpQiV}(<~=|mBqRQsL3$V zD|c0-PJbX(jCA<4Bf!s0cJOU1XlMs5vd?S*?e1 zZ|HwoJQb_+8xm0@;YfMQocR;0=X7bIrNLJhpJuPG(CBy4=*}Gp3Dg|AqN4q1jEb{peDMx9?#HRAru!kQZ&n(!brAKPdfp z2;m>K^n1Fci;F;QoM=!z9>yW?+D=SMh7v(whwun&I0we2K6PZ)R|}F!$g))@6*$mQ z9>H}8Mlb4+&!9KND8R67{lE}L6Y{>-qNlJ^BMcMqO+I3t?6>;JmNASR{*&ejjUKwp z^5_A*5$5OmM7l5-c9VSdATV|n5DjX>qLDsM+!0{2O z^;=A99#Q$LqLx`$oV=}_%t*;i@)8UAt2re%UtLIU&{zFuEjLdXhS|PqhL3UT8nCy= z1I!RoZbYk5g-V+>|4bdifp|X|-!O*COH(7b7j2!(I~J6dOYmX|%vud%3UHB`2UoVV zgK^WP2r>)-7^@Lobf7Jp-a418xABtuS$SPM9qYPyft>=v5hlhjW zC7xWk5cbB{va@t42pEB-{$@~q$r+RZqLMf~G7CMVL}o=iBpVSnb!i?F_4!tfjEi?b zZNAI2$?%Z=mq^Ho>;>qp#3PL(Q2(M~zk))iuzLr~97uhEYr~eCu*L~11te}Plt=Jr zv&xmhsw1i}2l`*#dbbfwKp76akW7_ehm#Q9%7xnXxRJASA_$QLrM_pW`iiqukq-Zx z*5N;6b|me5Sp5o1bA1vI2;}6K4DY{K{pQ=8M0jt7-KjK|3u8h!8ciMAj?)!4x-NV& z=^oiyjX}F@y;Mw2vrxBpe+(m{Ys2UcjQJ?xv>d_6RsbUc0r3{!9)0btuccjK0+(++&D;R(fr?5w@~61-1Pll^f1z zSNv5U-a;**03teg(MkU?L1-&>KkgX}7$JHuvbb-@LXzIg`8D>Q=T|%$Edqo1gKf*B z*0|}mWgw~Jz~FyqQ%V4b>oOUlr#EDP@`aB2yk8^ZB6QToN$5VX?+n}r>@9+TRdKeg zs_Ig{RXx9{s!U;QkP{Aqb3vsC^+41XAm$vXTAS#TgZ~W&4I1dH;{iW)@(!*&?>kxz zZG~jsm;$k2{VOfji|Hy-O<$*RMV_$$z2532U4XPvKXTEzZM?=2yP0dH^QlzPU!@M1R>^ERvQJO zWWzG5(^VH2l)(3?lreZ%uP9F7Zukv}Jqq5u(Bh47FSgp_5`W__nAi7P{iXAo9E}lT z7J;IewE=N-gHxY^wZJlc%T?opuw~5o4=qt{B$2`Ro8-m!OKH(A5=v{`P>44%$s1>HsJ4~Yt%e$mcT6kk8A3iXy zuAh84toAr`fkouB#qD+Ljgqd?7RGL2r3qGgsiI2Ebz4<`4c3rT=1H$xfdmzJ#GAL< z9mW&<{e;CQVWqE2fQs0i_>S$<|FC+^CMs;#9=V#>M*t~XeYwgYK_a+;e6>X?0yp-Y zLH*xD0`=l4HxRcHh{QXBG5&&q{JUWRDUbURrQIhH!=#UEcw8J6(}>lDX93$Kicca& z+t}uEb2W+BSG;UOS9;l6gR$+7O(Rx!;u5d$;;s0?$X;ui^^EgkYrZ7zE0~>}HXg28 zY{lQQC_LxpsH>f=S~zQ6ORBY9HwD$Yg0d@XmtlBkthSXNtmo{g?iQR)Pce@ptZ0S5Fb{NSOR6gb zKtknTWYI+!(k)T2N#X6s%;OVQU)elH^SO;^OkgPU3Db=ufwB;BT#E(HKo2nE%e7cC z&XE`sQN!KDnNIIF!kSHe^axC&Lk^ANCeAcx1&P|E`B>57c#!FcQ8Q9=<0o64iHlxB z0~a?pF#|_7q=12g+gT>Pu(T%_I1`%G2F`xV!vD0h9HB#o2JU7O{&yMjXBs#tUj?&+ z4r^}=fARP~T6p|hY5WiJ_?Cgo$QfGy5Zy=tYXPWO;p53*xY%3YiJ^+rhj&(=sdsv? zQU7xF1#WqnZHC0+MCKmCcCgwmmpn9sb94PimY}VOEbZwVYGG@B*`l>Dnq1&PGm0ND zuYSX7pRKBBC~qfT(a_3J-j-D9hv?@9?*^nY303%m;ryc^!MOpsm<5lt)xa+U4>De~ z`&(yt2C&sQB(2Vp$sV!Q#1MB|Z94s!M#se+HI073G|KQkUJKU2ll8*Rz?p$oy8?^L z1>CAySoOQL4({v0@jt9`3+Z*?ClF&>3`W#;mMSmijY0k%9uUNQTuA0?dnb=S*wG0$ z*m8l&L!p~%bEnLWZglxzF-K}KFRc4MVSKuZTl&FVG8ep2;Ie=B$ zDXrSRfuRvH@TZmxMD5&8Y3JYv%g$d|?Jkh)u$_B0$qqprmmPZJE<2{vKQ16UrV-0d z`b-;-PnjhX$2Yh+hT!KN%10kDQ4)&MnD|syu*RW&^v$tu*q$HQrF^D4*(+;`a4L=x~lg`i#;#|X!G%+P`gmp4)A!r&s*RU~LSunV5 z8r|v8C~iDVbJjHmR2dJaY9_3+h0I6JX4b2n*+!=0d87$X7;4z2BP-VXrF$_ubP8O= zupHzHgpV+j5Td@V_LPqJ&>~sQ%pBuYXBkHQ)z!w@Xn3PB6hmlEjxOS67j`rXb)R67 z-GVzOm+>+hn8z`xs{=*qPeU1cSeZXpMWsrRdNMPOK`U%oeqszmRo>lqd(+`u%2oJZ`DAMCqHR?KP zMSOT_$PaJEWl1LL#8^KofR*t6mUQ;H5$2j0lgXkcykYb8GeaU(tQcSnN1n8XJ;th`QLgaC%m8#6` z=)Xu6v=ypyWT>zS={RIbhaGQ9dM~9i_FhUQ;J{LeKUgYHTH~fOa{#HtAxSD{NwEpy zc+7y_kOt;UrRj9PM#sg7n?@{^=_AG6elrKKpUlmb+iw?z*|-!tICaE$+cBr#>P%cq zOF1oehDj`^h0;b`a$3gl`qw#gLTYw$2JWt%#@k{~!ZnO1Pw_b{ZSE)18i2+|3H8=zJFqW-R;Vy@ki$P2<0t$9E5={33(~z4D5G4sLU4^{NXM ztgr_QllHPIlaFD`vf7BPn0kGBw_WedU=`i47zK2qO7g0XJk^mm21_cK6yXZZa?si< zhZt8O&e{IGgt=MiCD?oOAF=2tJp>C|GCo(^&)E+BoYh;p9YU$VrOaO93IU=F$yE`; z3PVR!gUK1lf0i5uLLH^AlfjoyIP>|Pdh;4~V1Yu=AW|aPTNGM$jvX=#7WOAAn zE)$5HX!rNd;0!W3!H_gLCCgOAWwPan&2-ud!*u##jgHIYWEy?Qp;3HtGR@g!F`#O4 zik<59RnDNSS9Zi0J~F(+3TS(`M^_iw+KvJ3yGYw_*G)m&EgPH_m1@(Ok!rBy!}caz zMF{(ss=gqVRaDi>yeeGnse(me^?s@sqz{Uy1B3KQiL$gI+62i>)q3YN79qjF42q^; zUNj_9u0g@E&{km#8;{#V2)kAXE8Pq$aWn(WoW^hv$<75GgX#O`LJYJmv7CWN*2gg%#8Xph63J8 z2QcwE?)-CxL-Hq&gYS7K_j;q}MqgRxL;l+x z1`wp0)CJ$80oNzZ z7KBfNB{;OMZe4&%k1)|v*u&gX0lRU%l@+)iGU%9_9k;FDlm>uMmmjvIMM&h;R-~51 zF!r2z{}HRVe8st!6o&v&it~`(pNByEP$(lDff*-S@&%Ru;p1*Fq7Vo6CKDK4ER zmcjuzZmuGVqO3%C2SQ?%3KPhS#S}$%TYA-{$=) z@YEb`hQPIwsq=1l$a`jh^Kmn9K8|8?V3E?m78YsCGooI;ut;}gBS!`*?=u#iZPr-% z_Ua*G8-c0p)l6ZsW+5D1ugep7Gx7x9m^1JLt=IVkUNY{{^*WKo-M*S$uh96oxT~ho zW`{;``)ZoA@(F{8M-beq02w7FL*lk)Lzf_GCp6(w#8b|^Mc)K%+A$K$lZGO8*dxQ9 zyh&eXhwimJpN^#(7x0>y1-w*dpya7Nb}rwjW&!j(q!ZoY+JtDEo13oQhf4Mht|!84idi z+I_1tbb}ZOycrH;5Ux8pl8jtrIZJ4}+XvHW-3WFznbA`>jg}l5#qEP>&dLp3^fYahPOi+o^^$kxhO$hhXB3XbTHHzrvQ&4)Q*$s1L2Jk9o<*EA<7XUt?MZaN@J9lvk00x@4k@A+MW0%!)wsc_l{4wGV0Tr4FdDMvBkeRUaqhs$m+v0kGjv+N+ll+pA zIWi<DvxMa>X8XSdY;IQG0%qra|E$GyA;CA07M3K2B+)5v zS;9YV^_Aayafk)@C)qAoTr z`RZb5{!<0i#WZqKm)|}P7xu!L?t`>HyDz**?9e%gCU*{dXDR$D z=HiM?U0)>os@p#U>;gY;LZSgI{EkAjdh*cGsc@@!aye+Nu5};{;q+t`t{)EC+h?bp z>cqqvPU+*8&|XX+mxY)Kq4-BjD1^Vcc<(Wm+8)y`gA$}&*t~8<%h5{^E$U=c9#Amrk4B_SWF(d0aBMTPd zo?5rN+SxlbwOsGkdW)q>Yh@}AI3bm0p`J{yh?OATlf}!o5~kCy7O)bg5nGA$k>U$= z<6Pck#^mO>O}WFRl8;#~(sI=;h<-qq<)+FRs#v(2-|BT&dtFSCg^c$wF%2K%`W7uFl;D6wE|rtm z(dX04;kP2Ms~Mbw6T7gLhuHz@zEa5BgN_&Umm}~_UCA7(A%4bS@}d(Q_@G;BRZAG3 zo1O3f7%#LnCYYCo>GvmU7N&o|JgpVtDO#t1cv@wiZd>2kA2)=_qV7mV?L~6J`)gvn z%<7LRcUj0sGII2jsq&g3QRNO!qDzt~H)uy#@(5!2h@n0|B&Z`*IGF6wDje6wb-)ds z#4{pVViVsnfmgvtZ^qa|5a`5kLIFQ2l~4R0DX$I6eiYlQl3h-!a$1vM4-_ zq(wtar@ltVB^qKHeY0tl5e<2GKO6;yjKr|Q>SPBKZq3dI?0BpMaML1Qu>}@ddAH_t z8(zX>mS*a+1w7}5mAw^LFs^vlAiWDQ_+yKm!k^ui3C+ z=m{+Q+Trc#Yj9z82OJ?h4>YsGY0Z~d@fg~UV;S$+={M|BEr?3(QBw!9 zh(T;(Tlcg(?!0wBBm3MnIc=)8s;&F@Th@)Aah4<$1)RcH$vpq0VZZ=e_n$00ew)Vs zRUY3x0J2`Ox9eyV-}jE)_YfQqoO%S#6t>z2z$^6pjt4%#LpjKFk!&{$Rd)MkFW7K zO{3p4jnci^_4n99(g`XpSg*C(Rb1IYU=3^4cf6pqT=L5G&cYc8lvTrv%PVk*vK#){ z4ywIMz*`+c4h(CKA@tZr0PC7|>#hG^!3LnJ){_G-7<93}|kFBsSZLjv}aNCBr9@gjc9 z%r1fq{1*7Z(42IJW&pPmha|rxSr#IGi;YXZO)#BauhDVwTTCOi3F#xn{T5?Vc-G_Q z%5SlcTW$2?1)R*>NpttG_Ay@X%vf?G&XShC#t^ZZj{D9H;i6NnJvAhqQ5HxduwYpAt zf4LD9H{=XQXb+G$#;E<)kWd?gXqA)1WXWv^rm_S+;Rp>Rm5KUL6QaO5i ziAGM}GL=e&sDuZ`UrAJYo1P(4dcw~z_nt8`Tz zv$KH@s~6m_-`#%*9omY;$b3Hl2ua>=Q7n?J2SX7f&|=B3=mS=}ba@=eVsTjX31SpM ztmfi~#iBPfiRD`?)9DKg_tOzU+lgyh)95bKD8pi%SVY&#gL4Wf@0$DlpQf7KEl*Qz zwL2G_ZCD(#I4h1qL7$>s*J_tekbyYMN1kyU$Xg0Xj}F*=+j-?ve!K0j9X?u8 zTvtVC=LX=d85Aa%GrwUp?i>;tk$gZxkZc5GUTwgHEjR3LHrUzHLAYgn!I<4WB+R0L z;uvZ&G%z2yS+PF%b3WG21(|KNxRRC(g=TwhhXtlrbe6_CQtO6tV?jp%;Y7 z+2KjEaLVXRE%lmk+zc*V2)#D?%X>B(khlbG_=6$(&LKgx0r#feD0@|e#RQo3lp%b2NDxNMU5s4Y)~5@L z8pCLJm#>zFuT71fi&~mStd{8`#r+Kv@Z;?cZm#xkM2&}xa(QOkq|gpdPPvxfF2rU` z0{M1Qjo&gPv;#;P(Sh&BawuSJ;H>JoZg~p-s@Bnlz%EX!xdbIB;q>-mZ#gtK@LFwh z(@wZL&TYpV%`q;tYj~CW&^Ep|Ah1HazGx9k*sV<(CDJSNo2B)yt=9Qg=nX__8aP~J zOu2z{xuGoqC7v)?|1l)6u1{j18>BhA?pvP|bwK+i+*Kx{0_DgJv|BTzjmVn$4HJ5F zNN7aeED{Yf14Z4e)cyE*XJ`g;vv@x~MVQAk_`qf|Z3o75`lrSiWlIOfGfksEc4!p0 z=cYLuKn7IVbGtlW(rtgnjK-|F)tR`RDJ%dK&*_V05mKU_OBUgsczGZEmkR*xn4H;- zxBWeM?8NLWS5ej5n9oc59=4BEi{!ih8qV^DemPDwZzAhg*G<9t^(tIb=>6ARXFg>Xh zfjx5r%t5j&mpuo~S?m&X5T~T1!A3IR@Ffe#^Q{r{=dGt`-XdVtycKoz>6MwQqT)J7 zprW|Sx?D$`p&3YAxh_{SG7)jLamg1~)9JKE$3qPp`!)evHL45S$@6kTY-o(~GOu8RQyt}0ZxsGjkg71#@kRPy53Z5MN8 zU;}PSjf*>R*f|s{pt>5Rh1F%axem_*aJbbL^_InIA?i1$;ze?k@dbuMm?`^3Zh4v12&cnExV|68rl)+~`&h;PjRoVc6$4Rhw>g_-^iQp#U2oPpKM z{llV{5M&y_sIi>2fHH(CoI{2mjMHbGaT;LO!Xe4YN+wBU*0OQQ*8tP$e>Zf_wwM^8 zGL4)x;9aV=xhegD)jbZhns6no3ajshD^%18#^|-hRQKGk;LWiRlQ>Ox$wJLZxK*+m zx@7(5b6L|% zlzE^G;ewu;Oj6r2_6=EBaFSXw5h5~AOy zk#Jy=ib8tzCA9CWut^P<5w+kI-dToGIUf|o_tb$(Ojd<$Z^e}{A$_vGH4j3}OL@yO zIq%F(G(jkn?fv(S8*Moz4Jn{v9tf}16{xvNwS zVE?aFZ+2F}gh8eP6u1pJm=3OK*1X}1_CzH($lTDhq1i1OlaJGg7=XGW| z#Qe(wQrc1A6hR1wP2mTF_iAVG2JjtlNb(($xe&3V#2#rje8KeJrAU za4}m6GRYPfTjyZQp`s!)uzFQzi0VsgurFV4sIwkER$E6s#8V)FhYg^bs&Y8s68eeo zyt+y;@*#Ps1L?$Y5p&I74dCddsj8q9wST92ZknCyxT1c)B>_TFZy`mEqf7FX^$APa z2dy#kmG#}EtOTA?*8c~$gf0}3g;vm@B!O0PweZA&wxZofo$(w@Q{FQ8w+;#XO`5$~KuZ?^7)dZfcmaMe zNR!SW4Pex8NOBR984@vS#40k-Y%9|Ca7?HFVe~OuG|)dcjsDG{QQWAR=4=BPP-WEY z3$T*wXc=1)Gi#!|s~W4F+1Z5Kf78=eR0~d9i6zHSUWrR`%yYtI7jgg9{N%JsjyZAs z_#6+SH$$JB_BrInV1wk;n7~;S$qauVDfgmo3d-GoYRs9!%iDt*Taw$E`JM3{s( zSac9Z`{KLEj=*1RMBZw($kshvuDzcqM}sM|98DgeS7Zhx9QPPF?h$aj?*hXi_s}_j zeaT&S6EyfIljWy}1Wv5*X9i_1xrc#)KN*-$4hfh$a^#Ljw4r2kmS)C{RD7ET)@7w< z8okam%Gip35vT*6MB{)e1X}db5UoSFX9+8jHq^YUL%H1WFnZ_kNIckAPIV_Z&x@d1Pu%`kBvPGxC=W ztFpnxY1%Y$;_ufqe>vGAEP%|pgSa22c*+~ry{4{`%U_kD;_=bwEjXI%K?kBNZW{uj zm;@cVUj*7=1>^L79WQY={jT;Jjj1`jzCA-0uYGQ+6VB;jF#-UYj4WmnQ%L!bkkG zKVszeJ0l0K{?7bsbc{X-@iuOLGGn6?e1C|~mT3)RYahVoPBPX-@h&G#C`L)#UH5XtX0+P~TGW5^DHSMrx)SQH1M6(Jfy1laI z{{klHgvmaz?=S|%U&q0~_Bs%j$g)ajEv5*SzBUd8DRR;)X7sD9KJ)F*50m{NaFqSI zDGg^KRMa5BB;A@p8A2rU8^-7@L&9hiF@(Fe5y+QAL#%EAIW&!&LTwRvK{2 za6DNOBWBW%Yqb38!b)Rd1@g`s+KKDJMkwrW!k75gJK|Src!>AGz;8D(xlDblZa0|S z)qiOZXq!0$f5hUVko8fXThlNlk#YHy+52W-HUk$x8gaZ6)BM3EX#!+X!HP;CJe<--ef)lyzx7b5s`Y%7n=a z7IrY1CG-G!6sn|jdnDX>hwqLwj-YwLSrJVOEG5I_SInDEuv6u6yg3DE-uFg4w9T|F zo1d5J-FwEiBx1)7e*T9nq+6}=^6koxkX<2Am0h_SRa5Xr=mC9~U}55go^{AE{(?as z9TLc!Nm|@sy&;k6WC&Bw7)|zlSVvJty zjM0#0pk&*SLJ)y){xoEI-l%bMnTAXwr)da}^Yu0Yne=&?{r}BR-Q% zj|OT84gYCpXa*jk9);+|`8Vy8J7-pEM7q1oLs5!y~D{C$g!LWH;4Fq6#2U$BsV-s&%3NPnD! zlt58JdR2rzLhk4*Bdk~%eABKcPRMTRRM>S0*W$%_r*&8OJj%GSZ z2huc7%1-7;MAK|s@-@wL`nv@*%`|e-G*$6n5mp@)RSKrQ+-rxGuCbz_*IDbp#DLB( zlrqOy1YE!#EctL?4(=$eoSuY>8N8FnA5<|5xClYrxzL09lyGjL2AMteO4t{!Dt7jt z+5>IXU5Yci`@bCr+KQD)fcE8rV=XlBIhH&|eVm;l;{}iv?Mha=3nRxcB(1VPLY9Rf z4yV7!#eVe4m=md#Kxi@?csfX4C$ldDnWrwg2yP37|2%fS_H6ifC;S_Se<#=XI>fk> zY&edcja5WDZKU$G(~xSr#>>TNGmV_Ib6(AZc=7=&Z$->IPk)tKuW4>HgHWO(KW0iv`(-~tvP1)C&r^+m$7`ufDjaUtthPGcNhrLEzLF0~&}*H#KJO1!_`hIert_By z(HV>2{w&e?3x>|w%7LzxiI+DJh*bIHhI}fL8ltVv~(}u3AeuChN)Mp z!!7RZN^Pw)@^B3<##(Lra5M=sMv>8Yqi+XAV9mpG1Y;1ao}4btm!`*cZhQxf{Am!X zDwh9%N;S&?mJ{d(ZJj-(jz`gxu#U2UK~+jEmHRo8S^`8#ZM?QJy(V!KaBe1o6M+1HA$!4)AiLoU zPrfrQT3H0OHWgxsY+HZ+0D_q{GP}9g#Kf0qmGFj%_L3nHEtbg^BLahZh0rJhGV+YU zJ3S=uvZPH!+lz|aD~AMLq|{lAa;f4aA-6V0Vx2_R+0){pKCnPS!rtMG(ICrf7?PIP z$<`s7KbMKj>@FF}gC8tCKm3hA2FK4vCK4;KabeFoEm_=9XjG%)5-Tu`TqfQ1Upg4T zvdxsUNQ`T%y9UgAu8ss{CV)BG!GImI-~(>218vpkgqc!GY<&p#CHt#mxl!Q3sk{@{#l-ds5Dix zyG#}=?%~R8*MD|KWdKu!Ly~qUGccmv#9H!U^0nJ^`YDZ$i*}nvPTIYAQkAyz#&E3~ zUZ>a%s&MKS*Rw&ZWb&Kg)NQNUgV;T+SZ7MJrD<@V8<4sZcw@8Evon)3vy(G(<7frK zmXoHXl0J+Z-k36$;P)-1=(fX@o*6U)5u8xnkh`l6o6{mU+S8rGw>WlV0LnPZgOU)Hx|rSmv--*-#xG}9I%)- zs4%?9>MvgyK1RYopeSKDB!poAO0Zy1@9u(O0DEBp!7z=S1moRWFh~$!r=abZR3V-= zoX4-jT^(@#OPvz)!${S1X}YviO2wo5&IX+p+(UE%%lAMl?{L_P69N73i^(9Eq^>7* z*QIvgS0QeUx6qa9t*M|n1;>~mGBd>~^_w)1!h|#|E(@u-U7L_(RLGv>e8p_*S|jDl z)5l4k2uLMQx1mi@ECR+(NP$Y@#bQo@B9KDA93a$ zf`Xy%UnXh%upwiS(D!Q+YGLFQ>o5z5@{sFtT$ccg(41ehXd`SwywV0G)5dCZu%>+4 z>MvjOe}!mGplAnQ-?*tlhi(9KcuNDy4;aAD4++3aflparu>}fiYM7MDXn~D?a0X`p zcU%_ONG5m09VbS(Pr9blPiS;pyfM@0wT#x3R$Gm=WmOJm zCGeYSUjz1xV4)0~v+}AB{tjZ^;Mc=-Bi6^_;t>9L1=9cRZq?d62?9C;R}Ie8RXR>| z1mpEzpM;W-sq3dwUH)g8wXB5Ef{K4oAaL^opcPSeo$! zY?9eSC>3bIc$J2PSLBY47+O}`G4`G#y3a{KJ3-J0XV=de;e$g$I2NYPKx!rdsceNH z{Q79gs6H|bRM~Bj?h5%RxL0cg{Te-Az=~Us(qrjx(XZrcv=hZ4qa&Yi$MccTd-qIDfLig zaV2P~OA^)bssR!qcgY%On`vxeq@S_~Ak5lT5eP}lt*0!)Pg_0Zo88|aQW6l#?B0|{ ziY%z5yE3~=W=FyghVjGBFb?3Z;P@0hOhz%{t`PDxv9NNaX|d__twsd1iH#W-rqOqq zMj7tPoA;{>Us=9srG5_26dR90Zs-d`h-dcPdLIRyB9VNsjN{DxGXkZym zCH59eP!DSAs8xg{DKB$&*A9`1dvhveg3q6^_$;KFo$3rP`wy)4+2qCj?*BouOhYSK zj?FyumY6L7+Y+TD>6`tSh54_B1mq2gJj@BGk^nW+YX~`$xMi7 zo6UfHZ8M#ITBGAKXPQQ=ZRsP$=S-ulJjrl#HD~Uy=FFtqC(Tq9n=wUaS9aR%xrEYt z=|%Cd0T;!KRoDI+v-87g%50$Wno&?X!;O zBd7tNc9Lf!ZqEcu*n^i^1QW*ZstE98P^_oS`bDd!Y}TWF{w$H6fKc{%gsGGTC)>O9 zqC7xL0z3O7#-i(t1=z=aN){nZRv{_@8x;`j$6~+`9wEn>9)+QeMMypfw=rbusH)r%UIrwOK5Vsz5%TbM zi%&vsw?u&<39uhC&);kHl}#>`+|QBZ5*SKyqrnM!MVu25UTqPFK#VBb z)Xk8hdjgVu(4ogOA3^g>z1?c!LPQB!%c)~7N@mE!v2@di|FYpdP+1OSShQX9w zOdo=)2RwVAeGfl;{P6yh4JbNlB!s4!e8Xfq z{o4YD$ux2?OzR&x+^nNN5OESBUh?Qt0HF!Bm9clF-oY}rqaKt5UB*Zgl%!UzF@xaH zQSTU7B|Q3u6_wg}Wt2J$1}!>qN7`SlZ=auWDt-i?PN{N=@Vzh>E4i>kP4PJNSYf;m z_=R-6z>+R;ym*_nT+mpOoTj~I$-U3&JKY3<q?O*d zORMShE{%fAG-?_-N$U^nhddWASOOXA!qNCH#L93|f=nxr%&rd?^r>oIILjVW!7z0n z56rq=xzk&L@LJm|!-NXSx4oun+L49QQAqD?wRUBD$pjEAug5Fej zN>xpQQ6^XX&gl+h=1igj1g$A(Cj@j)-{1;it6Ksg=DAA&DUvMpH;d8BtXAn_gcb~q z_wSKR(11!NHXzL$p#jPoXz*`_=CwnD=H^t!iNOedl3bykBg|fcR6b&WpK=CRE-s4+ ziqXbo%15-(#wma9Fr6-GR9v*tG;-3$SM7u3*cF%=!gFJ*ZAe`QC$w9sg{Hp+W?!8w z#EAee7Hr`xz+1T zfr7WY3$QF*IP2HD<#E2^`I`y@0_T-7K@sBgGnOa_{hKHPFbQ0-Ml6yav*5_r=>JI? zO(=wGUmzU!O0P&+@&(KE`jZ6&%QRxaN*^g6(KSI24*hX+717;gM|A!8B~d1TNC8Z9 zyxQt)CwI1<97m1CZ7DeF9=Dy*aa#!5!hcQ5emI`}k{R}Y3yA^7ZU2zO;Qttg4G_28 zG+Sga5lvwp&@KwAyem zN8Rij_c~X@J+f-M4#!)!@0lsEuNJnUDDIvaG11$lKW?>%By7eejR~0p^P5?`-D;h$ z>3>Wlrh%2FrxvK9uSn?ycwFo)nWO}E?stsNjv=8FEmal6fmepluzYZv=LUzo?-+;s zoN)kuU{AhR9s!9(%D4o{42`%1HUZd%rNx^~r#ESATwDUv=myg$Bi{TOrL4)Kv%oqG z=i17ZMypp{FiyO9+g|QrU`z$Qgo?MT3!Pqj$*;hX^I)j~D(*Kc0T!Rj;p2tT@wz1v zLW%CkCIHD_-e)X+FSEwVw+Mei7Jrnd=};KmdN5%j6=8SK{%3G6M#>MNNL z?n?&zp2pj zv1O)_lP!DC$%Dt>_TCmOYnJzV;7>+kWTS8gRIlCaj81r?cnWwKz6;c^;G8P-+8I?F zX`_vL^ECVo89lJ|+=XwzU~QkB@BjL3Xe(TgdM1<*0Ml?n)N8_npA0KKA$Tz^h9{2U zBLy@5mQV||`;;X@Vu=l5*?Dp4H2z@q`Ha;r-Hw6i^;?M!horFV=gABb#L5gtWRKpE z3Cx#0)9J4jkUi7LMfOf@fc+xv_p0-z$w#xwd!q>rSY-*^VqG~MZw!Rhv_}WXAk?MK zrg>v$0x0yVBDxdaS&-fKgx71s7UG15H?)jEL=CFhllg=#;&6G6aeL?@fP1X5IwgdS z!66TCNxkqV+H4Q||5%bFX5XBHYI?^Y=PQ=kf3rqPmsyIW{V53@0jY%Ucn(Ssh~7F_~D~9fU3mY@R^VPxxs;NdJIk z;7(_>z-|rc2w(zX@=cRz^!Ei!lWD}JDSf1PaK@|eQ)Irw*z=B{lb*cnR1`AmbVAl z@)DNKA~VMw2lM0raU2+S3Xr>U!VDWB0cx@sOqM^uZAs^hLjlWL=rUCouUOaLDZT4X zYw7xWCFZTBxcEEf7Vc);#NaQinN>W}rs`7Zl(1lWKZtKBG)xMWq)^6Gy`Dw#Y4Bm- zyT_;xel6jzRj(K3OSN-_W*u1$n9jn;l*OhN_}zAgd|atkTIUK_Ge+V-IWh7PZ&z94 zmENpDD5Whw-(ceYqM)=p9i))bA)VrJeJW&B^`pf}pNaTb=u5kK(eX6%_wJZjY`@=a|0Vie*L;Ur913C zN&T)p_-c=Ou+gTSAM{(3Da^p9eOB22y%(^n{H7^m*?LVNEg{x}rDpzb(jhC+cSJj4eRc#0hYfR^0Rn7gVRNlEa z&%A}y+ILyTt__Pq#+JVu;!y7P|C!q#)%J53sVB(001p8Mbew-lXH8&uuX27XbD{*^ zAfN_EwctR^@YHik3|lyM+s%iO8oeBD zGDOnEAYe+Seph1N?bO~~Vg4&4lL0dda|bERU^i`gr?puw>u=>rv$qQkvtcDGPYT^C zg)+v^&l4@|4FHCEl$-z)4kS05h1>Fe;|eMu9RlJvDBmDutUrGH;V~TQi{ymW3PmY5 z%SfEp+GUO`99hA3#F2fJyqAe=VgS9uhbfLNuq1cy9kzppkM+2R7Mq@N7|HdhBz?Ch zKC$oWmVldd#NPUc2j!%fIPIo0#Y)_yXp+p_G4RyCG5<5fhX13xB={4vw>68~93>}< zs{2|y_-lDOIMjVPHOd@ax)t&My1mjdD{Z6}T(w00(&@ufGb!XHv`-+G763p^w1aQ9A-CS$Eg35KU@|8H}8v@qZWg#7wB11tv4z;Tb&xZv%vS6 z1-Nm;0s$1K-&~SB!lO?RS^4o1Y&e8JqBNN%(ag<9kCDCKI9F}ipE?$U^^M# zk-^FBOLz4rm2L>T<1>wvLSB;g>hWl*1uQ}mkJ~mTd@qgCxgrwbQXEhJRH;?kRj6Uq zY9W@lJu_<#jwn5&_N;Lnd55joXU&rM$O?{g7}4V#bj8X|{t#+V_qB55xHk{bxK4xF z4_IiPDfotwcu5>3mT>b=6C`MBGU8a2(mrbs8a?X4dLfk`;A@G-ASgpB&kEX$dIlQv zOcrQSskhVJkJ#z%U*!$dilkoC-6u0lMCx7s=q~kA>CXrkX6t*JM@k_tseihM)R*rI z2h?Z@-73?6sz;E;hT#lgE(H1+8gsAUe5FU=B&vrDkS@6428M`k6`+6a5kMLEu}}O^ z9=qTgg$TC_(W?DX(<@t$Xbec^rAH;Qy0+tDtGkp-JMR>p%?6I7Tnc$f`K@MZBeTQP zrD_F=y-X8MY`K%Q6?lpkX0dPGe5DO|p)8NUTW0p9vrNYi#eBSjUdw#cV;Hnu=9vXqPaAq#GsaRA=g&8) zOwjOT1KKZ1uf-uuL1Z988?>hk+(8B#au9;-w1<*8Bs^e@BExK7vY}eik*G%Si2B7$=7y0y*ch)ncDH49!V<$jbFgcP z;f3fbi=DYw#{QyHs=Jt7$TZ;wjhL+oFzE-+D#AAd6g((I|JWml&fo0^%$k7e3=Tgk zK<|3oxxwkn_*lN9=t6v|j%|KH(BJ2;KUY+5u+>AQJL&2BoEr+KI_cKqZmg~KOK z#&mF@iN$s-P)yL)3Tz@O(_w&9Wq3>LSaL_&t=dda_3m(Pa4nt~cX+~5#t|_N{j8C9 zDl@ZAE!h;Ix!P)0&J2K2&O1DCmj%2dNL+WCAjQ6W3epR`yW0~%O2$=Gkle0x7bL0m zSz&K{rm9lNOOTo;N)YvD z`C<(cWY);7NKZ4Tt4tQg@5Z#YJVr;+kE@qrP0+Z-E^lGn!%+;j9swJ1;k)?nE@491H-zx`NSGAzkubBTP-oH<^H*vVn^+nTk8nq1bQ9yw8O)b4 zDm7Y2#bewdTBfwHP(9aQEzM6%l?sKkht3Y39gNr0kD(0n@#1_18w$hQ(%D_%G(C77 zOxcU`rL#MCjt}&p$sq0eR|kp+YD0VDiB(orG+ zbZ7+uphI>5=%oowTO|CLLqdx&H%9?vCU9RXJABrutGncEVaZ`IjO1(}dpkr$7N|Ct z0$~gwhDAImSYP!9YXw|NO){4z_bM_ha(`JLbmvm3^g&^`Z2XcrC54nr(_4xUi^AkO zhG=m!EV>67t!B(_D*-7**3qR0E-e7EQwkOPZ`2Zjy|j6@DB zihoo#+IBF{41k8A6e&v#UG9cUEY76CzfSFNe0j6|igwKT=bU zYF~g6TbiM%sM&ZFOdK&eTSiIk#!uzy2JJz=EZz-=Y;L~NI2vPQW8CK5jui*CY()M%gtSp`kXF4_b{$Z`zdk>nGDFoC|a5S!A zmcw1f$wH1UN@oan26m;J@ag&bRAu@cozN3J8^=gl_om;p;)X0GJ?o&!8izL8;INX9 zzEpBAIQ3-fNb>Gq$>?Sf%or5id&ZwwUB{sdkmEoXzEtR5*bC@X_|hyI=~7uZC>swn zR!E@o1w?tT!LS9&W04hJaI7 z(}YnRzvU>_6U=%<hFMyIYfS%TT9%R-nJ!BcS&YNpe#&i#CoYF@}V#oedT*WYwg8>NNqn7(M)`==hHw zp<_#oC$$Z?C*9>(_~Z{m@O~G z?MOO-Z}GqthoYvgCFwg-LDx<)gLwT`DSM66YIhCrSk?dxaIyyAuL&C9s?_cfCAcG9 zex+U5)1xk!R5>;a_z}k|ws)*YFh+7a#!$Sqb7yaPRgvtr)m;M!pKJ~L?xO*uke3E{ z5{XbG2&Yh*pgb0o9#=Gbu&jv9in9o5#Jny#=wfQO(rOe-bGgV&_RcjdO*1*LB!#@N zbeqwWvV%Br|MRXw>kJaTm5~Nys!92xrf5zQxZCy2B_oJ zOL51Q%w=>6t;LPw%1Q>6ni5nd;_L|MRm}Fsa*>aG5|3jJdr**=XEo>6FzjwTv>M9I z!G&|<=D<$mp{o^!2ZslT#1&OvpuJ<11WA5Q9@#mBFNoN!4QsRprY}3avLtV#RD^bU zRE@q=7W=wWPj~sdma)Si82Q_?oc<{oTo+5LGEmxtQNZ|u5GfmWnlMVC&r6|vTE%|$rEa%=u1V`hU=pi zV|Kr3_I4f9Y;9Q7(Ck=dkC63M`b4>2J$j`eay$O?6cASlh}r!jdP*TLdQKl{BQhD3 zG10f-DVGJr9ky{KW&;5XI8g|8LTvM6lR~7{(3q&F8l}^SJUeW1*WXfU-P)cg+!UV9NQjSG zbrWqQbYVNLjV$yy4H+@kv}iXxy8H|hD2u#g#s{-^pZZ`0?CPMiIrY zL%J3>Hj10JJUPv-mG&4nOgx)e%P z0Y@<6ga^pr@!&MoJ%jtq>iDo%%D(8Hk1%=PNF;e*7*{gYtxb#dU*Vu7A~L95MTQ=f zD}U7~_ppczHOV3~z|>%fjmSinq4|ryq)4S5A#r*~2of3-rO={Bp}3?-ab>Hhq#TGP zq)uFh7WRxuO0>FB>o7-?DfYmiyS^A(&*Viz|Mg5=*&f{K;?+1|$)gE<;}B~dgKe6`nVe8?NYD=-wPNgnl5=wpWnx_wdYpEk3XO8-ezST-xu zs3(Q~Q3_>PKa<8a8XQq+lu{Ud! zoEp1xvZ2j@s-`w&*j$#1o;#sYal9YzG6k>|nhyvwKJM*Q&L* zxb<4n^HB#8)~s}Mv_2Lc_q8JRPn^2a1)OZXZFDLLbgSIw|Bu zx+xdM&rriRJZY+0q&Yx+sv8wk3;GfCI}Q;nf?knYHPbfZ7fR;uIW1(8c{H2M=@7A9 zc0E&^JLW@iDfF!z6qiC?6dwY`q3F!6rNVfq27`2iIC7#+^FEAt<%xmtytyFf53M|J zv`bo|c-alnIfXTltqtpEI?1zAWJ*1eG0P1bQ|e0NH%sY)HpgYyuzLGO5`mEOI=_L8wiRuwEetKP!Ho z>XhzIjvJU9+^`|XDzc{hpz70@BnHfWrLf)83)s37Tsm}p4uVS|FM{6y@)gEUOi%9F zv*+L-%*tlD2!n+akab*7%^5vx;w3DI|#B!e@VPfMt0ICMf!7{I=eH(lb9hG zoMe{)!V4WX<6lf zwaF+o^h11>>@)3E=*N3gd)F!3|T$5KY9!pP7Nl^dsmh201+Z&zF6 zQf#pA)GVB(l^``>Gu)D2slociEQ3Ecg0G_fRaqupJWv*=5esy}z?>8=`{!n9=&jB4nUP7G#2>39{n3eg{1 zJJIJg(rwB1!@m2`c(&u00{a$3?ud=|-+SDfAI3l;PStd6>4u z7sfH~#$6f zi)4ka2`aZ}c=3}`?avJs2+YlqcZ$g?oLaJxLU!oQ%*+gcVdml7J@xC#I>rb0Ltkho zp3tLCtTsDqG63t&XM&y0Axu7IvlQ~;vv;4unipcCpzO&j%ptTmHm}{FR75(v31&Ny z;2~nFLxu4cG9yeCPglxRMN#Z-+7)=)JkqNiM)koV%d|1jd3D$v)fX6EX^;L|(DX^6BJ0F_5KN5z-X=)P9`y|qVRrgLR7p!PI5lzsb^0{DSm z0N7pUi_W+$Y|lsMOCi~qqOE4l9#)Igf)ZwTwTWTUBE;9B{(NNeM&!Py{ra3uz`Lg}(1mD6Z|KxGDt&w9}{ZtBGZd&nNmN-1OgP zYnhnZv+5-;l65qF7$fM$?8RaPIS|h`MsU;)1Kc|>5;;vi{!#h0m5VD#x!%Fb;J&aZ zl)>_Ip1e4B`$xI`7i#a0l{g0xyDi%!`D=BOaSQ3(V$-!tCnK9D+&*>} zFu~l{L{`$NMd&6ANeX!h*y}R|3^6*Vkpiqy=%>Si%+_CdRd3LTMA1XekVLr|^*W77 z@jHq$m<*k1QuNag6Qq`CJl^3HOQaInY*db;N&Bo^IN;QsPRP7m2q;+8POzwPPmHKV zxRAfFq;=;)sdRhT1s^ppg_H}^TZ-H1GD@g@r^Ss|!p$U^bcmW*iEO3zYE|}G-ozxz zkimS4Df4teqQ5udo~K|>%UHF76AIv4z!-SCT&*wAwh|0Wv|5VYC5|;43|GbW)U-(y zOMCHYO9|{8pP?&pCmhQ5)S?~iJBn527W^y(?AWnzILFBd6AcQYsNM83uzLpn za`Q_*-|bv5|3unoT7Skea&UBeuyl;b8EgbZCY7g}!-)#jI^{H!gA}%Q26ExjQV{n! zbhoVQKE*f>P4+8Q1m~PO(iH*m4q4fEGw*QoMyl6Ijs>lof55^GwHZmfll0x*wGsOs zF>BLp^as5Av=W=bveA=K616F^JCkmszbQ{=R&JvwcV$DcQ<-dZdr?2ur&I#l9`CK4 z`XeoB={%`=JZ)Yf7^#Jn@ELHV(7hgo;scHpSN*JjngPd3T5DWF$!>7b^SOqc)laRQ zMH1xDD;hp23cu{lkv!ZyomIvc1RMUtO=r=LnLLDq2DR(3tHT_RQJyX#kS90~W42s^ z31|+rsnu%(Jnx#S&l`Ph(vlA^d$<`H8W!tM*Ot7U$p4-TXQXDI$vFFG#o5-*6HWgg zdj4ycg8^&k;7Ua`+o~0PW#ZF@xM8c@x|?#$UJiAiy(A9p)Fj)G$!Lh!kZxa8Qqn|P zD*cY&HhbKonT!v$~RlS0pJW&`xF6i66$n z8+W+I9K7sB^>y&>xA&Fr85j|t8EpcOe^do>qc;<=0x7aE+z=LRXF7P-9>%G@GpfSm zSz)*!ju*a!r zSUJsx;gDHDu9t%cL=$f9+>^IoMt6Di%u+gKhgPl~necsE7GAQdR^7givB$blUnm>3 z9niAX2D=~u6Bx~yAjzu&zcbP{W z)mdqpS}L6oq02@wX=*7{^e7b9)KXjpT>&+k+Ap<@C=6CwGT(Qqv$FXaT^-k*FwD1E`TqBw>!*=`|hd(?YIKeHL)lXB5x(S3me*57uoP16v#lt^RL1Z|&)q}+Wn5~FL zYK1y@`PS(0!Qq{S-6rAI=+KaQC8r-5;4L-tRfj&7lae%&Wk}M4^3}JTa_LgNBK4$( z8*D5pbo?8CMJ3h$jc{Fhmq=7dQAwdMOQ8%C;^a@yBB;kivjxdw;ERF> ziac(IDAR0VJKNjaDT@oQO_?M!wL1A{TJ_0#mD0k58D7*v`sr?UBY7d$PPq%c>sOp^ zev0qZfzU&novTc;4PjBAnYR@3!s(5Aj+LEwW&DsV^NmY_21EvPRtu8oaVo&UziKvI z#*xE=c7?2NQ@$#ecILto85Hx3rN;}FU{LgF4=kzUpDz_zy_k5>axD(hsk&Iis!+si zv0j;)4EE7uWNi#gAR4Zo zG-mF@j4TD4+h(!p&Qb#Q8*{Lf6!K!J4zW}u%bq=F2+x`d4<_S$*YV&4NkszRtDg$z zG&j3BOX$#u<)XPN6Dmuue#T)1i{+vRmW2jF^rh0~^G-e8S!#h7Fi zkblCIx3vE@a;{n7Q4vgvU}XMCd+`t6y})R(pN-@6Kpg?bqLMgIk`WM5qHe#tbG%gg z$s8Ong_PsdTZ%hRWJ;s6Z!J#F6U+ijwr$l(3YCyKJo^yDb&};ukSxF9`Xz=4|_etiS~%u-~oW-08y(4KDpVc~-Htvo*QACA5Q1k1V0R zI&GW?T490c_A|xaey6SOg56^5F_=DibEMD{1m)Q+(Og;z^?MYG^Q{zDGCO?hCSFKB zELPYh#<@;)R?^?l>E}A(VopEytob_q_Sq5mdj^I_nd0R1i+@x)S8~yrq~r|Kd0Mca zC8?`1B&qWueA4#s&)xnxZvTw7??`Ee)9;=&=Oarm#_k&OR3gn8oO(QPQ_@|T(T6IW z_5_E=57J#QM%~gVEzIKRgG#H8JeU0lj)ITirsKC2CK~0^z2vY7mS%Q_JL7SvT6t=) z&!ob|el5<+A2tyjj20%ul#wII_)n|b+r#DU?FzC<(mQ;>&tfnM$p-?bB#%cZYgr9f zq~gO;KELP?%2GaCT&ywk#Xl(FU**)7E%s!L{wx!oK}ncm@h7nu)LX-+0EQz5KPp7O z`7lFd2gWE^mnJY3<1g`>0{osH0Sq6tCl6=wgA))Gqr}$Ev1LjC9Fn07kUvrcx4A56 zY$^a`+uV$Stn+g?xRH)0WS!ta>F`BwI;_Omfc9xxHkK+05fjqwiw;S)MaJ<49 z!hZ?~**cRnQH!}LlLuIv6yBA?s6qz5EfNLa1 zn{`|p(?nk=BCg9#i=Sg!>PyO z*U*B{d4<>Leyc+TOTsvQ1r#1kY>KJd{fCO~<4$|om?H^%K2x1R^_gBsp|Kn^l0sfI zdOFc4kQ0^;S~8lT@NgQcaNt=5f`XJ|$V|iejR&8C&w-r)>aw=U1^p#b+MLTl zZ7HPGPS?fp$)pT`IvdgA#tCAD=cQ)xlQ|8~sr;NE-DBV0n2T^Uz55?bxHkwAT_;G! z^r|y9PCmD>`b`U!u||XDNAva57$(dCX5)2yE7u3%HE#{-l6H_S)%wQDOReP1(OQ{d z-Pg)J@6FY5QZO&(j=x(wj@-F6{FZF-kC;0x+1hIL#Ofu(oc38^|5T4)cT>4$z`VhN znE{QwQ|P|Z3+Plv(#%mI$2)}_*;1p0qxG4116=PHOh$tFv3Nc+28B38HZ2=~4xeNYg>-FgVVfS4A5eS_N1emD3y;rq#lqo2wsZj0R+jP77laqf@jL%sb^SDCkEMWe!iV2%)5+`OyTI?!hB`2Q4cb} zllrVz+kp~p)aUK$Sf{FFZ%u}Tr9ADkB6!{*dA3lInXt$Rt_Xs`C*>}EhYQQ}o*Y=A z!(ci6SHQV-*2&#DLja!^z_WWx1F95K&PZ=5ZXL^btj44kH`cMcn>u-On;50J?Bgz* z+g_K8_GBCX0@MCAf&5RVvB&h(&n=W zcp29D_738>*}?!appOg>42@W!|0!RUWM9ffGLnT?FvkRgSBD1|bV z;%UO97!)(*RxzAEAv6NBE?5~Sg85XKtT}kP38$nYsXy6`CKWlI0XBe>(#=s|6Qvf8 z8q=v5k}(D*>|o$p8{K0i>vv=Eu5&PJQRy-^HX=|mu~NP&&2~FAXJe9Rw!}1Jpc3Y0 z{E6)V3*J6O9s_B=Qpj%V5oEC}!WqDAun5V}McyfRCwm0m^()~Q1;_1_>iINRhS2eG zVNZN)aw+5`Mo%R%nyOE>&5^&xdWIJxCJFs?yfCI&ED?bTUO!U{4GpG5uc}k5wQ>=W zY=U25?!PYw)})YPEuB7bn?Q7z4k}vQ*sInCzEp3n3{5;V_R5?4np{YvQTkUIiLVkQ zx)y7eH@9+Usc~;4gsnok^>t~L+`DuXM73OM;B09apc?wNyNcthk>k=VfE4P}k$Q;X zidH>_^Jr*YZJM;k&9^w6wlv&htf)5!Fy`c}pD1^}(`lo-Zhj3TmccW+c~>5EnzrcoRR^~gk8X+p z$Ru;#DwV$F)Rc`ovJ!rcIgx=doERI6`D>D)Kp+PAV)**3R|?#ZdIa1mqKY5-ywk31 zxg}~|FBfswSsa1{2B|#a2mad7W@Nm|vm$kSj{sj60&Zt*a*5tue1)6-MkFyClO(=U z$V+@b8u&r1V9REyQ6#rU6Z>(@+2IgKO3y}tlh|t$hBTP1tbv~maYW_m>B=N!Vb#5w zeY6Y{gO=?w?vLYzg zhF!9l;;=(jOC>y7;w7DqGnb_QK-uPYr~Ygzk)n7lD+&h9D2i)H`(+~AuTvW=l5jsF z?-cZB^$7I!vavJ^L?nZ+F9oi*(i0@$$PADb5=6_c3)BLoYJn}uq5x;22Xl}51QgjvZ-s!(?R>s&pj zN$~5r=UzYeB+O45&fu4h+M= zBlQU^_Dx~^mzHWva6OzZRomrVFzYZ0oGf8$=v0An@wLjeQVm-y2$z(!j|Si!!^8W$ z2HeDr3&Z=YVfR`;&@Dyv?+yj5QF(K;gRG+5*GkPFIdx?dhDP8wFf|zrGXfu2E-JJ7 zr3x6)>cjiEH^GDUVau()R`W_i*U>(Qt|y})qGlO6JVLAXN}F>^rT-!fpG^#s5-Fro zlHO8W&5DqzPSWC?)s?B?A#2}Pkhrr^Ho4t@=sPah_;8SJ|?TnZs~oH6G?fgr&T281w~m)&%-AOL|f`^-l4Xo#<$Ak zDnbrcfN7tVliN<+*_wpZ`foBPF<3^eKj+8E0DibyMQp;D2_6&=FX<5;E{U^Y7Ie;Z zjZw;j0R=TYa!i~BXk>)lBdJ<2!s0>E_y%t@u4IHolRUyEb7N$Lb&;wAP1*=6mCl9T z@tMd-p&2QZVTaDs5*9YQ!iR&C*k`xPvB0`1w^|EUg+;_+u9q5>*6h4FCd8~5+uw$V zNDotuRvq=35xg~APwNfas9CeaFl?BX@`D{uOGua`45VrvE^p{?fw?b#myg?jQ!}L{0`d{y{_Flm}|2ALSn?#!ingl-RF1k|a10h;`L{|!ViSASwkQ+TQOVbxZ zvSh`1q13>xDA-9RevPsuA$Wr6-?Y;jocB4j1yqq^OOn3Ze$UwVh*2s=<*6~J-Si;ZySMQQE|qhqGb|nae-#-75|`IQFrP~=L#MW z-pYh!Pz+(WcSlfGFO-K9-1FAiu1Pqy>V1KCZ(1P7W9DW+e3+Zi zV=*BYWwKito4sV4nCq}rZ{U3_VgsSmSFgS z7jQTJ!CutyKKzT_CX|IBND*G1#CJOCj@)#kD_D*hwU=Xd2Az87`LA}ng+Q7}$1Djw z|44KeWNDd86S~iuCh?of=X$5s?%L)ZOiu>LXq%t%$F^Ue)`m3Ue#o=Jer1nfk65zY zD^Y}7JC8}{imbkq_}sJ*g;2kphMcQ01r_d=7bCzA;n(UUF`RQ;s+y`<6~iIiuv z60Iyrq5t$K6xWkdTs4aV8t6%DGg0dKQKFz?deW`UO4Dh!CdJozV(Uu0c;mmWbRb+; z8X6cLcJdSM9dth`8&$m7h!yj@Sdgc~q7dZeuPfc3yZzti_Rnbh&bm^@z_6X%k?O51 z&CE2gM1w5V$W=(^l-RCIckjwCIH;6$*Y`pvL%8XSMOn*Fo-_8 zkEGBq2qLpvBH5EdFZC!Cmpv)2#B-&^-LaZvqX-W$4|>@sa&{RfwdMRSiuymyg?h46 z-piPt?I*_=Z>`aVV!17i$;4OY+m0QQbp{!TAIRPIb0 z!lYlH6$Z#g28odr`m_|vP+HsW#wtv`jm;mC9Z0P+NQWvRRM|gL%5A(oY7k}vOa9jP zGv(HYMSc9OQb>E4j?1{B5Co}MY4Ko?cDD~FZ*3R(jHwE@zP*}FI~=CnVKX*N^H}IV zOpod?Jv1;PDKCTA5ci`J?O-mVkzV=$6K%f`Z3V;hk=*TnklVjS+joZPEWP+y8mD=y zFzrJfZ&g~=^7!uYsd96&Q8A~Z<7uHD6WZ4*965RHDE2Io!%mXVVVSm6V7@o(PRph4Z13M3LRgyk5-vO_ z?XuJ)eNsmKFQ?A#I{HJbqZu5dqla?$QeohVSjf7QQ(*XKp-eX5WZ_C7FLE9?smrNX z&Gy7(6+xWjoaJ=YcZQ4UL9CIXC4wOl%2}ao%GE;a+(MWOYx`uiPSFnAg{+svYqq5H z>N}#wuubH6`$FV|Pm17cojS8|MFa64Gm#k_L*zjdS(VjWgjI$8MNm~nuey_1Ahy&%T4Z#C*nbK4NuI zLSsYLaZ?u8RGj`=val%v5Q~BHRwdv*r>5=_@Dauw17RfKNT3iF77!KTgc*x?$E)$_&b4q5DiuCVCnftiW_(X`mFwt311ZChk69^ z1(6w1jO{#UME~jyO;2V-$pYleh`RJ8bw;%I&Zv!+F3&6Ii_VCW`x2QExjj*{C2d9| zmA)b*jE{XKg>(c-Zz*nH$pCah+SKBKedV`PS3cJG0*|f&Oo@ki!W$j=Plh8Vhf<)Bs!faEQTDE0XVyT$hoz7V! z##L6}MZ76Cue$t7RnJMMrE~!yG}3_g2}UCW>9bxag>DtxXSYOFkQ5s8C=};mDX#Q( zco>mf(L*qk4-*u|$;HE6qMDwU3-L5V_!J}lX9XQD|7Ll`uT5SEqP(d%P6(!BbVB+_>LfZqzgdL3{2; zCD{*hF$5{LKV>%lo{($>%Z(e3`kH)f7<`V~Ul$gQ8wOd5^_r+VS%Y|RP9D4urK*nq zuAlg^4y=~qxRQl$FkT_cW9Dy^BG);sWXl67mOp2VFn~T|ycF6dXv}VjBu@%mA%!xu z`94B5wxm(CmAI(j_+|eNZLSF1Rrpn~RSKJ~7+uROt%$ri7b0nd`wK?oP13#YIFUk% z6IB4N-ivD^L8-E{77w&hEJm?p4gxOmnUj40U8I7gvRA&*N-ivtg7{0u;LW^={ryTtceUFy$mi%3!Y}W$kZcvmV(;bg&{h6-!tXLL4`;`O*nR zCCV#-V;L)0R4~V(>>nQ8Imj&c<7is>^|`q)P5k;-jOqIY)7|-13Z0Qc88ZB$gmAO* zn~=r=6PxMEjETe0ISz+-^_vtOO^&Yz8L;`0ma5CO)0IZOM!A)PbDEJ6qfkDJq#fku z?hoVQcH#h2svT*jDOQ1;%m4g-!)SVTb6(swa#Fpn7oO~Wp zc%o%;DZD;aF2V-ZE5+u=bFl%by)Q8vd_=J6s=W+3d!j&57{8wq(G-zIrbTiwi760R zX&T2wHB9bjwJ^d+X0=$fdv<`rUpsxV#A1uv7Gov;L2>hUPJP)-Ln88J#tnmFL}XK> zU)C&#f5oh90eo?+_Y85u7X|tIy#QGm)#Y=tO-Uh3KffqEkc}LYC@J)p9);otgcMi4 zQ$PcWassXAW}bZBc@bd}-pwUUl97<3tl1B!c;9g>uX+C!W|cx%6s+R!_bY`iJ6=Sk zctVUJyO2rA%F8s4qkY`4Y=eFpvh?AA!WxpW7m-7^S}rz7_mBiOTjkPJ zXe&?@$>Y76vbcKG!G*=uo1*|ROS`WXuTOUB%H}c>!M|a=G8je#H%Ghf2kj+s1Tn-( zpA_o5dIWW!MGmc|D`|HD4p|1dPn3=#Mr+>c7Mm*!##8fU-CjQnE3{|fvM zugTs1*SY;yY5R_X%JM(lep9ts54LbZ)li~3O}iZ&Z4HaJJdHo3`z+Erf3a4dDi=BP z9JH00xa=FU&feK*S856ITb$lmDrXfn%~T2=lq&CZ%4JIhsh7WFtZy8sCNy@97}%r}=aH8eK7|qn$?^avR6@v3$OU`%B7ww?;l0b=Zm@UMO5$^( z_rO{5_TLUYtn>|tvEFM3T;oCMxc0cO0k`}mc{E4{^ca}n@0kf0UZX}LOY;21U)rS7 zALigJDdfdj!^W!&oei!jR!bA*D)clFiCB23QX| zZ85Cj114AOo<=2_&q9OCXUpFky;htruE(467SAzYMYM_yN{{8>a4F=);bV6qEj&)GLl!z( zGcTM$CeQNjX6bZ!_d*qU<#7l!7_tH;HF2ZuDWoi}vvbz)49QfTs=TDB=HONX>uS&Fr@=l;G%wtC}K+=m!C+Sa}0g zE2~5?^gwP5eVZ}#OF1wkg%m?NS9B-I@u{mApgQx>;=$C_CyZYvP&|S2TB_<2p!4or z7^HdRcNl~36b$BYGz}v|PhtFCn36LX=|$IKs2@L7na5(r9rc+R9CT~42$|z>jgB+h zkEp1npcRr&qAoy&VBLM%7TWE3iY#bM>8-f^kI)earu$r%5kpzxM7+}2W1Q6#^lGXEgpE{ zI$~muANH>JJAU?x<7eo=z=-C3GiM;UAC+WR-Q_#6AkHO${TJrk$Am?}xyw&SGnl*m zf8+L_pzY^y{M5}9Ax!m11Isv8Ip^oYwQ5+1^*Z*q)seEhhJ!)fk*J@3heKp=rVf?e ziB)Yn(`_nTDaD>3vl(b~bT|FG_u!uN3C2^Lo?H56g9RQ-bmX1V?}$@Nw)BwZ`FF-2 z17I}Ivma(GD8$^XzmgD$pDYy5?j|V-DfC1sl;Ng%*~xaW>4|0*L2x6leOKVIF%u5g zD2Z@_Iavs9iio9xLpg)>3R*Cn#ZeSNPP_ur&rFd$Q>vyh42+teB#@MP_vYd^awvU| z`E6DR(VcoyNU5hs3ePrjfU?AZrdUF^-#7dHYx!Tm}O6b$xdoY}ZkeReCtGH#MywT~FrOx!=0BVF4 zn)6m!?01}+vblv++7B2(41`f>p_kb7Mr-Gv_^ThO{SAWtY>-I(NTFZ%C=|C*q_~pY zWngPLDK$7&I48!yZf#ajf4Dg1+6*xpg$)6=QLHN02eBeJ;y|UW6M1>vvzDy5x!Xem z&R#gXZT7+}-&1D|PVZ?FDf5M?33h%C&MZ-@pSr0yu)GG{1mq zHv|n9DKHL?ec@xfQN`1yR(;YO97|u(@M=KVIJeZfWV&8&;b=PApgehR@bUKZJDZv~ z4z|{wFP^2a%_Y2{rRvH87St)yuGK`9R|ap&)v|e0q&>?;v*91Wqs6cQWdJZQHX?Te zcK;TuIJ61qyP(rIi)cN5T-~`CVPe14EQfGa;H9c@(pjnw&>THXCES4LMdZTF6Rk;C-6R21$>s%CI z+Nx!>sb#5imGi}^Vs6Wc^UmvR4(e4Hxb(K@2d8jn3-tlK)|>^3s_4^FXA?5s%(P)A z0^?J7zMx!N>Rd{Zj*Y3}R2g0jjPp3umoU91FenHkl_~Hlj)}lgMQb{nVKdZ=`l@q5 z1?;tHsy)9@6cz+x%?mme0fCcMs_-K7#xOULUtcXW%k8Op@$5XY)E1MjYXVM}dHHwG)^*0gB@I$-x~Yrcxc*0)L%5TvQr?9%P)I#+=$=Zhkt z(gDhF2_{+WY-ygWwMu7;vz3|ID*nL2tB^GV9KW$SUxKXN*M?{}fv8K(bMS}*%qjB4 zp!O>0Q#!vAhp`#C1eOg7QTpEY0-D$i=*-6TP!%kKf$EbK&aJxP64Dm%vpc`5%oG1s z>m^FpOpuXc0^7__l&2uY=K#WNx!gh{mm&8>>E2=)2Vqu=FqcTz8n7>>nn?pU%hl;X zvn_TmM3Cvy(e^}VU7%4Q!r;bAEjaeA7+55xcNYUFuvQBy7InbeA87E4=%}~JI*#iY zpgZg(THm?c{i%s-N3=St;n~%lRU`ZNs4Lq%1jGOAm2*d-0Gbo=;ky%S%pUIM?m)5G ztBfF^Ll-Mxa4{imM008GPW&Pm2mrwa!_q$8O6$)~YdxXH^!D4GOCngH#jX^L&E1X` z6XAUpKD3E6(_Fl>hEx*J{M@C^T6!7W_s@L|7R=m3bh+U|Tn^#V39V&l362WIEyu?k z?S%f4qjNW}LW!H`^0TXPIZKz%uEpikba`zbF0ZD`{tdY7q00|8;_^MZoZF1cX}Wyo zB3wRcE?aQ-F}hSP!DX5*e|tGDU!hCk3S6$D%dgU9i7qeMhRciS^0!yx@)f$QD&TTH zUEaPOm$%Yo`dVBj=~CQ@%QNY+dkB|ZbouTuF5jlhj=i`P=(6=7E|=2f2D%)g%SW%r z<->HTA-HeuUR*kT7zi*VkeguX=-i>3@P3pozfYInqs!!BT*m407h|~m8C{-&!;R*i zOqWSytehLC%O0cynj50azhcwR+&|Ifg;-3T`#HK?P9%C1UA{z@zrv;6Sx=OtbUlVc z3@sN89T(@$fCU!k&YJ5vbG_eOiDrw2UW7v0WpfV5= z4i^pn77gwe4c-_)@Uv(K43djW*} z<#WG`f98IUE?=k1tLZXAjQ=gVGrW8wJ${@nchTh#@%Lxw&hYmw^th2Y{T{kopu3Cd zVtD>}boa_NxV(byt|mG7ReGGGyT{SxLAuoGVr1iUbobDDT)s|sH}~Q44SM_~x;sJ_ zBRRiLcTXT0dK=vt89GRhYe|}p(A^2T+eDY|(B&Sw7zz6?x~px%WiwrBBy}yiGg9{) zdfY?u_j0=XW4b#?7bA&(N_RJtOn#N_K1g>*=whVvGj#X0i*flIx_kB|xO|fyjl@>z zapF>3o=bPXa2YPM^mukFF0Z7=&y!?7j~X+qmlL<^w^=x zUb+~$|24YXawRUmO?PMMZYy1$Lt5c^bZ4}}%jog)t8jTO-F==k#Z~lZG{x8H@z`T= z`5xW9h3=k4m+#Z%9dt2zWG$(cTdu+7(R8`c^^HVx)GNb(%t9i?&);dO?vbTbZ0c`4fOa{x*Vm8(XH>L zyNeIw@=3b8hwd(?i_y2!bobhuaXCYG4~*gR273Gi-Mxk`MjO+i#&f^)R9wDEcOSe3 z7dn`JZj^L2ot+%$YD!W+_to2Qq0>R;?m2=B<-ZT~H|55idpBJuFZWzO>2ylG8|ZY} z$~t$)9k@`YuDL+aiRTdb04G&ZS9!5@)#}@ zl0J8a?kL(d7$a!aV(x9naiL|zxs7+>LJJ~h+?XSO!Q4yeLLRia&(eil5$(<<+t4+} z!luaz?U8`#1_L5^LsJ_5U0~wbZ-U=p#sI^3exhC#+u8i|QO-;G_4-JS>$z1^=#ohN zn4LCSG#$RottqALb%3x0JUxJUV^z=bD&S PSKIJ6Ja?%*G5G%hi2>}b literal 0 HcmV?d00001 diff --git a/.doctrees/configuration.doctree b/.doctrees/configuration.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d22897de3d04d0cda0a5553e06f23818cc3d437f GIT binary patch literal 23343 zcmeHPeT*H~Rkyuge$V#$duwasWSkGYOT2I6)@hSXT$0+3W9+O$;>2zo_wDR^^LA!D zZ{}q_yu1BCsnb?jaj7EZ1wjQx4FyGrKPZK?w2f$?h<|{8Ktdo8RYfHPs8aty{6od> z+&g#X&b;^Ly=Ob2l^VsnJ2U6rd%o^D=bn4-d3o%Od#`Nb|FNAx%e36Jie9g~Ufl@V zY-`=CMNPvE+po80Ki&RRdxn*KeKqhRzh<=ACP36o%c=W@+rHXnlLQ`GPEd*4PXtCS zv^+OyZjPDb=ET+Zj9Fr1p%prY@`>#@>A4MSCGvINhyVdMdeK-T1oEFh+ZGs&w{(mj zw$0tFR80^zN7#6b=OP<*EZ1l+M$0-Y>tX0y%TWmWh@KIv9uV#mHAfEuyu{yQuHF=X zZLLSG^kG@AUGt3w!9;8#)K}Gh%n|btduHDBn#Q~zxvt^QuX_Hqd9P)- zhBwz*4^7XVt2q{s?fw$T2lF+R2Ngd6VRxPzjh4ZQiB;WqEq6ub*`*B6w1(vvfd+X%$-+lOZ1pj6sX!Cya1Lh&~D5Nlf zX7l}k=KwgKYJ_ z9AkxGB{pukT+8K5?bl+eXNM_|p6kt{8S^X~gQWl|MxI~Kg8U0bd}7-}Uv~pX5A|i3 zfDOUqY4e;Ik28CFVF#n(dJ7h4d(1O|2%Cr>+iYAgk&ExF(rcL{!za^tsQW8MYT3ZA z1C@$a&CI_lpHB;7GW1drHU^_$)!S@urtKVW%Q1+c6FYJ`u}unATEt!Q1>4(YP74&K zx_?V0_PO2?%S(yO)+-8Yc7ZLawkXPp;8XD2j`HS_j@F#xZ;eu zUZ}dQ%kOO7v}qCVz#JVW)HDL48@=4nV)i!-a#vcz_nMrYdW0r!Xw|sa)8I0FBb=}4 zHL#kiP`PdeU}<2~HT1s#Wm{OHM%`3(sZzd(c9>bA;qwt2@X5Tb=V}m(5C5Tc9Wvmq zfm}z^3qogIYwE7PLW4$-CXlP?jXA43Em4aHT7$7l!4&}($^)r|1*J#04xqBep&@OV@@&qy_=Wq z)Wp1{nix3$?J$^i%)9Cu=C11b@9Hy|h0(t#9fSGDJSdxD2YO9^1&Oy+B(m|%3>)Q` zu#q5y+nT`7Il`=~Bmbj9KRk|h2wM@HXKXje7H#I$dl-(eGY5*~Ym24dUr6Va(- z)vU0+!9P=M+kTa|i#>AznG`VmVH}mc57zlDSmvqA$6<(nX8&%&{`F8@W1y&*`2Xc1 zB_UzGi3n&)x=|7w1Xd6MjXyyS21_4W0!}gcnBw{Gy|uerobv+#&I8NCnKWrdPddAJb}k6l9qGsABB|B#d^ju8G58+*uWNzTY$b5<%2jJ{?2l@O9;}mB zqG>=Lkb79+xPmC|O!J~pMpnz-8o8}FvYJ`7uw=wnM7I{Lh~aTXm}MEkY!W{G6jPAO z^S=j|r;N((fjV)yX5@L|^qS5kGDBe+53nM{V+dX2Tm*zhD`3HXk`%&|CdodSU5Eqy zDfZ~C^pYB3dlVLFc*>3_l$F>H#NLLlJJn?bK-X0F@y3-iNG;&g)$%>s(}?Us#7H`p zWL*L?PIcXA=#dj@l*pKaPtu-y<~;P+#s4$}LjCI${nd>!BDiG_d^^FTzjFD?Ne>wf zz81Jzj=QN+H`L1sz9cZbO3m@2x}3B>q1XwXGpFr+kWEmq@@J*Brn3;V5QZYp)$$S6 z`_~Ox&)IuOtRg2ctH|oQbkyu{_myNd31RyzDa}u_J2DQHFDB=b=Egc%)YM|L zabbkoy3A-OZxMteXF1P@SwYy@1ue2F8Xv?$z74ja zRx^U25jmO(W4&rQj)nz^m|BU6_zA-*<^GciFNeu(eNd4CxL;!1mLtb8!m0zFDMm+T zD@v?HU#hT8P31H5vG&qhdT5eaG2H8xkE9o^cWD(z*&c0a>B7^e7f)ZPo;-i{^y0