geobridge 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.
Files changed (33) hide show
  1. geobridge-0.1.0/.gitignore +24 -0
  2. geobridge-0.1.0/LICENSE +21 -0
  3. geobridge-0.1.0/PKG-INFO +331 -0
  4. geobridge-0.1.0/README.md +249 -0
  5. geobridge-0.1.0/geobridge/__init__.py +130 -0
  6. geobridge-0.1.0/geobridge/auth.py +191 -0
  7. geobridge-0.1.0/geobridge/modules/__init__.py +1 -0
  8. geobridge-0.1.0/geobridge/modules/cds_download.py +445 -0
  9. geobridge-0.1.0/geobridge/modules/discover.py +661 -0
  10. geobridge-0.1.0/geobridge/modules/extract.py +703 -0
  11. geobridge-0.1.0/geobridge/modules/form.py +464 -0
  12. geobridge-0.1.0/geobridge/modules/fuse.py +340 -0
  13. geobridge-0.1.0/geobridge/modules/style.py +317 -0
  14. geobridge-0.1.0/geobridge/modules/wmts.py +462 -0
  15. geobridge-0.1.0/geobridge/semantic/__init__.py +0 -0
  16. geobridge-0.1.0/geobridge/semantic/arco_overrides.yaml +67 -0
  17. geobridge-0.1.0/geobridge/semantic/arco_snapshot.yaml +44456 -0
  18. geobridge-0.1.0/geobridge/semantic/cds_snapshot.yaml +6333 -0
  19. geobridge-0.1.0/geobridge/semantic/engine.py +501 -0
  20. geobridge-0.1.0/geobridge/semantic/vocabulary.yaml +1122 -0
  21. geobridge-0.1.0/pyproject.toml +87 -0
  22. geobridge-0.1.0/scripts/refresh_arco_catalogue.py +452 -0
  23. geobridge-0.1.0/scripts/refresh_catalogue.py +372 -0
  24. geobridge-0.1.0/smoke_test.py +347 -0
  25. geobridge-0.1.0/tests/__init__.py +0 -0
  26. geobridge-0.1.0/tests/test_auth.py +103 -0
  27. geobridge-0.1.0/tests/unit/__init__.py +0 -0
  28. geobridge-0.1.0/tests/unit/test_auth.py +88 -0
  29. geobridge-0.1.0/tests/unit/test_discover.py +253 -0
  30. geobridge-0.1.0/tests/unit/test_extract.py +174 -0
  31. geobridge-0.1.0/tests/unit/test_semantic.py +135 -0
  32. geobridge-0.1.0/tests/unit/test_style.py +96 -0
  33. geobridge-0.1.0/tests/unit/test_wmts.py +147 -0
