dhidb 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,123 @@
1
+ name: CI and release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ versioning:
15
+ name: Compute semantic version
16
+ runs-on: ubuntu-latest
17
+ outputs:
18
+ version: ${{ steps.semver.outputs.version-string }}
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+ fetch-tags: true
24
+ - name: Compute version from Git history
25
+ id: semver
26
+ uses: bitshifted/git-auto-semver@v2
27
+ with:
28
+ create_tag: false
29
+ main_branch: main
30
+ initial_version: 0.1.0
31
+ - name: Display version
32
+ run: echo "Candidate version is ${{ steps.semver.outputs.version-string }}"
33
+
34
+ test:
35
+ name: Test Python ${{ matrix.python-version }}
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ - uses: actions/setup-python@v5
44
+ with:
45
+ python-version: ${{ matrix.python-version }}
46
+ cache: pip
47
+ - name: Install package and test dependencies
48
+ run: python -m pip install -e ".[test]"
49
+ - name: Lint
50
+ run: ruff check src tests
51
+ - name: Test
52
+ run: pytest --cov=dhidb --cov-report=term-missing
53
+
54
+ build:
55
+ name: Build distributions
56
+ runs-on: ubuntu-latest
57
+ needs: [versioning, test]
58
+ env:
59
+ SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DHIDB: ${{ needs.versioning.outputs.version }}
60
+ steps:
61
+ - uses: actions/checkout@v4
62
+ with:
63
+ fetch-depth: 0
64
+ - uses: actions/setup-python@v5
65
+ with:
66
+ python-version: "3.12"
67
+ - name: Build wheel and source distribution
68
+ run: |
69
+ python -m pip install build
70
+ python -m build
71
+ - name: Check distributions
72
+ run: |
73
+ python -m pip install twine
74
+ twine check dist/*
75
+ - uses: actions/upload-artifact@v4
76
+ with:
77
+ name: python-distributions
78
+ path: dist/
79
+ if-no-files-found: error
80
+
81
+ release:
82
+ name: Tag, release, and publish
83
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
84
+ runs-on: ubuntu-latest
85
+ needs: [versioning, build]
86
+ environment:
87
+ name: pypi
88
+ url: https://pypi.org/project/dhidb/
89
+ permissions:
90
+ contents: write
91
+ id-token: write
92
+ steps:
93
+ - uses: actions/checkout@v4
94
+ with:
95
+ fetch-depth: 0
96
+ fetch-tags: true
97
+ - uses: actions/download-artifact@v4
98
+ with:
99
+ name: python-distributions
100
+ path: dist
101
+ - name: Create semantic version tag
102
+ env:
103
+ VERSION: ${{ needs.versioning.outputs.version }}
104
+ run: |
105
+ set -euo pipefail
106
+ git config user.name "github-actions[bot]"
107
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
108
+ if git rev-parse "v${VERSION}" >/dev/null 2>&1; then
109
+ echo "Tag v${VERSION} already exists"
110
+ else
111
+ git tag -a "v${VERSION}" -m "Release v${VERSION}"
112
+ git push origin "v${VERSION}"
113
+ fi
114
+ - name: Create GitHub release
115
+ uses: softprops/action-gh-release@v2
116
+ with:
117
+ tag_name: v${{ needs.versioning.outputs.version }}
118
+ generate_release_notes: true
119
+ files: dist/*
120
+ - name: Publish to PyPI using trusted publishing
121
+ uses: pypa/gh-action-pypi-publish@release/v1
122
+ with:
123
+ password: ${{ secrets.PYPI }}
@@ -0,0 +1,50 @@
1
+ name: Documentation
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "docs/**"
8
+ - "src/**"
9
+ - "assetts/**"
10
+ - "pyproject.toml"
11
+ - ".github/workflows/docs.yml"
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+ pages: write
17
+ id-token: write
18
+
19
+ concurrency:
20
+ group: pages
21
+ cancel-in-progress: true
22
+
23
+ jobs:
24
+ build:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ - uses: actions/setup-python@v5
29
+ with:
30
+ python-version: "3.12"
31
+ cache: pip
32
+ - name: Install package and documentation dependencies
33
+ run: python -m pip install -e ".[docs]"
34
+ - name: Build Jupyter Book
35
+ run: jupyter-book build docs
36
+ - uses: actions/upload-pages-artifact@v3
37
+ with:
38
+ path: docs/_build/html
39
+
40
+ deploy:
41
+ environment:
42
+ name: github-pages
43
+ url: ${{ steps.deployment.outputs.page_url }}
44
+ runs-on: ubuntu-latest
45
+ needs: build
46
+ steps:
47
+ - name: Deploy to GitHub Pages
48
+ id: deployment
49
+ uses: actions/deploy-pages@v4
50
+
dhidb-0.1.0/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .coverage
7
+ htmlcov/
8
+ build/
9
+ dist/
10
+ docs/_build/
11
+ .venv/
12
+ .DS_Store
dhidb-0.1.0/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Helmholtz Centre for Environmental Research - UFZ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
dhidb-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.4
2
+ Name: dhidb
3
+ Version: 0.1.0
4
+ Summary: Read-only Python access to the global 300 m Dynamic Habitat Indices database
5
+ Author: Julian Oeser, Ingolf Kühn
6
+ Author-email: Taimur Khan <taimur.khan@ufz.de>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/thisistaimur/dhidb
9
+ Project-URL: Documentation, https://thisistaimur.github.io/dhidb/
10
+ Project-URL: Repository, https://github.com/thisistaimur/dhidb
11
+ Project-URL: Issues, https://github.com/thisistaimur/dhidb/issues
12
+ Keywords: biodiversity,DHI,remote sensing,S3,TileDB
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: GIS
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: affine>=2.4
25
+ Requires-Dist: numpy<3,>=1.26
26
+ Requires-Dist: pandas>=2.1
27
+ Requires-Dist: pyproj>=3.6
28
+ Requires-Dist: rasterio>=1.3
29
+ Requires-Dist: shapely>=2.0
30
+ Requires-Dist: tiledb<0.38,>=0.35
31
+ Requires-Dist: xarray>=2024.1
32
+ Provides-Extra: docs
33
+ Requires-Dist: jupyter-book<2,>=1.0; extra == "docs"
34
+ Requires-Dist: matplotlib>=3.8; extra == "docs"
35
+ Requires-Dist: sphinx-copybutton>=0.5; extra == "docs"
36
+ Provides-Extra: test
37
+ Requires-Dist: build>=1.2; extra == "test"
38
+ Requires-Dist: pytest>=8; extra == "test"
39
+ Requires-Dist: pytest-cov>=5; extra == "test"
40
+ Requires-Dist: ruff>=0.9; extra == "test"
41
+ Dynamic: license-file
42
+
43
+ <p align="center">
44
+ <img src="https://raw.githubusercontent.com/thisistaimur/dhidb/main/assetts/DHIDB_logo_white.png" alt="DHIDB" width="720">
45
+ </p>
46
+
47
+ # dhidb
48
+
49
+ `dhidb` provides read-only Python access to the global 300 m Dynamic Habitat
50
+ Indices database stored as a dense TileDB array on public S3-compatible object
51
+ storage. It supports point, bounding-box, and polygon queries without first
52
+ downloading the complete database.
53
+
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ pip install dhidb
59
+ ```
60
+
61
+ For development:
62
+
63
+ ```bash
64
+ python -m pip install -e ".[test,docs]"
65
+ ```
66
+
67
+ ## Quick start
68
+
69
+ ```python
70
+ from dhidb import DHIProvider
71
+
72
+ with DHIProvider() as db:
73
+ print(db.years)
74
+ print(db.variables)
75
+
76
+ germany = db.query_bbox(
77
+ bounds=(5.8, 47.2, 15.1, 55.1),
78
+ years=[2020, 2021, 2022],
79
+ variables=["dhi_cum", "dhi_min", "dhi_var", "valid_count"],
80
+ )
81
+ ```
82
+
83
+ ## Documentation
84
+
85
+ The Jupyter Book source is in [`docs/`](docs/). Build it locally with:
86
+
87
+ ```bash
88
+ jupyter-book build docs
89
+ ```
90
+
91
+ ## Data variables
92
+
93
+ | Variable | Meaning | Unit |
94
+ |---|---|---|
95
+ | `dhi_cum` | Cumulative productivity from LSP TPROD | PPI integral (`m2 m-2 day`) |
96
+ | `dhi_min` | Minimum seasonal productivity baseline from LSP MINV | PPI (`m2 m-2`) |
97
+ | `dhi_var` | Inter-period GPP coefficient of variation | dimensionless |
98
+ | `dhi_combined` | Normalized combined DHI, where available | dimensionless |
99
+ | `observed_count` | Number of available 10-day observations | scenes |
100
+ | `valid_count` | Number of accepted 10-day observations | scenes |
101
+ | `qflag_any_count` | Observations carrying any source quality flag | scenes |
102
+ | `qflag_rejected_count` | Observations rejected by quality filtering | scenes |
103
+
104
+ ## License
105
+
106
+ MIT
dhidb-0.1.0/README.md ADDED
@@ -0,0 +1,64 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/thisistaimur/dhidb/main/assetts/DHIDB_logo_white.png" alt="DHIDB" width="720">
3
+ </p>
4
+
5
+ # dhidb
6
+
7
+ `dhidb` provides read-only Python access to the global 300 m Dynamic Habitat
8
+ Indices database stored as a dense TileDB array on public S3-compatible object
9
+ storage. It supports point, bounding-box, and polygon queries without first
10
+ downloading the complete database.
11
+
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install dhidb
17
+ ```
18
+
19
+ For development:
20
+
21
+ ```bash
22
+ python -m pip install -e ".[test,docs]"
23
+ ```
24
+
25
+ ## Quick start
26
+
27
+ ```python
28
+ from dhidb import DHIProvider
29
+
30
+ with DHIProvider() as db:
31
+ print(db.years)
32
+ print(db.variables)
33
+
34
+ germany = db.query_bbox(
35
+ bounds=(5.8, 47.2, 15.1, 55.1),
36
+ years=[2020, 2021, 2022],
37
+ variables=["dhi_cum", "dhi_min", "dhi_var", "valid_count"],
38
+ )
39
+ ```
40
+
41
+ ## Documentation
42
+
43
+ The Jupyter Book source is in [`docs/`](docs/). Build it locally with:
44
+
45
+ ```bash
46
+ jupyter-book build docs
47
+ ```
48
+
49
+ ## Data variables
50
+
51
+ | Variable | Meaning | Unit |
52
+ |---|---|---|
53
+ | `dhi_cum` | Cumulative productivity from LSP TPROD | PPI integral (`m2 m-2 day`) |
54
+ | `dhi_min` | Minimum seasonal productivity baseline from LSP MINV | PPI (`m2 m-2`) |
55
+ | `dhi_var` | Inter-period GPP coefficient of variation | dimensionless |
56
+ | `dhi_combined` | Normalized combined DHI, where available | dimensionless |
57
+ | `observed_count` | Number of available 10-day observations | scenes |
58
+ | `valid_count` | Number of accepted 10-day observations | scenes |
59
+ | `qflag_any_count` | Observations carrying any source quality flag | scenes |
60
+ | `qflag_rejected_count` | Observations rejected by quality filtering | scenes |
61
+
62
+ ## License
63
+
64
+ MIT
Binary file
Binary file
@@ -0,0 +1,35 @@
1
+ title: DHIDB
2
+ author: Taimur Khan, Julian Oeser, and Ingolf Kühn
3
+ copyright: "2026, Helmholtz Centre for Environmental Research - UFZ"
4
+ logo: _static/DHIDB_logo.png
5
+ only_build_toc_files: true
6
+ execute:
7
+ execute_notebooks: "off"
8
+ parse:
9
+ myst_enable_extensions:
10
+ - colon_fence
11
+ - deflist
12
+ - dollarmath
13
+ - linkify
14
+ repository:
15
+ url: https://github.com/thisistaimur/dhidb
16
+ branch: main
17
+ html:
18
+ favicon: _static/DHIDB_logo.png
19
+ use_issues_button: true
20
+ use_repository_button: true
21
+ home_page_in_navbar: true
22
+ extra_footer: >-
23
+ DHIDB is developed at the Helmholtz Centre for Environmental Research - UFZ.
24
+ sphinx:
25
+ extra_extensions:
26
+ - sphinx.ext.autodoc
27
+ - sphinx.ext.napoleon
28
+ - sphinx_copybutton
29
+ config:
30
+ html_css_files:
31
+ - custom.css
32
+ html_theme_options:
33
+ logo:
34
+ text: DHIDB
35
+ show_nav_level: 2
Binary file
@@ -0,0 +1,75 @@
1
+ :root {
2
+ --dhidb-black: #050505;
3
+ --dhidb-panel: #111416;
4
+ --dhidb-purple: #440154;
5
+ --dhidb-blue: #31688e;
6
+ --dhidb-green: #35b779;
7
+ --dhidb-yellow: #fde725;
8
+ --pst-color-primary: #35b779;
9
+ --pst-color-link: #35b779;
10
+ --pst-color-link-hover: #fde725;
11
+ }
12
+
13
+ html[data-theme="light"],
14
+ html[data-theme="dark"] {
15
+ --pst-color-background: var(--dhidb-black);
16
+ --pst-color-on-background: #f4f7f5;
17
+ --pst-color-surface: var(--dhidb-panel);
18
+ --pst-color-on-surface: #e8efec;
19
+ --pst-color-text-base: #eef4f1;
20
+ --pst-color-text-muted: #aab8b2;
21
+ --pst-color-border: #27302d;
22
+ }
23
+
24
+ body,
25
+ .bd-header,
26
+ .bd-sidebar-primary,
27
+ .bd-sidebar-secondary,
28
+ .bd-main .bd-content .bd-article-container {
29
+ background: var(--dhidb-black);
30
+ color: #eef4f1;
31
+ }
32
+
33
+ .bd-header {
34
+ border-bottom: 1px solid #27302d;
35
+ }
36
+
37
+ a,
38
+ .toc-entry a.nav-link.active,
39
+ .bd-links .current > a {
40
+ color: var(--dhidb-green);
41
+ }
42
+
43
+ a:hover {
44
+ color: var(--dhidb-yellow);
45
+ }
46
+
47
+ code {
48
+ color: #9be26d;
49
+ }
50
+
51
+ pre,
52
+ div.highlight {
53
+ background: #0d1110;
54
+ border: 1px solid #27302d;
55
+ }
56
+
57
+ .hero-logo {
58
+ margin: 1rem auto 2rem;
59
+ max-height: 300px;
60
+ object-fit: contain;
61
+ }
62
+
63
+ table {
64
+ border-color: #27302d;
65
+ }
66
+
67
+ thead {
68
+ background: linear-gradient(90deg, var(--dhidb-purple), var(--dhidb-blue));
69
+ }
70
+
71
+ .admonition {
72
+ background: var(--dhidb-panel);
73
+ border-left-color: var(--dhidb-green);
74
+ }
75
+
@@ -0,0 +1,10 @@
1
+ format: jb-book
2
+ root: index
3
+ chapters:
4
+ - file: getting-started
5
+ - file: data-model
6
+ - file: queries
7
+ - file: quality
8
+ - file: api
9
+ - file: contributing
10
+
@@ -0,0 +1,11 @@
1
+ # Python API
2
+
3
+ ```{eval-rst}
4
+ .. autoclass:: dhidb.DHIConfig
5
+ :members:
6
+
7
+ .. autoclass:: dhidb.DHIProvider
8
+ :members:
9
+ :undoc-members:
10
+ ```
11
+
@@ -0,0 +1,22 @@
1
+ # Contributing and releases
2
+
3
+ Install the development environment and run the checks locally:
4
+
5
+ ```bash
6
+ python -m pip install -e ".[test,docs]"
7
+ ruff check src tests
8
+ pytest
9
+ python -m build
10
+ jupyter-book build docs
11
+ ```
12
+
13
+ ## Versioning
14
+
15
+ The CI workflow derives a semantic version from Git history. It computes the
16
+ candidate version for pull requests and pushes, but creates a tag, GitHub
17
+ release, and PyPI distribution only after the test matrix and package build
18
+ have succeeded on `main`.
19
+
20
+ PyPI publication uses GitHub trusted publishing. Configure the `pypi`
21
+ environment for this repository on PyPI before enabling the first release.
22
+
@@ -0,0 +1,31 @@
1
+ # Data model
2
+
3
+ DHIDB v1 is a dense TileDB array with dimensions `(time, y, x)`.
4
+
5
+ | Dimension | Size | Meaning |
6
+ |---|---:|---|
7
+ | `time` | 12 | Annual layers from 2014 through 2025 |
8
+ | `y` | 47,040 | Global raster rows |
9
+ | `x` | 120,960 | Global raster columns |
10
+
11
+ Each annual layer contains 5,689,958,400 grid cells. The complete logical
12
+ array contains 68,279,500,800 cells before compression and exclusion of
13
+ unwritten fragments.
14
+
15
+ ## Variables
16
+
17
+ | Variable | Definition | Unit |
18
+ |---|---|---|
19
+ | `dhi_cum` | Sum of LSP TPROD over two growing seasons | PPI integral (`m2 m-2 day`) |
20
+ | `dhi_min` | Minimum of scaled LSP MINV over two growing seasons | PPI (`m2 m-2`) |
21
+ | `dhi_var` | Coefficient of variation of accepted 10-day GPP | dimensionless |
22
+ | `dhi_combined` | Sum of normalized component layers | dimensionless |
23
+ | `observed_count` | Available GPP observations | scenes |
24
+ | `valid_count` | Accepted GPP observations | scenes |
25
+ | `qflag_any_count` | Observations carrying any source QFLAG | scenes |
26
+ | `qflag_rejected_count` | Rejected observations | scenes |
27
+
28
+ `dhi_cum` and `dhi_min` summarize the smoothed Plant Phenology Index
29
+ trajectory represented by Copernicus LSP. They are not direct annual GPP sums
30
+ or minima. `dhi_var` is calculated from the 10-day GPP time series.
31
+
@@ -0,0 +1,41 @@
1
+ # Getting started
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ pip install dhidb
7
+ ```
8
+
9
+ ## Connect to public QAS storage
10
+
11
+ Public reads use unsigned S3 requests. No access key is required.
12
+
13
+ ```python
14
+ from dhidb import DHIProvider
15
+
16
+ db = DHIProvider()
17
+ print(db.years)
18
+ print(db.variables)
19
+ db.close()
20
+ ```
21
+
22
+ The provider uses the public endpoint and array defaults, so Python needs no
23
+ connection arguments:
24
+
25
+ ```python
26
+ from dhidb import DHIProvider
27
+
28
+ with DHIProvider() as db:
29
+ print(db.metadata)
30
+ ```
31
+
32
+
33
+ ## Query safety
34
+
35
+ The default client refuses a request containing more than 50 million
36
+ space-time cells. This protects laptops from accidentally materializing a
37
+ global array. Raise the limit deliberately when appropriate:
38
+
39
+ ```python
40
+ db = DHIProvider(max_cells=100_000_000)
41
+ ```
@@ -0,0 +1,37 @@
1
+ # Global habitat dynamics, queried where you need them
2
+
3
+ ```{image} _static/DHIDB_logo.png
4
+ :alt: DHIDB logo
5
+ :class: hero-logo
6
+ :width: 760px
7
+ :align: center
8
+ ```
9
+
10
+ DHIDB provides direct, read-only access to annual global Dynamic Habitat
11
+ Indices at 300 m resolution. The data remain in a dense TileDB array on public
12
+ S3-compatible object storage; the Python package retrieves only the years,
13
+ variables, and spatial window requested by the user.
14
+
15
+ The indices describe three complementary dimensions of vegetation dynamics:
16
+
17
+ - cumulative productivity (`dhi_cum`),
18
+ - the minimum seasonal productivity baseline (`dhi_min`), and
19
+ - inter-period variability in gross primary production (`dhi_var`).
20
+
21
+ ```python
22
+ from dhidb import DHIProvider
23
+
24
+ with DHIProvider() as db:
25
+ point = db.query_point(12.37, 51.34, years=range(2014, 2026))
26
+ ```
27
+
28
+ :::{important}
29
+ The provider uses the public QAS endpoint and production array defaults
30
+ automatically. Public reads do not require credentials.
31
+ :::
32
+
33
+ ## Why TileDB?
34
+
35
+ The database contains 12 annual layers over a grid of 47,040 by 120,960 cells,
36
+ or 68,279,500,800 dense array cells. TileDB exposes this as `(time, y, x)` and
37
+ allows small spatial subsets to be read without transferring the full array.
@@ -0,0 +1,16 @@
1
+ # Quality information
2
+
3
+ The database retains observation counts alongside the DHI components so that
4
+ users can evaluate temporal support for each pixel.
5
+
6
+ `observed_count` records how many 10-day GPP scenes were present.
7
+ `valid_count` records how many contributed after source-quality screening.
8
+ `qflag_any_count` and `qflag_rejected_count` summarize the original
9
+ Copernicus QFLAG observations.
10
+
11
+ For annual products, a maximum `valid_count` of 36 is expected. The TileDB
12
+ fill value for an unwritten `uint16` cell is 65,535; clients should not
13
+ interpret that value as an observation count. Query only production-complete
14
+ years and use finite DHI values together with plausible count values when
15
+ validating an analysis.
16
+