windkit 2.0.0__tar.gz → 2.0.1__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.
- {windkit-2.0.0 → windkit-2.0.1}/CHANGELOG.md +22 -6
- {windkit-2.0.0 → windkit-2.0.1}/PKG-INFO +49 -27
- windkit-2.0.1/pyproject.toml +113 -0
- windkit-2.0.1/setup.cfg +4 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/__init__.py +6 -1
- {windkit-2.0.0 → windkit-2.0.1}/windkit/_version.py +2 -2
- windkit-2.0.1/windkit/integrations/_earth_engine.py +337 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/__init__.py +1 -0
- windkit-2.0.1/windkit/spatial/_conversions.py +42 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_struct.py +27 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/map_conversions.py +3 -0
- windkit-2.0.1/windkit/tutorial_data.py +276 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/binned_wind_climate.py +1 -1
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_farm/wind_turbines.py +143 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit.egg-info/SOURCES.txt +1 -2
- windkit-2.0.0/PERFORMANCE_CI_PLAN.md +0 -294
- windkit-2.0.0/pyproject.toml +0 -15
- windkit-2.0.0/setup.cfg +0 -66
- windkit-2.0.0/windkit/integrations/_earth_engine.py +0 -241
- windkit-2.0.0/windkit/tutorial_data.py +0 -188
- {windkit-2.0.0 → windkit-2.0.1}/LICENSE +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/README.md +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/_errors.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/_rvea_xml.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/_weibull_nb.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/cfd.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/config.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/all_vars.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/color_table_roughness.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/CGLS-LC100.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/CORINE.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/ESA_CCI.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/GWA4_micro.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/Globcover.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/MODIS.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/NEWA_micro_v2.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/landcover_tables/WorldCover.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/loss_tables/dtu_loss_table.csv +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/map_file_header_to_epsg.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/map_file_header_to_epsg_read.json +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/data/uncertainty_tables/dtu_uncertainty_table.csv +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/import_manager.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/integrations/__init__.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/integrations/_gwa_map_api.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/integrations/_planetary_computer.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/ltc/__init__.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/ltc/_validation.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/ltc/mcp.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/ltc/regression.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/ltc/scores.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/__init__.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/_colormaps.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/_helpers.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/color.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/elevation_map.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/histogram.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/landcover_map.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/operational_curves.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/raster_plot.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/roughness_rose.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/time_series.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/vertical_profile.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/wind_rose.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/plot/wind_turbine.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/README.md +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_bbox.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_crs.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_cuboid.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_dimensions.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_interpolation.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_latitude.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_metpy_natural_neighbors.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_point.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_raster.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_utm.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_vector.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/_vertical.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/decorators.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/spatial/spatial.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/__init__.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/_vectormap_gml.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/_vectormap_helpers.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/get_map.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/landcover.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/map_conversion/__init__.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/map_conversion/_polygons_constraints.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/map_conversion/helper_functions.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/map_conversion/lines_to_poly.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/map_conversion/poly_to_lines.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/raster_map.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/topography.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/topography/vector_map.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/utils.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/weibull.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/weng_workspace.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/__init__.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/generalized_wind_climate.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/geostrophic_wind_climate.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/predicted_wind_climate.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/time_series_wind_climate.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/weibull_wind_climate.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_climate/wind_climate.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_data.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_farm/__init__.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_farm/loss.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_farm/power_curve.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_farm/uncertainty.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/wind_farm/wind_turbine_generator.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/workspace.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/xarray_structures/_validate.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/xarray_structures/data_structures.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/xarray_structures/direction.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/xarray_structures/empty.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/xarray_structures/metadata.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/xarray_structures/sector.py +0 -0
- {windkit-2.0.0 → windkit-2.0.1}/windkit/xarray_structures/wsbin.py +0 -0
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All major changes are listed here.
|
|
4
4
|
|
|
5
|
-
## 2.0.
|
|
5
|
+
## [2.0.1 (2026-01-29)](https://docs.wasp.dk/windkit/v2.0.1/)
|
|
6
6
|
|
|
7
7
|
### Highlights
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
#### Performance improvements
|
|
10
10
|
* Significantly reduced import time by lazy loading some packages and data. Should be approx 1/3 of previous import time.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
#### Documentation
|
|
13
|
+
* Restructured user guide into focused, object-based documentation pages:
|
|
14
|
+
- Wind climates section with dedicated pages for TSWC, BWC, WWC, and GWC including I/O formats and usage examples
|
|
15
|
+
- Topography section with elevation, roughness, and landcover map documentation including format support tables
|
|
16
|
+
- Spatial section explaining point, stacked_point, raster, and cuboid structures with operation examples
|
|
17
|
+
- Wind farms section documenting wind turbine datasets and WTG objects
|
|
18
|
+
- New overview section with data structures, schemas, and tutorial data documentation
|
|
19
|
+
|
|
20
|
+
#### Sheer and veer functionality
|
|
13
21
|
|
|
14
22
|
* Added new function `wk.shear_extrapolate` to extrapolate wind speeds to different heights using a power law shear profile.
|
|
15
23
|
* Added new function `wk.shear_exponent` to calculate a shear exponent from wind speeds
|
|
@@ -23,16 +31,24 @@ All major changes are listed here.
|
|
|
23
31
|
|
|
24
32
|
* new function `create_geowc`, which creates a dummy geostrophic wind climate
|
|
25
33
|
* functions `mean_wind_speed`, `mean_power_density`, `ws_freq_gt_mean`, `ws_cdf` and `mean_ws_moment` are now also working when a geostrophic wind climate is passed.
|
|
26
|
-
* bug fix to interpolation, which would create invalid spatial structures when a dimension was in exclude dims but not present in the target structure (e.g. when doing interpolation from `stacked_point` to `point`).
|
|
27
34
|
|
|
28
35
|
### New features
|
|
29
36
|
* Added new function `wk.extrapolate_to_height` to extrapolate wind climate objects to different heights. Currently, only works for time-series wind climates (TSWC).
|
|
30
|
-
* Fixed bug where a point dataset with several horizontal locations would be converted to a single horizontal location when using the function `to_stacked_point`
|
|
31
37
|
* `wk.roughness_map_to_file` now allows to write to a old fashioned `.map` file for the special case where these is a single polygon and the external roughness length is not specified (None). For this case we assume that the external roughness length is the same as the roughness length inside the polygon.
|
|
32
38
|
* `wk.roughness_map_to_file` now allows users to write to a `.map` as long all displacement heights in the map are zero.
|
|
39
|
+
* For `wv_count` objects (thus also geostrophic wind climates) if all of the bins have nan's, the result of function `mean_wind_speed`, `mean_power_density`, `ws_freq_gt_mean` and `mean_ws_moment` operating on such a function is also nan, whereas before it would be 0.
|
|
40
|
+
* Added new function `wk.load_tutorial_data` to download and load tutorial data directly into memory as windkit-compatible objects (xarray.Dataset and geopandas.GeoDataFrame).
|
|
41
|
+
* Changed `wk.get_tutorial_data` to return a `Path` to the extracted tutorial data folder, allowing users to load files manually using windkit readers or generic loaders. The function now includes detailed docstrings describing all available files for each dataset, including .nc, .omwc, .wtg, .map, and .csv.
|
|
42
|
+
* Added `wk.read_wind_turbines` and `wk.wind_turbines_to_file` functions to read and write wind turbine datasets in various formats. Both only support CSV for now. The CSV should follow the windkit wind turbine format specification.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
### Bug fixes
|
|
46
|
+
* Fixed pixel misalignment when downloading raster maps from Google Earth Engine. Downloads now use `crs_transform` instead of `scale` to preserve exact pixel alignment with source datasets (e.g., Globcover, SRTM, WorldCover). This fixes half-pixel offsets (~150m for Globcover) and ~12-15m offsets for elevation data.
|
|
33
47
|
* Bugfix in `read_bwc`: it now opens `bwc` stored in netcdf correctly.
|
|
34
48
|
but some of this functionality was only available in pywasp, so it has been moved there.
|
|
35
|
-
*
|
|
49
|
+
* Fixed bug where a point dataset with several horizontal locations would be converted to a single horizontal location when using the function `to_stacked_point`
|
|
50
|
+
* bug fix to interpolation, which would create invalid spatial structures when a dimension was in exclude dims but not present in the target structure (e.g. when doing interpolation from `stacked_point` to `point`).
|
|
51
|
+
|
|
36
52
|
|
|
37
53
|
### Changes
|
|
38
54
|
* Changed default value of `use_bounds` to `True` in `wk.spatial.BBox.reproject` method.
|
|
@@ -1,50 +1,72 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: windkit
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: WindKit provides core functionalities for working with wind resource data
|
|
5
|
-
Home-page: https://docs.wasp.dk/windkit/latest
|
|
6
5
|
Author: DTU Wind Energy
|
|
7
|
-
License: BSD-3-Clause
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
8
7
|
Classifier: Programming Language :: Python :: 3
|
|
9
8
|
Classifier: Operating System :: OS Independent
|
|
10
9
|
Requires-Python: >=3.11
|
|
11
10
|
Description-Content-Type: text/markdown
|
|
12
11
|
License-File: LICENSE
|
|
12
|
+
Requires-Dist: geopandas>=1.0
|
|
13
|
+
Requires-Dist: h5netcdf
|
|
13
14
|
Requires-Dist: lxml>=5.0
|
|
14
15
|
Requires-Dist: netcdf4>=1.6
|
|
15
16
|
Requires-Dist: numpy>=1.26
|
|
16
17
|
Requires-Dist: packaging>=23
|
|
17
18
|
Requires-Dist: pandas>=2.1
|
|
19
|
+
Requires-Dist: platformdirs>=4.3
|
|
20
|
+
Requires-Dist: pydantic>=2.7
|
|
21
|
+
Requires-Dist: pydantic-settings>=2.3
|
|
18
22
|
Requires-Dist: pyproj>=3.6
|
|
23
|
+
Requires-Dist: pyyaml
|
|
24
|
+
Requires-Dist: rasterio>=1.3
|
|
25
|
+
Requires-Dist: requests
|
|
26
|
+
Requires-Dist: rioxarray>=0.17
|
|
19
27
|
Requires-Dist: scipy>=1.12
|
|
20
|
-
Requires-Dist: shapely>=2
|
|
28
|
+
Requires-Dist: shapely>=2.0
|
|
29
|
+
Requires-Dist: toml
|
|
21
30
|
Requires-Dist: xarray>=2023.9
|
|
22
|
-
Requires-Dist: rioxarray>=0.17
|
|
23
|
-
Requires-Dist: rasterio>=1.3
|
|
24
|
-
Requires-Dist: geopandas>=1.0
|
|
25
|
-
Requires-Dist: h5netcdf>=1.3
|
|
26
|
-
Requires-Dist: h5py>=3.9
|
|
27
|
-
Requires-Dist: matplotlib>=3.8
|
|
28
|
-
Requires-Dist: pydantic-settings>=2.3
|
|
29
|
-
Requires-Dist: pydantic>=2.7
|
|
30
|
-
Requires-Dist: platformdirs>=4.3.8
|
|
31
|
-
Requires-Dist: plotly>=5
|
|
32
|
-
Requires-Dist: kaleido>=0.2.1
|
|
33
|
-
Requires-Dist: requests>=2.31
|
|
34
|
-
Requires-Dist: toml>=0.10
|
|
35
31
|
Provides-Extra: plots
|
|
36
|
-
Requires-Dist: matplotlib>=3.
|
|
37
|
-
Requires-Dist: plotly>=5.12; extra == "plots"
|
|
38
|
-
Requires-Dist: kaleido
|
|
32
|
+
Requires-Dist: matplotlib>=3.8; extra == "plots"
|
|
33
|
+
Requires-Dist: plotly>=5.12.0; extra == "plots"
|
|
34
|
+
Requires-Dist: kaleido; extra == "plots"
|
|
35
|
+
Provides-Extra: performance
|
|
36
|
+
Requires-Dist: numba>=0.57.0; extra == "performance"
|
|
39
37
|
Provides-Extra: data-apis
|
|
40
|
-
Requires-Dist: ee; extra == "data-apis"
|
|
41
|
-
Requires-Dist: pystac_client; extra == "data-apis"
|
|
42
|
-
Requires-Dist: planetary_computer; extra == "data-apis"
|
|
43
|
-
Requires-Dist: fsspec; extra == "data-apis"
|
|
44
38
|
Requires-Dist: adlfs; extra == "data-apis"
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
|
|
47
|
-
Requires-Dist:
|
|
39
|
+
Requires-Dist: earthengine-api; extra == "data-apis"
|
|
40
|
+
Requires-Dist: fsspec; extra == "data-apis"
|
|
41
|
+
Requires-Dist: planetary-computer; extra == "data-apis"
|
|
42
|
+
Requires-Dist: pystac-client; extra == "data-apis"
|
|
43
|
+
Requires-Dist: zarr>2.15; extra == "data-apis"
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: dash; extra == "dev"
|
|
46
|
+
Requires-Dist: ipython; extra == "dev"
|
|
47
|
+
Requires-Dist: nbval; extra == "dev"
|
|
48
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest; extra == "dev"
|
|
50
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
51
|
+
Requires-Dist: pytest-xdist; extra == "dev"
|
|
52
|
+
Requires-Dist: windIO; extra == "dev"
|
|
53
|
+
Provides-Extra: doc
|
|
54
|
+
Requires-Dist: docutils; extra == "doc"
|
|
55
|
+
Requires-Dist: jupyter; extra == "doc"
|
|
56
|
+
Requires-Dist: jupyter-dash; extra == "doc"
|
|
57
|
+
Requires-Dist: jupyter-sphinx; extra == "doc"
|
|
58
|
+
Requires-Dist: myst-parser; extra == "doc"
|
|
59
|
+
Requires-Dist: nbsphinx; extra == "doc"
|
|
60
|
+
Requires-Dist: nbsphinx-link; extra == "doc"
|
|
61
|
+
Requires-Dist: pydata-sphinx-theme; extra == "doc"
|
|
62
|
+
Requires-Dist: recommonmark; extra == "doc"
|
|
63
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
64
|
+
Requires-Dist: sphinx-argparse; extra == "doc"
|
|
65
|
+
Requires-Dist: sphinx-copybutton; extra == "doc"
|
|
66
|
+
Requires-Dist: sphinx-design; extra == "doc"
|
|
67
|
+
Requires-Dist: sphinx-gallery; extra == "doc"
|
|
68
|
+
Requires-Dist: sphinxcontrib-bibtex; extra == "doc"
|
|
69
|
+
Requires-Dist: sphinxext-opengraph; extra == "doc"
|
|
48
70
|
Dynamic: license-file
|
|
49
71
|
|
|
50
72
|
# WindKit
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "windkit"
|
|
7
|
+
description = "WindKit provides core functionalities for working with wind resource data"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = "BSD-3-Clause"
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "DTU Wind Energy"}
|
|
12
|
+
]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
]
|
|
17
|
+
dynamic = ["version"]
|
|
18
|
+
requires-python = ">=3.11"
|
|
19
|
+
dependencies = [
|
|
20
|
+
"geopandas>=1.0",
|
|
21
|
+
"h5netcdf",
|
|
22
|
+
"lxml>=5.0",
|
|
23
|
+
"netcdf4>=1.6",
|
|
24
|
+
"numpy>=1.26",
|
|
25
|
+
"packaging>=23",
|
|
26
|
+
"pandas>=2.1",
|
|
27
|
+
"platformdirs>=4.3",
|
|
28
|
+
"pydantic>=2.7",
|
|
29
|
+
"pydantic-settings>=2.3",
|
|
30
|
+
"pyproj>=3.6",
|
|
31
|
+
"pyyaml",
|
|
32
|
+
"rasterio>=1.3",
|
|
33
|
+
"requests",
|
|
34
|
+
"rioxarray>=0.17",
|
|
35
|
+
"scipy>=1.12",
|
|
36
|
+
"shapely>=2.0",
|
|
37
|
+
"toml",
|
|
38
|
+
"xarray>=2023.9",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
plots = [
|
|
43
|
+
"matplotlib>=3.8",
|
|
44
|
+
"plotly>=5.12.0",
|
|
45
|
+
"kaleido",
|
|
46
|
+
]
|
|
47
|
+
performance = [
|
|
48
|
+
"numba>=0.57.0",
|
|
49
|
+
]
|
|
50
|
+
data_apis = [
|
|
51
|
+
"adlfs",
|
|
52
|
+
"earthengine-api",
|
|
53
|
+
"fsspec",
|
|
54
|
+
"planetary-computer",
|
|
55
|
+
"pystac-client",
|
|
56
|
+
"zarr>2.15",
|
|
57
|
+
]
|
|
58
|
+
dev = [
|
|
59
|
+
"dash",
|
|
60
|
+
"ipython",
|
|
61
|
+
"nbval",
|
|
62
|
+
"pre-commit",
|
|
63
|
+
"pytest",
|
|
64
|
+
"pytest-cov",
|
|
65
|
+
"pytest-xdist",
|
|
66
|
+
"windIO",
|
|
67
|
+
]
|
|
68
|
+
doc = [
|
|
69
|
+
"docutils",
|
|
70
|
+
"jupyter",
|
|
71
|
+
"jupyter-dash",
|
|
72
|
+
"jupyter-sphinx",
|
|
73
|
+
"myst-parser",
|
|
74
|
+
"nbsphinx",
|
|
75
|
+
"nbsphinx-link",
|
|
76
|
+
"pydata-sphinx-theme",
|
|
77
|
+
"recommonmark",
|
|
78
|
+
"sphinx",
|
|
79
|
+
"sphinx-argparse",
|
|
80
|
+
"sphinx-copybutton",
|
|
81
|
+
"sphinx-design",
|
|
82
|
+
"sphinx-gallery",
|
|
83
|
+
"sphinxcontrib-bibtex",
|
|
84
|
+
"sphinxext-opengraph",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[project.scripts]
|
|
88
|
+
split_combomap = "windkit.topography.vector_map:_split_combo"
|
|
89
|
+
|
|
90
|
+
[tool.setuptools_scm]
|
|
91
|
+
write_to = "windkit/_version.py"
|
|
92
|
+
|
|
93
|
+
[tool.setuptools]
|
|
94
|
+
include-package-data = true
|
|
95
|
+
|
|
96
|
+
[tool.setuptools.packages.find]
|
|
97
|
+
namespaces = true
|
|
98
|
+
|
|
99
|
+
[tool.setuptools.package-data]
|
|
100
|
+
"windkit.data" = ["*.json"]
|
|
101
|
+
"windkit.data.landcover_tables" = ["*.json"]
|
|
102
|
+
"windkit.data.plot" = ["*.json"]
|
|
103
|
+
"windkit.data.loss_tables" = ["*.csv"]
|
|
104
|
+
"windkit.data.uncertainty_tables" = ["*.csv"]
|
|
105
|
+
|
|
106
|
+
[tool.pytest.ini_options]
|
|
107
|
+
minversion = "6.0"
|
|
108
|
+
norecursedirs = "dist build .tox"
|
|
109
|
+
testpaths = ["test",]
|
|
110
|
+
markers = [
|
|
111
|
+
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
112
|
+
"performance: marks tests as performance tests (run with '-m performance')",
|
|
113
|
+
]
|
windkit-2.0.1/setup.cfg
ADDED
|
@@ -105,6 +105,8 @@ __all__ = [
|
|
|
105
105
|
"create_wind_turbines_from_dataframe",
|
|
106
106
|
"create_wind_turbines_from_arrays",
|
|
107
107
|
"wind_turbines_to_geodataframe",
|
|
108
|
+
"read_wind_turbines",
|
|
109
|
+
"wind_turbines_to_file",
|
|
108
110
|
# workspace
|
|
109
111
|
"Workspace",
|
|
110
112
|
# weng_workspace
|
|
@@ -142,6 +144,7 @@ __all__ = [
|
|
|
142
144
|
"total_uncertainty_factor",
|
|
143
145
|
# tutorial_data
|
|
144
146
|
"get_tutorial_data",
|
|
147
|
+
"load_tutorial_data",
|
|
145
148
|
]
|
|
146
149
|
|
|
147
150
|
from windkit._version import version as __version__
|
|
@@ -238,6 +241,8 @@ from windkit.wind_farm.wind_turbines import (
|
|
|
238
241
|
create_wind_turbines_from_dataframe,
|
|
239
242
|
create_wind_turbines_from_arrays,
|
|
240
243
|
wind_turbines_to_geodataframe,
|
|
244
|
+
read_wind_turbines,
|
|
245
|
+
wind_turbines_to_file,
|
|
241
246
|
)
|
|
242
247
|
from windkit.workspace import Workspace
|
|
243
248
|
from windkit.weng_workspace import WengWorkspace
|
|
@@ -301,4 +306,4 @@ from windkit.xarray_structures.direction import (
|
|
|
301
306
|
from windkit.xarray_structures.wsbin import (
|
|
302
307
|
create_wsbin_coords,
|
|
303
308
|
)
|
|
304
|
-
from windkit.tutorial_data import get_tutorial_data
|
|
309
|
+
from windkit.tutorial_data import get_tutorial_data, load_tutorial_data
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '2.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 0,
|
|
31
|
+
__version__ = version = '2.0.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 0, 1)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# (c) 2022 DTU Wind Energy
|
|
2
|
+
"""
|
|
3
|
+
Module that downloads elevation and roughness maps
|
|
4
|
+
|
|
5
|
+
Currently driven by the google earth engine, which is a cloud interface service to access
|
|
6
|
+
landcover and elevation data, among other things.
|
|
7
|
+
|
|
8
|
+
Installation & Setup
|
|
9
|
+
--------------------
|
|
10
|
+
|
|
11
|
+
The earth engine is an optional install, you can install with conda::
|
|
12
|
+
|
|
13
|
+
conda install earthengine-api google-cloud-sdk
|
|
14
|
+
|
|
15
|
+
After installation you will have to do a one-time authentication
|
|
16
|
+
step from the command line: ``earthengine authenticate``
|
|
17
|
+
|
|
18
|
+
This will open a browser where you will have to allow google to use
|
|
19
|
+
you google account to retrieve data from the google servers. If you are on a machine
|
|
20
|
+
without the ability to use a browser (such as an HPC
|
|
21
|
+
cluster), you will have to use ``earthengine authenticate --quiet``, which requires you to
|
|
22
|
+
to manually copy the authentication code into the terminal.
|
|
23
|
+
|
|
24
|
+
In addition, you will have to `sign up
|
|
25
|
+
<https://signup.earthengine.google.com/#!/>`_ for the google earth engine and give
|
|
26
|
+
a reason why you want to use the program. Please pay particular attention to
|
|
27
|
+
their terms of service.
|
|
28
|
+
|
|
29
|
+
Automated Datasets
|
|
30
|
+
------------------
|
|
31
|
+
|
|
32
|
+
Currently, the databases that have been added are the Copernicus Global Land Cover
|
|
33
|
+
(CGLS-LC100), Copernicus CORINE land Cover (CORINE), MODIS Global Land Cover MCD12Q1
|
|
34
|
+
(MODIS), Globcover and WorldCover
|
|
35
|
+
(https://developers.google.com/earth-engine/datasets/catalog/ESA_WorldCover_v100) as landcover databases and
|
|
36
|
+
NASA SRTM Digital Elevation 30m(SRTM), ALOS DSM: Global 30 (ALOS) and NASADEM
|
|
37
|
+
(https://developers.google.com/earth-engine/datasets/catalog/NASA_NASADEM_HGT_001?hl=en) as elevation databases.
|
|
38
|
+
|
|
39
|
+
The landcover databases have standard conversion tables that are included in
|
|
40
|
+
``windkit/data/landcover_tables``.
|
|
41
|
+
|
|
42
|
+
Google Earth Engine provides lists of
|
|
43
|
+
`elevation
|
|
44
|
+
<https://developers.google.com/earth-engine/datasets/tags/elevation>`_ and
|
|
45
|
+
`land cover
|
|
46
|
+
<https://developers.google.com/earth-engine/datasets/tags/landcover>`_
|
|
47
|
+
data sources, which provide additional details about the various datasources used
|
|
48
|
+
in this library.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
import logging
|
|
52
|
+
import math
|
|
53
|
+
import tempfile
|
|
54
|
+
import urllib.request
|
|
55
|
+
import warnings
|
|
56
|
+
from pathlib import Path
|
|
57
|
+
|
|
58
|
+
import rioxarray
|
|
59
|
+
|
|
60
|
+
from ..spatial import BBox, clip
|
|
61
|
+
|
|
62
|
+
CRS_GEOGRAPHIC = "EPSG:4326"
|
|
63
|
+
|
|
64
|
+
# Dataset configuration: maps datasource name to (url, band, is_collection)
|
|
65
|
+
_DATASET_CONFIG = {
|
|
66
|
+
"CGLS-LC100": (
|
|
67
|
+
"COPERNICUS/Landcover/100m/Proba-V/Global/2015",
|
|
68
|
+
"discrete_classification",
|
|
69
|
+
False,
|
|
70
|
+
),
|
|
71
|
+
"CORINE": ("COPERNICUS/CORINE/V20/100m/2018", "landcover", False),
|
|
72
|
+
"MODIS": ("MODIS/006/MCD12Q1/2018_01_01", "LC_Type1", False),
|
|
73
|
+
"SRTM": ("USGS/SRTMGL1_003", "elevation", False),
|
|
74
|
+
"NASADEM": ("NASA/NASADEM_HGT/001", "elevation", False),
|
|
75
|
+
"ALOS": ("JAXA/ALOS/AW3D30/V2_2", "AVE_DSM", False),
|
|
76
|
+
"Globcover": ("ESA/GLOBCOVER_L4_200901_200912_V2_3", "landcover", False),
|
|
77
|
+
"WorldCover": ("ESA/WorldCover/v100", "Map", True),
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
ELEVATION_DATASETS = {"SRTM", "ALOS", "NASADEM"}
|
|
81
|
+
LIST_DATA_SOURCES = list(_DATASET_CONFIG.keys())
|
|
82
|
+
|
|
83
|
+
logger = logging.getLogger(__name__)
|
|
84
|
+
|
|
85
|
+
# Initialize Google Earth Engine
|
|
86
|
+
try:
|
|
87
|
+
import ee as earth_engine
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
credentials_path = Path.home() / "earth_engine.json"
|
|
91
|
+
if credentials_path.exists():
|
|
92
|
+
service_account = "windkit@windkit.iam.gserviceaccount.com"
|
|
93
|
+
credentials = earth_engine.ServiceAccountCredentials(
|
|
94
|
+
service_account, str(credentials_path)
|
|
95
|
+
)
|
|
96
|
+
earth_engine.Initialize(credentials)
|
|
97
|
+
else:
|
|
98
|
+
earth_engine.Initialize()
|
|
99
|
+
except Exception:
|
|
100
|
+
warnings.warn(
|
|
101
|
+
"Could not initialize Google Earth Engine. Run 'earth_engine.Authenticate()' and try again."
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
except ImportError:
|
|
105
|
+
earth_engine = None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _bbox_to_ee_geometry(bbox):
|
|
109
|
+
return earth_engine.Geometry(bbox.__geo_interface__, bbox.crs.to_string())
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _get_image(datasource):
|
|
113
|
+
"""Get image from Google Earth Engine for the specified datasource.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
datasource : str
|
|
118
|
+
One of: 'CGLS-LC100', 'CORINE', 'MODIS', 'Globcover', 'WorldCover',
|
|
119
|
+
'SRTM', 'ALOS', 'NASADEM'
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
image : ee.Image
|
|
124
|
+
Google Earth Engine image for the specified band
|
|
125
|
+
"""
|
|
126
|
+
if earth_engine is None:
|
|
127
|
+
raise ValueError(
|
|
128
|
+
"ee (earthengine-api) is required to get maps from Google Earth Engine"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if datasource not in _DATASET_CONFIG:
|
|
132
|
+
valid_sources = ", ".join(LIST_DATA_SOURCES)
|
|
133
|
+
raise ValueError(f"Please specify a valid data source from {valid_sources}")
|
|
134
|
+
|
|
135
|
+
url, band, is_collection = _DATASET_CONFIG[datasource]
|
|
136
|
+
|
|
137
|
+
if is_collection:
|
|
138
|
+
dataset = earth_engine.ImageCollection(url).first()
|
|
139
|
+
else:
|
|
140
|
+
dataset = earth_engine.Image(url)
|
|
141
|
+
|
|
142
|
+
return dataset.select(band)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _get_ee_map(lat, lon, buffer_dist=20000, source="SRTM", vector=False):
|
|
146
|
+
"""Extract map from a given lat, lon
|
|
147
|
+
|
|
148
|
+
Extract the smallest square which fits a cirle with radius buffer_dist
|
|
149
|
+
around the coordinates lat,lon.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
lat : float
|
|
154
|
+
Center latitude from which we extract a map
|
|
155
|
+
lon : float
|
|
156
|
+
Center longitude from which we extract a map
|
|
157
|
+
buffer_dist : int, optional
|
|
158
|
+
Distance in meters from the given (lat,lon) where a map is extracted, by default 20000
|
|
159
|
+
source : str {"CGLS-LC100", "CORINE", "MODIS", "Globcover", "WorldCover", "SRTM", "ALOS", "NASADEM"}, optional
|
|
160
|
+
Landcover or elevation datasource, by default "SRTM"
|
|
161
|
+
vector:
|
|
162
|
+
If true, return the map in vector format else return a raster map
|
|
163
|
+
"""
|
|
164
|
+
if vector:
|
|
165
|
+
raise NotImplementedError("This feature is not yet available.")
|
|
166
|
+
|
|
167
|
+
bbox = BBox.utm_bbox_from_geographic_coordinate(lon, lat, buffer_dist)
|
|
168
|
+
ras = _get_raster_map_from_earth_engine(bbox, dataset=source)
|
|
169
|
+
return ras
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _compute_aligned_origin(bbox_min, bbox_max, scale, origin):
|
|
173
|
+
"""Compute a new origin aligned to the native grid but near the bbox.
|
|
174
|
+
|
|
175
|
+
This prevents Earth Engine from computing pixels from a distant origin
|
|
176
|
+
(e.g., -180 degrees) to the bbox by finding the nearest grid-aligned
|
|
177
|
+
point just outside the bbox.
|
|
178
|
+
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
bbox_min : float
|
|
182
|
+
Minimum bound of bbox in this dimension (west or south)
|
|
183
|
+
bbox_max : float
|
|
184
|
+
Maximum bound of bbox in this dimension (east or north)
|
|
185
|
+
scale : float
|
|
186
|
+
Pixel scale (positive or negative)
|
|
187
|
+
origin : float
|
|
188
|
+
Native grid origin
|
|
189
|
+
|
|
190
|
+
Returns
|
|
191
|
+
-------
|
|
192
|
+
float
|
|
193
|
+
New origin aligned to native grid, positioned just outside the bbox
|
|
194
|
+
"""
|
|
195
|
+
# Choose reference bound based on scale direction
|
|
196
|
+
# Positive scale: origin at min side, negative scale: origin at max side
|
|
197
|
+
reference_bound = bbox_min if scale > 0 else bbox_max
|
|
198
|
+
n_pixels = math.floor((reference_bound - origin) / scale)
|
|
199
|
+
return origin + n_pixels * scale
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _create_aligned_transform(native_transform, bbox):
|
|
203
|
+
"""Create an adjusted transform aligned to the native grid near the bbox.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
native_transform : list
|
|
208
|
+
Earth Engine transform: [xScale, xShear, xOrigin, yShear, yScale, yOrigin]
|
|
209
|
+
bbox : BBox
|
|
210
|
+
Bounding box for the download
|
|
211
|
+
|
|
212
|
+
Returns
|
|
213
|
+
-------
|
|
214
|
+
list or None
|
|
215
|
+
Adjusted transform, or None if transform cannot be computed
|
|
216
|
+
"""
|
|
217
|
+
x_scale, x_shear, x_origin, y_shear, y_scale, y_origin = native_transform
|
|
218
|
+
|
|
219
|
+
if x_scale == 0 or y_scale == 0:
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
west, south, east, north = bbox.bounds()
|
|
223
|
+
|
|
224
|
+
new_x_origin = _compute_aligned_origin(west, east, x_scale, x_origin)
|
|
225
|
+
new_y_origin = _compute_aligned_origin(south, north, y_scale, y_origin)
|
|
226
|
+
|
|
227
|
+
return [x_scale, x_shear, new_x_origin, y_shear, y_scale, new_y_origin]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _get_download_url(ee_image, download_params, dataset):
|
|
231
|
+
"""Get download URL, falling back to scale if crs_transform fails.
|
|
232
|
+
|
|
233
|
+
Some datasets (e.g., NASADEM) may not respect the adjusted transform origin
|
|
234
|
+
and fail with grid dimension errors.
|
|
235
|
+
|
|
236
|
+
Parameters
|
|
237
|
+
----------
|
|
238
|
+
ee_image : ee.Image
|
|
239
|
+
Earth Engine image
|
|
240
|
+
download_params : dict
|
|
241
|
+
Download parameters (may be modified in place)
|
|
242
|
+
dataset : str
|
|
243
|
+
Dataset name for logging
|
|
244
|
+
|
|
245
|
+
Returns
|
|
246
|
+
-------
|
|
247
|
+
str
|
|
248
|
+
Download URL
|
|
249
|
+
"""
|
|
250
|
+
try:
|
|
251
|
+
return ee_image.getDownloadURL(download_params)
|
|
252
|
+
except Exception as e:
|
|
253
|
+
if "crs_transform" in download_params and "grid dimensions" in str(e).lower():
|
|
254
|
+
logger.debug(
|
|
255
|
+
f"crs_transform failed for {dataset}, falling back to scale: {e}"
|
|
256
|
+
)
|
|
257
|
+
del download_params["crs_transform"]
|
|
258
|
+
download_params["scale"] = ee_image.projection().nominalScale().getInfo()
|
|
259
|
+
return ee_image.getDownloadURL(download_params)
|
|
260
|
+
raise
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _get_raster_map_from_earth_engine(bbox, dataset="NASADEM", band=None):
|
|
264
|
+
"""
|
|
265
|
+
Get map from Google Earth Engine.
|
|
266
|
+
|
|
267
|
+
Parameters
|
|
268
|
+
----------
|
|
269
|
+
bbox : windkit.spatial.BBox
|
|
270
|
+
Bounding box of the map to download.
|
|
271
|
+
|
|
272
|
+
dataset : str, optional
|
|
273
|
+
Dataset to retrieve, by default "NASADEM"
|
|
274
|
+
|
|
275
|
+
band : str, optional
|
|
276
|
+
Band to retrieve, by default None
|
|
277
|
+
|
|
278
|
+
Returns
|
|
279
|
+
-------
|
|
280
|
+
da : xarray.DataArray
|
|
281
|
+
DataArray with the map
|
|
282
|
+
|
|
283
|
+
Notes
|
|
284
|
+
-----
|
|
285
|
+
When the requested CRS matches the dataset's native CRS, the download uses
|
|
286
|
+
`crs_transform` to preserve exact pixel alignment with the source data.
|
|
287
|
+
When the CRS differs, `scale` is used which may result in slight pixel
|
|
288
|
+
misalignment (typically sub-pixel shifts).
|
|
289
|
+
"""
|
|
290
|
+
if earth_engine is None:
|
|
291
|
+
raise ValueError(
|
|
292
|
+
"ee (earthengine-api) is required to get maps from Google Earth Engine"
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
if not isinstance(bbox, BBox):
|
|
296
|
+
raise ValueError("bbox must be a BBox object or a windkit.spatial.BBox object.")
|
|
297
|
+
|
|
298
|
+
ee_image = _get_image(dataset)
|
|
299
|
+
projection_info = ee_image.projection().getInfo()
|
|
300
|
+
native_crs = projection_info.get("crs")
|
|
301
|
+
native_transform = projection_info.get("transform")
|
|
302
|
+
requested_crs = f"EPSG:{bbox.crs.to_epsg()}"
|
|
303
|
+
|
|
304
|
+
download_params = {
|
|
305
|
+
"region": _bbox_to_ee_geometry(bbox.reproject(CRS_GEOGRAPHIC)),
|
|
306
|
+
"format": "GEO_TIFF",
|
|
307
|
+
"crs": requested_crs,
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Use crs_transform for precise alignment when CRS matches
|
|
311
|
+
crs_matches = native_crs == requested_crs and native_transform is not None
|
|
312
|
+
adjusted_transform = (
|
|
313
|
+
_create_aligned_transform(native_transform, bbox) if crs_matches else None
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
if adjusted_transform is not None:
|
|
317
|
+
download_params["crs_transform"] = adjusted_transform
|
|
318
|
+
else:
|
|
319
|
+
download_params["scale"] = ee_image.projection().nominalScale().getInfo()
|
|
320
|
+
|
|
321
|
+
download_url = _get_download_url(ee_image, download_params, dataset)
|
|
322
|
+
|
|
323
|
+
tmpfile = tempfile.NamedTemporaryFile(delete=False)
|
|
324
|
+
try:
|
|
325
|
+
logger.debug(f"Downloading file {tmpfile.name}")
|
|
326
|
+
urllib.request.urlretrieve(download_url, tmpfile.name)
|
|
327
|
+
|
|
328
|
+
da = rioxarray.open_rasterio(tmpfile.name)
|
|
329
|
+
da = da.rename({"spatial_ref": "crs", "x": "west_east", "y": "south_north"})
|
|
330
|
+
da = da.drop_vars("band", errors="i")
|
|
331
|
+
da.name = "elevation" if dataset in ELEVATION_DATASETS else "landcover"
|
|
332
|
+
da = clip(da, bbox)
|
|
333
|
+
da = da.sortby(["south_north", "west_east"])
|
|
334
|
+
return da
|
|
335
|
+
finally:
|
|
336
|
+
tmpfile.close()
|
|
337
|
+
Path(tmpfile.name).unlink()
|