@@ -0,0 +1,24 @@
1
+ # Claude
2
+ .claude/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.pyo
8
+ .DS_Store
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Distribution / packaging
16
+ dist/
17
+ build/
18
+ *.egg-info/
19
+
20
+ # Jupyter
21
+ .ipynb_checkpoints/
22
+
23
+ # folders
24
+ examples/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GeoBridge contributors
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.
@@ -0,0 +1,331 @@
1
+ Metadata-Version: 2.4
2
+ Name: geobridge
3
+ Version: 0.1.0
4
+ Summary: Python bridge between Copernicus Data Stores (C3S, CAMS, CEMS) and mainstream GIS operations
5
+ Project-URL: Homepage, https://github.com/ECMWFCode4Earth/GeoBridge
6
+ Project-URL: Repository, https://github.com/ECMWFCode4Earth/GeoBridge
7
+ Project-URL: Issues, https://github.com/ECMWFCode4Earth/GeoBridge/issues
8
+ Author: Kostas Fokeas and Ilias Machairas
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 GeoBridge contributors
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: CAMS,CEMS,ERA5,GIS,WMTS,climate,copernicus,earth-observation,geotiff,zarr
32
+ Classifier: Development Status :: 3 - Alpha
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Intended Audience :: Science/Research
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3.10
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
40
+ Classifier: Topic :: Scientific/Engineering :: GIS
41
+ Requires-Python: >=3.10
42
+ Requires-Dist: pyyaml>=6.0
43
+ Provides-Extra: dev
44
+ Requires-Dist: build; extra == 'dev'
45
+ Requires-Dist: cfgrib>=0.9.10; extra == 'dev'
46
+ Requires-Dist: dask>=2023.1; extra == 'dev'
47
+ Requires-Dist: fsspec>=2023.1; extra == 'dev'
48
+ Requires-Dist: mypy>=1.8; extra == 'dev'
49
+ Requires-Dist: numpy>=1.24; extra == 'dev'
50
+ Requires-Dist: owslib>=0.28; extra == 'dev'
51
+ Requires-Dist: pyproj>=3.5; extra == 'dev'
52
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
53
+ Requires-Dist: pytest>=7.4; extra == 'dev'
54
+ Requires-Dist: rasterio>=1.3; extra == 'dev'
55
+ Requires-Dist: responses>=0.23; extra == 'dev'
56
+ Requires-Dist: rioxarray>=0.14; extra == 'dev'
57
+ Requires-Dist: ruff>=0.4; extra == 'dev'
58
+ Requires-Dist: types-pyyaml; extra == 'dev'
59
+ Requires-Dist: types-requests; extra == 'dev'
60
+ Requires-Dist: xarray>=2023.1; extra == 'dev'
61
+ Requires-Dist: zarr>=2.16; extra == 'dev'
62
+ Provides-Extra: full
63
+ Requires-Dist: cfgrib>=0.9.10; extra == 'full'
64
+ Requires-Dist: dask>=2023.1; extra == 'full'
65
+ Requires-Dist: fsspec>=2023.1; extra == 'full'
66
+ Requires-Dist: numpy>=1.24; extra == 'full'
67
+ Requires-Dist: owslib>=0.28; extra == 'full'
68
+ Requires-Dist: pyproj>=3.5; extra == 'full'
69
+ Requires-Dist: rasterio>=1.3; extra == 'full'
70
+ Requires-Dist: rioxarray>=0.14; extra == 'full'
71
+ Requires-Dist: xarray>=2023.1; extra == 'full'
72
+ Requires-Dist: zarr>=2.16; extra == 'full'
73
+ Provides-Extra: zarr
74
+ Requires-Dist: dask>=2023.1; extra == 'zarr'
75
+ Requires-Dist: fsspec>=2023.1; extra == 'zarr'
76
+ Requires-Dist: numpy>=1.24; extra == 'zarr'
77
+ Requires-Dist: rasterio>=1.3; extra == 'zarr'
78
+ Requires-Dist: rioxarray>=0.14; extra == 'zarr'
79
+ Requires-Dist: xarray>=2023.1; extra == 'zarr'
80
+ Requires-Dist: zarr>=2.16; extra == 'zarr'
81
+ Description-Content-Type: text/markdown
82
+
83
+ # GeoBridge
84
+
85
+ **Python library that bridges Copernicus Data Stores into mainstream GIS workflows.**
86
+
87
+ GeoBridge removes the technical friction GIS users face when working with
88
+ Copernicus climate, atmosphere, and emergency data. It resolves dataset
89
+ discovery, authentication, and access-method differences into a single
90
+ ergonomic API that produces analysis-ready Cloud Optimized GeoTIFFs.
91
+
92
+ The library is the foundation for the project's QGIS plugin.
93
+
94
+ ---
95
+
96
+ ## What it does
97
+
98
+ - **Discovery.** `gb.discover()` lists every dataset in the Copernicus
99
+ catalogue with filters for keyword, service, variable, bounding box, and
100
+ time range — all from a locally bundled snapshot, no network needed.
101
+ - **Authentication.** A single `gb.authenticate()` call handles credential
102
+ resolution for the new ARCO bearer-token model.
103
+ - **Extraction — ARCO path.** `gb.zarr_to_geotiff()` pulls a spatial / temporal
104
+ subset from the ARCO Zarr Data Lake and writes it as a Cloud Optimized
105
+ GeoTIFF, ready for QGIS or ArcGIS.
106
+ - **Extraction — CDS API path.** `gb.cds_to_geotiff()` submits a download job
107
+ through the standard CDS API for datasets that are not yet in the ARCO lake,
108
+ converts the result to GeoTIFF, and streams it to disk.
109
+ - **WMTS.** `gb.wmts_layer()` returns a ready-to-use WMTS layer object for
110
+ live tile streaming inside QGIS or Leaflet.
111
+ - **Form schema.** `gb.fetch_form()` and `gb.fetch_constraints()` retrieve the
112
+ server-side parameter form for any dataset so your UI can build validated
113
+ request widgets. `gb.valid_variables_for_product_type()` filters the variable
114
+ list to what the selected product type actually supports.
115
+ - **Styling.** `gb.to_qgis_style()` generate
116
+ calibrated colour ramps for known Copernicus variables.
117
+ - **Fusion.** `gb.fuse()` co-registers multiple layers onto a common grid
118
+ for joint analysis (e.g. heat + air quality).
119
+ - **Semantics.** `gb.semantic_search()` resolves user themes like
120
+ "urban heat island" or "wildfire risk" into concrete dataset and
121
+ workflow recommendations. `gb.list_themes()` and `gb.list_use_cases()`
122
+ enumerate the built-in vocabulary.
123
+
124
+ ---
125
+
126
+ ## How to run it
127
+
128
+ ### Prerequisites
129
+
130
+ - **Python 3.10 or newer.** GeoBridge does not support older Python.
131
+ - **A free Copernicus account.** Register at
132
+ https://cds.climate.copernicus.eu and copy your personal access token
133
+ from your profile page.
134
+ - **macOS, Linux, or Windows with WSL2.** Native Windows may work but is
135
+ not tested.
136
+
137
+ ### Step 1 — Create a clean environment
138
+
139
+ A separate environment avoids dependency conflicts with anything else you
140
+ have installed. With Conda (recommended because some geospatial libraries
141
+ need compiled C bindings that pip alone struggles with):
142
+
143
+ ```bash
144
+ conda create -n geobridge python=3.11 -y
145
+ conda activate geobridge
146
+ ```
147
+
148
+ Or with `venv`:
149
+
150
+ ```bash
151
+ python3.11 -m venv ~/.venvs/geobridge
152
+ source ~/.venvs/geobridge/bin/activate
153
+ ```
154
+
155
+ ### Step 2 — Install the geospatial stack
156
+
157
+ If you used Conda, install the heavy native dependencies through
158
+ conda-forge first:
159
+
160
+ ```bash
161
+ conda install -c conda-forge rasterio rioxarray zarr fsspec httpio dask -y
162
+ ```
163
+
164
+ This avoids the most common build failures (GDAL, PROJ, libtiff).
165
+
166
+ ### Step 3 — Clone and install GeoBridge
167
+
168
+ ```bash
169
+ git clone https://github.com/YOUR_USERNAME/geobridge.git
170
+ cd geobridge
171
+ pip install -e ".[zarr]"
172
+ ```
173
+
174
+ `-e` installs in editable mode so you can pull updates without
175
+ reinstalling. The `[zarr]` extra adds the optional dependencies needed
176
+ for `zarr_to_geotiff()`. Use `.[full]` to also get OWSLib (WMTS) and
177
+ cfgrib (GRIB support).
178
+
179
+ ### Step 4 — Configure your credentials
180
+
181
+ Create `~/.cdsapirc` with your personal access token:
182
+
183
+ ```
184
+ key: YOUR-CDS-API-KEY-HERE
185
+ ```
186
+
187
+ Then protect the file so other users on the machine cannot read it:
188
+
189
+ ```bash
190
+ chmod 600 ~/.cdsapirc
191
+ ```
192
+
193
+ Alternatively, export your key as an environment variable instead of
194
+ writing it to a file:
195
+
196
+ ```bash
197
+ export CDS_API_KEY=YOUR-CDS-API-KEY-HERE
198
+ ```
199
+
200
+ ### Step 5 — Verify the installation
201
+
202
+ Run the bundled smoke test. It exercises every module without making
203
+ network calls:
204
+
205
+ ```bash
206
+ PYTHONPATH=. python smoke_test.py
207
+ ```
208
+
209
+ Expected: nine stages all pass, ending with `ALL SMOKE TESTS PASSED`.
210
+
211
+ ### Step 6 — Run the Athens demo
212
+
213
+ This is the end-to-end demonstration. It extracts ERA5 temperature for
214
+ Athens summer 2023, writes a Cloud Optimized GeoTIFF, and generates a
215
+ matching QGIS style:
216
+
217
+ ```bash
218
+ python examples/athens_urban_heat.py
219
+ ```
220
+
221
+ Expected runtime is roughly one minute on a reasonable broadband
222
+ connection. The output appears in `./athens_outputs/`. Open the `.tif` in
223
+ QGIS, load the `.qml` style alongside it, and you should see Athens
224
+ temperatures rendered with a calibrated colour ramp.
225
+
226
+ ---
227
+
228
+ ## Repository layout
229
+
230
+ ```
231
+ geobridge/ ← repository root
232
+ ├── README.md ← this file
233
+ ├── LICENSE ← MIT
234
+ ├── pyproject.toml ← installable Python package
235
+ ├── smoke_test.py ← offline smoke test (9 stages)
236
+
237
+ ├── geobridge/ ← Python package
238
+ │ ├── __init__.py ← public API exports
239
+ │ ├── auth.py ← bearer-token authentication
240
+ │ ├── modules/
241
+ │ │ ├── discover.py ← catalogue discovery
242
+ │ │ ├── extract.py ← ARCO Zarr → GeoTIFF
243
+ │ │ ├── cds_download.py ← CDS API → GeoTIFF (non-ARCO datasets)
244
+ │ │ ├── wmts.py ← WMTS layer
245
+ │ │ ├── form.py ← dataset form schema & constraints
246
+ │ │ ├── style.py ← QGIS QML export
247
+ │ │ └── fuse.py ← multi-layer co-registration
248
+ │ └── semantic/
249
+ │ ├── engine.py ← rule-based query resolver
250
+ │ ├── vocabulary.yaml ← themes and use cases
251
+ │ ├── arco_overrides.yaml ← Zarr URLs and variable aliases
252
+ │ ├── arco_snapshot.yaml ← ARCO catalogue snapshot (generated)
253
+ │ └── cds_snapshot.yaml ← STAC catalogue snapshot (generated)
254
+
255
+ ├── scripts/
256
+ │ ├── refresh_catalogue.py ← maintainer-side CDS STAC refresh
257
+ │ └── refresh_arco_catalogue.py ← maintainer-side ARCO snapshot refresh
258
+
259
+ ├── examples/
260
+ │ ├── athens_urban_heat.py ← end-to-end ERA5 demo
261
+ │ ├── example_utci.py ← UTCI thermal comfort demo
262
+ │ ├── examplepm2.5.py ← CAMS PM2.5 air quality demo
263
+ │ └── ... ← additional live-test scripts
264
+
265
+ └── tests/
266
+ ├── test_auth.py
267
+ └── unit/ ← pytest unit tests
268
+ ├── test_discover.py
269
+ ├── test_auth.py
270
+ ├── test_extract.py
271
+ ├── test_style.py
272
+ ├── test_semantic.py
273
+ └── test_wmts.py
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Maintainer workflow
279
+
280
+ ### Refreshing catalogue snapshots
281
+
282
+ The `cds_snapshot.yaml` and `arco_snapshot.yaml` files are regenerated
283
+ periodically from the live ECMWF catalogues. End users never run these
284
+ scripts; they get the snapshots bundled with whatever GeoBridge version
285
+ they install.
286
+
287
+ To refresh the CDS STAC snapshot (maintainers only):
288
+
289
+ ```bash
290
+ python scripts/refresh_catalogue.py --limit 5 --output /tmp/test.yaml # quick test
291
+ python scripts/refresh_catalogue.py # full run
292
+ git diff geobridge/semantic/cds_snapshot.yaml
293
+ git add geobridge/semantic/cds_snapshot.yaml
294
+ git commit -m "Refresh CDS catalogue snapshot"
295
+ ```
296
+
297
+ To refresh the ARCO snapshot:
298
+
299
+ ```bash
300
+ python scripts/refresh_arco_catalogue.py
301
+ git add geobridge/semantic/arco_snapshot.yaml
302
+ git commit -m "Refresh ARCO catalogue snapshot"
303
+ ```
304
+
305
+ ### Adding a new ARCO dataset
306
+
307
+ 1. Visit the dataset page on https://cds.climate.copernicus.eu and open
308
+ the "Analysis ready data" tab.
309
+ 2. Copy the Zarr URLs (typically there are two: `time_chunked` and
310
+ `geo_chunked`).
311
+ 3. Verify each URL responds with a 200 status:
312
+
313
+ ```bash
314
+ curl -I -H "Authorization: Bearer $CDS_API_KEY" "https://.../.zmetadata"
315
+ ```
316
+
317
+ 4. Add an entry to `geobridge/semantic/arco_overrides.yaml` following the
318
+ schema of existing entries.
319
+ 5. Add the variable aliases (CDS long-form name → ARCO short-form name)
320
+ by inspecting the Zarr store with `xarray.open_zarr()` and listing
321
+ `ds.data_vars`.
322
+
323
+ ---
324
+
325
+ ## License
326
+
327
+ MIT. See `LICENSE`.
328
+
329
+ ---
330
+
331
+ ## Acknowledgements
@@ -0,0 +1,249 @@
1
+ # GeoBridge
2
+
3
+ **Python library that bridges Copernicus Data Stores into mainstream GIS workflows.**
4
+
5
+ GeoBridge removes the technical friction GIS users face when working with
6
+ Copernicus climate, atmosphere, and emergency data. It resolves dataset
7
+ discovery, authentication, and access-method differences into a single
8
+ ergonomic API that produces analysis-ready Cloud Optimized GeoTIFFs.
9
+
10
+ The library is the foundation for the project's QGIS plugin.
11
+
12
+ ---
13
+
14
+ ## What it does
15
+
16
+ - **Discovery.** `gb.discover()` lists every dataset in the Copernicus
17
+ catalogue with filters for keyword, service, variable, bounding box, and
18
+ time range — all from a locally bundled snapshot, no network needed.
19
+ - **Authentication.** A single `gb.authenticate()` call handles credential
20
+ resolution for the new ARCO bearer-token model.
21
+ - **Extraction — ARCO path.** `gb.zarr_to_geotiff()` pulls a spatial / temporal
22
+ subset from the ARCO Zarr Data Lake and writes it as a Cloud Optimized
23
+ GeoTIFF, ready for QGIS or ArcGIS.
24
+ - **Extraction — CDS API path.** `gb.cds_to_geotiff()` submits a download job
25
+ through the standard CDS API for datasets that are not yet in the ARCO lake,
26
+ converts the result to GeoTIFF, and streams it to disk.
27
+ - **WMTS.** `gb.wmts_layer()` returns a ready-to-use WMTS layer object for
28
+ live tile streaming inside QGIS or Leaflet.
29
+ - **Form schema.** `gb.fetch_form()` and `gb.fetch_constraints()` retrieve the
30
+ server-side parameter form for any dataset so your UI can build validated
31
+ request widgets. `gb.valid_variables_for_product_type()` filters the variable
32
+ list to what the selected product type actually supports.
33
+ - **Styling.** `gb.to_qgis_style()` generate
34
+ calibrated colour ramps for known Copernicus variables.
35
+ - **Fusion.** `gb.fuse()` co-registers multiple layers onto a common grid
36
+ for joint analysis (e.g. heat + air quality).
37
+ - **Semantics.** `gb.semantic_search()` resolves user themes like
38
+ "urban heat island" or "wildfire risk" into concrete dataset and
39
+ workflow recommendations. `gb.list_themes()` and `gb.list_use_cases()`
40
+ enumerate the built-in vocabulary.
41
+
42
+ ---
43
+
44
+ ## How to run it
45
+
46
+ ### Prerequisites
47
+
48
+ - **Python 3.10 or newer.** GeoBridge does not support older Python.
49
+ - **A free Copernicus account.** Register at
50
+ https://cds.climate.copernicus.eu and copy your personal access token
51
+ from your profile page.
52
+ - **macOS, Linux, or Windows with WSL2.** Native Windows may work but is
53
+ not tested.
54
+
55
+ ### Step 1 — Create a clean environment
56
+
57
+ A separate environment avoids dependency conflicts with anything else you
58
+ have installed. With Conda (recommended because some geospatial libraries
59
+ need compiled C bindings that pip alone struggles with):
60
+
61
+ ```bash
62
+ conda create -n geobridge python=3.11 -y
63
+ conda activate geobridge
64
+ ```
65
+
66
+ Or with `venv`:
67
+
68
+ ```bash
69
+ python3.11 -m venv ~/.venvs/geobridge
70
+ source ~/.venvs/geobridge/bin/activate
71
+ ```
72
+
73
+ ### Step 2 — Install the geospatial stack
74
+
75
+ If you used Conda, install the heavy native dependencies through
76
+ conda-forge first:
77
+
78
+ ```bash
79
+ conda install -c conda-forge rasterio rioxarray zarr fsspec httpio dask -y
80
+ ```
81
+
82
+ This avoids the most common build failures (GDAL, PROJ, libtiff).
83
+
84
+ ### Step 3 — Clone and install GeoBridge
85
+
86
+ ```bash
87
+ git clone https://github.com/YOUR_USERNAME/geobridge.git
88
+ cd geobridge
89
+ pip install -e ".[zarr]"
90
+ ```
91
+
92
+ `-e` installs in editable mode so you can pull updates without
93
+ reinstalling. The `[zarr]` extra adds the optional dependencies needed
94
+ for `zarr_to_geotiff()`. Use `.[full]` to also get OWSLib (WMTS) and
95
+ cfgrib (GRIB support).
96
+
97
+ ### Step 4 — Configure your credentials
98
+
99
+ Create `~/.cdsapirc` with your personal access token:
100
+
101
+ ```
102
+ key: YOUR-CDS-API-KEY-HERE
103
+ ```
104
+
105
+ Then protect the file so other users on the machine cannot read it:
106
+
107
+ ```bash
108
+ chmod 600 ~/.cdsapirc
109
+ ```
110
+
111
+ Alternatively, export your key as an environment variable instead of
112
+ writing it to a file:
113
+
114
+ ```bash
115
+ export CDS_API_KEY=YOUR-CDS-API-KEY-HERE
116
+ ```
117
+
118
+ ### Step 5 — Verify the installation
119
+
120
+ Run the bundled smoke test. It exercises every module without making
121
+ network calls:
122
+
123
+ ```bash
124
+ PYTHONPATH=. python smoke_test.py
125
+ ```
126
+
127
+ Expected: nine stages all pass, ending with `ALL SMOKE TESTS PASSED`.
128
+
129
+ ### Step 6 — Run the Athens demo
130
+
131
+ This is the end-to-end demonstration. It extracts ERA5 temperature for
132
+ Athens summer 2023, writes a Cloud Optimized GeoTIFF, and generates a
133
+ matching QGIS style:
134
+
135
+ ```bash
136
+ python examples/athens_urban_heat.py
137
+ ```
138
+
139
+ Expected runtime is roughly one minute on a reasonable broadband
140
+ connection. The output appears in `./athens_outputs/`. Open the `.tif` in
141
+ QGIS, load the `.qml` style alongside it, and you should see Athens
142
+ temperatures rendered with a calibrated colour ramp.
143
+
144
+ ---
145
+
146
+ ## Repository layout
147
+
148
+ ```
149
+ geobridge/ ← repository root
150
+ ├── README.md ← this file
151
+ ├── LICENSE ← MIT
152
+ ├── pyproject.toml ← installable Python package
153
+ ├── smoke_test.py ← offline smoke test (9 stages)
154
+
155
+ ├── geobridge/ ← Python package
156
+ │ ├── __init__.py ← public API exports
157
+ │ ├── auth.py ← bearer-token authentication
158
+ │ ├── modules/
159
+ │ │ ├── discover.py ← catalogue discovery
160
+ │ │ ├── extract.py ← ARCO Zarr → GeoTIFF
161
+ │ │ ├── cds_download.py ← CDS API → GeoTIFF (non-ARCO datasets)
162
+ │ │ ├── wmts.py ← WMTS layer
163
+ │ │ ├── form.py ← dataset form schema & constraints
164
+ │ │ ├── style.py ← QGIS QML export
165
+ │ │ └── fuse.py ← multi-layer co-registration
166
+ │ └── semantic/
167
+ │ ├── engine.py ← rule-based query resolver
168
+ │ ├── vocabulary.yaml ← themes and use cases
169
+ │ ├── arco_overrides.yaml ← Zarr URLs and variable aliases
170
+ │ ├── arco_snapshot.yaml ← ARCO catalogue snapshot (generated)
171
+ │ └── cds_snapshot.yaml ← STAC catalogue snapshot (generated)
172
+
173
+ ├── scripts/
174
+ │ ├── refresh_catalogue.py ← maintainer-side CDS STAC refresh
175
+ │ └── refresh_arco_catalogue.py ← maintainer-side ARCO snapshot refresh
176
+
177
+ ├── examples/
178
+ │ ├── athens_urban_heat.py ← end-to-end ERA5 demo
179
+ │ ├── example_utci.py ← UTCI thermal comfort demo
180
+ │ ├── examplepm2.5.py ← CAMS PM2.5 air quality demo
181
+ │ └── ... ← additional live-test scripts
182
+
183
+ └── tests/
184
+ ├── test_auth.py
185
+ └── unit/ ← pytest unit tests
186
+ ├── test_discover.py
187
+ ├── test_auth.py
188
+ ├── test_extract.py
189
+ ├── test_style.py
190
+ ├── test_semantic.py
191
+ └── test_wmts.py
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Maintainer workflow
197
+
198
+ ### Refreshing catalogue snapshots
199
+
200
+ The `cds_snapshot.yaml` and `arco_snapshot.yaml` files are regenerated
201
+ periodically from the live ECMWF catalogues. End users never run these
202
+ scripts; they get the snapshots bundled with whatever GeoBridge version
203
+ they install.
204
+
205
+ To refresh the CDS STAC snapshot (maintainers only):
206
+
207
+ ```bash
208
+ python scripts/refresh_catalogue.py --limit 5 --output /tmp/test.yaml # quick test
209
+ python scripts/refresh_catalogue.py # full run
210
+ git diff geobridge/semantic/cds_snapshot.yaml
211
+ git add geobridge/semantic/cds_snapshot.yaml
212
+ git commit -m "Refresh CDS catalogue snapshot"
213
+ ```
214
+
215
+ To refresh the ARCO snapshot:
216
+
217
+ ```bash
218
+ python scripts/refresh_arco_catalogue.py
219
+ git add geobridge/semantic/arco_snapshot.yaml
220
+ git commit -m "Refresh ARCO catalogue snapshot"
221
+ ```
222
+
223
+ ### Adding a new ARCO dataset
224
+
225
+ 1. Visit the dataset page on https://cds.climate.copernicus.eu and open
226
+ the "Analysis ready data" tab.
227
+ 2. Copy the Zarr URLs (typically there are two: `time_chunked` and
228
+ `geo_chunked`).
229
+ 3. Verify each URL responds with a 200 status:
230
+
231
+ ```bash
232
+ curl -I -H "Authorization: Bearer $CDS_API_KEY" "https://.../.zmetadata"
233
+ ```
234
+
235
+ 4. Add an entry to `geobridge/semantic/arco_overrides.yaml` following the
236
+ schema of existing entries.
237
+ 5. Add the variable aliases (CDS long-form name → ARCO short-form name)
238
+ by inspecting the Zarr store with `xarray.open_zarr()` and listing
239
+ `ds.data_vars`.
240
+
241
+ ---
242
+
243
+ ## License
244
+
245
+ MIT. See `LICENSE`.
246
+
247
+ ---
248
+
249
+ ## Acknowledgements