Skip to content

Commit

Permalink
ensure WKT string is set; warn if BBOX not given
Browse files Browse the repository at this point in the history
  • Loading branch information
observingClouds committed Jan 9, 2025
1 parent 7e5c79c commit ec75257
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 15 deletions.
15 changes: 0 additions & 15 deletions example.danra.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,6 @@ inputs:
dims: [x, y]
attributes:
crs_wkt: 'PROJCRS["DMI HARMONIE DANRA lambert projection", BASEGEOGCRS["DMI HARMONIE DANRA lambert CRS", DATUM["DMI HARMONIE DANRA lambert datum", ELLIPSOID["Sphere", 6367470, 0, LENGTHUNIT["metre", 1, ID["EPSG", 9001]]]], PRIMEM["Greenwich", 0, ANGLEUNIT["degree", 0.0174532925199433, ID["EPSG", 8901]]], ID["EPSG",4035]], CONVERSION["Lambert Conic Conformal (2SP)", METHOD["Lambert Conic Conformal (2SP)", ID["EPSG", 9802]], PARAMETER["Latitude of false origin", 56.7, ANGLEUNIT["degree", 0.0174532925199433, ID["EPSG", 8821]]], PARAMETER["Longitude of false origin", 25, ANGLEUNIT["degree", 0.0174532925199433, ID["EPSG", 8822]]], PARAMETER["Latitude of 1st standard parallel", 56.7, ANGLEUNIT["degree", 0.0174532925199433, ID["EPSG", 8823]]], PARAMETER["Latitude of 2nd standard parallel", 56.7, ANGLEUNIT["degree", 0.0174532925199433, ID["EPSG", 8824]]], PARAMETER["Easting at false origin", 0, LENGTHUNIT["metre", 1, ID["EPSG", 8826]]], PARAMETER["Northing at false origin", 0, LENGTHUNIT["metre", 1, ID["EPSG", 8827]]]], CS[Cartesian, 2], AXIS["(E)", east, ORDER[1], LENGTHUNIT["metre", 1, ID["EPSG", 9001]]], AXIS["(N)", north, ORDER[2], LENGTHUNIT["metre", 1, ID["EPSG", 9001]]], USAGE[AREA["Denmark and surrounding regions"], BBOX[47, -3, 65, 25], SCOPE["Danra reanalysis projection"]]]'
semi_major_axis: 6367470.0
semi_minor_axis: 6367470.0
inverse_flattening: 0.0
reference_ellipsoid_name: 'Sphere'
longitude_of_prime_meridian: 0.0
prime_meridian_name: 'Greenwich'
geographic_crs_name: 'DMI HARMONIE DANRA lambert CRS'
horizontal_datum_name: 'DMI HARMONIE DANRA lambert datum'
projected_crs_name: 'DMI HARMONIE DANRA lambert projection'
grid_mapping_name: 'lambert_conformal_conic'
standard_parallel: [0.0567, 0.0567]
latitude_of_projection_origin: 0.0567
longitude_of_central_meridian: 0.025
false_easting: 0.0
false_northing: 0.0
dim_mapping:
time:
method: rename
Expand Down
8 changes: 8 additions & 0 deletions mllam_data_prep/create_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
from .ops.loading import load_and_subset_dataset
from .ops.mapping import map_dims_and_variables
from .ops.projection import (
ProjectionCompatibilityWarning,
ProjectionInconsistencyWarning,
check_projection_compatibility,
get_projection_crs,
validate_projection_consistency,
)
Expand Down Expand Up @@ -225,6 +227,12 @@ def create_dataset(config: Config):
except ProjectionInconsistencyWarning as e:
logger.warning(f"Projection information might be ambiguous: {e}")
projection = pyproj.CRS.from_cf(projections[0])
try:
check_projection_compatibility(projection)
except ProjectionCompatibilityWarning:
logger.warning(
"WKT string should include a BBOX definition to be compatible with e.g. cartopy."
)

# TODO: generalize the retrieval of x and y coords
# coords = (dataarrays_by_target[target_output_var][0]['x'], dataarrays_by_target[target_output_var][0]['y'])
Expand Down
71 changes: 71 additions & 0 deletions mllam_data_prep/ops/projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ class ProjectionInconsistencyWarning(Warning):
pass


class ProjectionCompatibilityWarning(Warning):
pass


def _extract_grid_mapping_names(grid_mapping_attr: str) -> List[str]:
"""Extract grid mapping names from the grid_mapping attribute.
Expand Down Expand Up @@ -71,6 +75,73 @@ def _get_projection_mappings(dataset: xr.Dataset) -> Dict[str, Any]:
return projections


def check_projection_compatibility(proj: Dict[str, Union[str, dict]]) -> None:
"""Check if the projection is compatible with mllam software.
Checks:
- if information is given as WKT string
- if the WKT string includes a BBOX definition
Parameters
----------
proj : Dict[str, Union[str, dict]]
Projection information as a dictionary with the projection
variable names as keys and the projection attributes as values
Examples
--------
>>> proj1 = {"crs_wkt": "EPSG:4326"}
>>> check_projection_compatibility(proj1)
>>> crs_wkt = (
... 'GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",'
... 'MEMBER["World Geodetic System 1984 (Transit)"],'
... 'MEMBER["World Geodetic System 1984 (G730)"],'
... 'MEMBER["World Geodetic System 1984 (G873)"],'
... 'MEMBER["World Geodetic System 1984 (G1150)"],'
... 'MEMBER["World Geodetic System 1984 (G1674)"],'
... 'MEMBER["World Geodetic System 1984 (G1762)"],'
... 'MEMBER["World Geodetic System 1984 (G2139)"],'
... 'MEMBER["World Geodetic System 1984 (G2296)"],'
... 'ELLIPSOID["WGS 84",6378137,298.257223563,'
... 'LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],'
... 'PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],'
... 'CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,'
... 'ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],'
... 'AXIS["geodetic longitude (Lon)",east,ORDER[2],'
... 'ANGLEUNIT["degree",0.0174532925199433]],'
... 'USAGE[SCOPE["Horizontal component of 3D system."],'
... 'AREA["World."],],ID["EPSG",4326]]'
... )
>>> proj2 = {"crs_wkt": crs_wkt}
>>> check_projection_compatibility(proj2)
Traceback (most recent call last):
...
mllam_data_prep.ops.projection.ProjectionCompatibilityWarning: WKT string should include a BBOX definition to be compatible with e.g. cartopy.
>>> proj3 = {
... "semi_major_axis": 6367470.0,
... "semi_minor_axis": 6367470.0,
... "reference_ellipsoid_name": "Sphere",
... "grid_mapping_name": "lambert_conformal_conic",
... "standard_parallel": [0.0567, 0.0567],
... "latitude_of_projection_origin": 0.0567,
... "longitude_of_central_meridian": 0.025,
... }
>>> check_projection_compatibility(proj3)
Traceback (most recent call last):
...
KeyError: 'Projection information must contain a WKT string.'
"""
if "crs_wkt" not in proj:
raise KeyError("Projection information must contain a WKT string.")

if "BBOX" not in pyproj.CRS.from_cf(proj).to_wkt():
raise ProjectionCompatibilityWarning(
"WKT string should include a BBOX definition to be compatible with e.g. cartopy."
)

return


def validate_projection_consistency(
projections: List[Dict[str, Union[str, dict]]]
) -> None:
Expand Down

0 comments on commit ec75257

Please sign in to comment.