Skip to content

Commit

Permalink
WIP properly read coords and determine type
Browse files Browse the repository at this point in the history
  • Loading branch information
thorbjoernl committed Sep 5, 2024
1 parent cdef4c1 commit 3cc7d6e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 13 deletions.
55 changes: 50 additions & 5 deletions src/pyaro/timeseries/Filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import numpy as np
import xarray as xr
import cfunits

from .Data import Data, Flag
from .Station import Station
Expand Down Expand Up @@ -868,11 +869,13 @@ class RelativeAltitudeFilter(StationFilter):
https://github.com/metno/pyaro/issues/39
"""
UNITS_METER = cfunits.Units("m")

def __init__(self, topo_file: str | None = None, topo_var: str = "topography", rdiff: float = 1):
"""
:param topo_file : A .nc file from which to read gridded topography data.
:param topo_var : Name of variable that stores altitude.
:param rtol : Relative toleranse.
:param rdiff : Relative difference (in meters).
Note:
-----
Expand All @@ -885,15 +888,57 @@ def __init__(self, topo_file: str | None = None, topo_var: str = "topography", r
self._topography = None
if topo_file is not None:
self._topography = xr.open_dataset(topo_file)
self._convert_altitude_to_meters()
self._find_lat_lon_variables()
else:
logger.warning("No topography data provided (topo_file='%s'). Relative elevation filtering will not be applied.", topo_file)

def _convert_altitude_to_meters(self):
"""
Method which attempts to convert the altitude variable in the gridded topography data
to meters.
:raises TypeError
If conversion isn't possible.
"""
# Convert altitude to meters
units = cfunits.Units(self._topography[self._topo_var].units)
if units.equivalent(self.UNITS_METER):
self._topography[self._topo_var].values = self.UNITS_METER.conform(self._topography[self._topo_var].values, units, self.UNITS_METER)
self._topography[self._topo_var]["units"] = self.UNITS_METER
else:
raise TypeError(f"Expected altitude units to be convertible to 'm', got '{units}'")

def _find_lat_lon_variables(self):
"""
Determines the names of variables which represent the time, latitude and longitude
dimensions in the topography data.
These are assigned to self._lat, self._lon, respectively for later use.
"""
for var_name in self._topography.coords:
units = cfunits.Units(self._topography[var_name].attrs.get("units", None))
if units.istime:
self._time = var_name
continue
if units.islatitude:
self._lat = var_name
continue
if units.islongitude:
self._lon = var_name
continue

self._time = "time"
# TODO: Time does not have a unit. Decide what to do about it.
if any(x is None for x in [self._time, self._lat, self._lon]):
raise ValueError(f"Required variable names for lat, lon dimensions could not be found in file '{self._topo_file}")

def _model_altitude_from_lat_lon(self, lat: float, lon: float) -> float:
# TODO: Include a tolerance?
data = self._topography.sel({"lat": lat, "lon": lon}, method="nearest")
data = self._topography.sel({self._lat: lat, self._lon: lon}, method="nearest")

# Should not vary in time too much so picking the first one here.
altitude = data["topography"][0]
altitude = data[self._topo_var][0]

return float(altitude)

Expand All @@ -913,9 +958,9 @@ def _is_close(self, altmod: float, altobs: float) -> bool:

def init_kwargs(self):
return {
"topo_file": self._file,
"topo_file": self._topo_file,
"topo_var": self._topo_var,
"rtol": self._rdiff
"rdiff": self._rdiff
}

def name(self):
Expand Down
16 changes: 8 additions & 8 deletions tests/test_CSVTimeSeriesReader.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ def test_relaltitude_filter_1(self):
engines = pyaro.list_timeseries_engines()
with engines["csv_timeseries"].open(
filename=self.elevation_file,
filters=[pyaro.timeseries.filters.get("relaltitude", topo_file = "./tests/testdata/datadir_elevation/topography.nc", rtol=0)],
filters=[pyaro.timeseries.filters.get("relaltitude", topo_file = "/lustre/storeB/project/fou/kl/emep/Auxiliary/topography.nc", rdiff=0)],
columns={
"variable": 0,
"station": 1,
Expand All @@ -506,19 +506,19 @@ def test_relaltitude_filter_1(self):
"flag": "0",
}
) as ts:
# Altitudes in dataset:
# Station | Alt_obs | Modeobs |
# Station 1 | 100 | 12.2554 |
# Station 2 | 200 | 4.9016 |
# Station 3 | 300 | 4.9016 |
# Altitudes in test dataset:
# Station | Alt_obs | Modeobs | rdiff |
# Station 1 | 100 | 12.2554 | 87.7446 |
# Station 2 | 200 | 4.9016 | 195.0984 |
# Station 3 | 300 | 4.9016 | 195.0984 |
# Since rtol = 0, no station should be included.
self.assertEqual(len(ts.stations()), 0)

def test_relaltitude_filter_2(self):
engines = pyaro.list_timeseries_engines()
with engines["csv_timeseries"].open(
filename=self.elevation_file,
filters=[pyaro.timeseries.filters.get("relaltitude", topo_file = "./tests/testdata/datadir_elevation/topography.nc", rtol=0.89)],
filters=[pyaro.timeseries.filters.get("relaltitude", topo_file = "./tests/testdata/datadir_elevation/topography.nc", rdiff=90)],
columns={
"variable": 0,
"station": 1,
Expand All @@ -541,7 +541,7 @@ def test_relaltitude_filter_3(self):
engines = pyaro.list_timeseries_engines()
with engines["csv_timeseries"].open(
filename=self.elevation_file,
filters=[pyaro.timeseries.filters.get("relaltitude", topo_file = "./tests/testdata/datadir_elevation/topography.nc", rtol=1)],
filters=[pyaro.timeseries.filters.get("relaltitude", topo_file = "./tests/testdata/datadir_elevation/topography.nc", rdiff=300)],
columns={
"variable": 0,
"station": 1,
Expand Down

0 comments on commit 3cc7d6e

Please sign in to comment.