Skip to content

Commit

Permalink
Add ROMs Dataset Extension (#38)
Browse files Browse the repository at this point in the history
* Add ROMS rotation to global reference frame as an extension

* Update indexing to handle time and depth

* Update to work with surface velocities

* Fix performance using xarray native primitives to avoid open_dataset calls

* Update doc string
  • Loading branch information
mpiannucci authored Jun 11, 2024
1 parent 8d046bb commit 664b3ed
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 98 deletions.
24 changes: 16 additions & 8 deletions datasets/datasets.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
},
"ciofs": {
Expand All @@ -24,7 +25,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
},
"creofs": {
Expand Down Expand Up @@ -52,7 +54,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
},
"gomofs": {
Expand All @@ -66,7 +69,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
},
"gomofs_2d": {
Expand All @@ -80,7 +84,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
},
"leofs": {
Expand Down Expand Up @@ -205,7 +210,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
},
"wcofs": {
Expand All @@ -219,7 +225,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
},
"wcofs_2d": {
Expand All @@ -233,7 +240,8 @@
"water_level_var": "zeta",
"vdatum_var": "mllwtomsl",
"vdatum_name": "mllw"
}
},
"roms": {}
}
}
}
90 changes: 0 additions & 90 deletions datasets/datasets_local.json

This file was deleted.

3 changes: 3 additions & 0 deletions viewer/src/query/datasets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const useDatasetsQuery = (datasetIds: Array<string> | undefined) =>
queries: datasetIds
? datasetIds.map((datasetId) => ({
queryKey: ['dataset', datasetId],
staleTime: 10 * 60 * 1000,
queryFn: () => fetchDataset(datasetId),
}))
: [],
Expand All @@ -29,6 +30,7 @@ export const useDatasetMetadataQuery = (
) =>
useQuery({
queryKey: ['dataset', 'metadata', dataset],
staleTime: 10 * 60 * 1000,
queryFn: () =>
dataset
? fetchMetadata(dataset.dataset, dataset.variable)
Expand All @@ -44,6 +46,7 @@ export const useDatasetMinMaxQuery = (dataset: {
} | undefined) =>
useQuery({
queryKey: ['dataset', 'minmax', dataset],
staleTime: 10 * 60 * 1000,
queryFn: () => dataset !== undefined ? fetchMinMax(
dataset.dataset,
dataset.variable,
Expand Down
2 changes: 2 additions & 0 deletions xreds/dataset_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
from xreds.dataset_extension import DATASET_EXTENSION_PLUGIN_NAMESPACE
from xreds.dependencies.redis import get_redis
from xreds.extensions import VDatumTransformationExtension
from xreds.extensions.roms import ROMSExtension
from xreds.logging import logger
from xreds.redis import get_redis_cache
from xreds.utils import load_dataset

dataset_extension_manager = PluginManager(DATASET_EXTENSION_PLUGIN_NAMESPACE)
dataset_extension_manager.register(VDatumTransformationExtension, name="vdatum")
dataset_extension_manager.register(ROMSExtension, name="roms")


class DatasetProvider(Plugin):
Expand Down
130 changes: 130 additions & 0 deletions xreds/extensions/roms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import numpy as np
import xarray as xr

from xreds.dataset_extension import DatasetExtension, hookimpl
from xreds.logging import logger


class ROMSExtension(DatasetExtension):
"""Transform ROMS currents to the global reference frame
Urho(i,j) = 0.5 * ( U(i,j) + U(i+1,j) )
Vrho(i,j) = 0.5 * ( V(i,j) + V(i,j+1) )
u(LON,LAT)=u(XI,ETA)*cos(angle(i,j))-v(XI,ETA)*sin(angle(i,j))
v(LON,LAT)=v(XI,ETA)*cos(angle(i,j))+u(XI,ETA)*sin(angle(i,j))
For an illustration of the grid see https://www.myroms.org/wiki/Numerical_Solution_Technique
"""

name: str = "roms"

@hookimpl
def transform_dataset(self, ds: xr.Dataset, config: dict) -> xr.Dataset:
angle = ds.angle

default_da: xr.DataArray | None = None
if "s_rho" in ds.dims:
if "temp" in ds:
default_da = ds.temp
if "temp_sur" in ds:
default_da = ds.temp_sur
elif "salt" in ds:
default_da = ds.salt
elif "salt_sur" in ds:
default_da = ds.salt_sur

if default_da is None:
logger.warn(
"No default data array found in dataset. Skipping ROMS transformation"
)
return ds

# Start with u
u_name = "u_sur" if "u_sur" in ds else "u"
u = ds[u_name]

u_rho = default_da.copy()
u_rho.name = "u_rho"
u_rho.attrs["field"] = u.attrs["field"]
u_rho.attrs["units"] = u.attrs["units"]
u_rho.attrs["standard_name"] = u.attrs["standard_name"]
u_rho.attrs["long_name"] = u.attrs["long_name"]

# Have to rename the dimensions to match the rho grid, otherwise
# xarray will refuse
u_renamed = u.rename(
{
"xi_u": "xi_rho",
"eta_u": "eta_rho",
"lat_u": "lat_rho",
"lon_u": "lon_rho",
}
)

u_center = 0.5 * (
u_renamed.loc[dict(xi_rho=slice(0, -1))]
+ u_renamed.loc[dict(xi_rho=slice(1, None))]
)
u_first = u_renamed.loc[dict(xi_rho=0)]
u_last = u_renamed.loc[dict(xi_rho=-1)]
u_rho = xr.concat(
[u_first, u_center, u_last],
dim="xi_rho",
coords="minimal",
compat="override",
)
u_rho["lat_rho"] = ds.lat_rho
u_rho["lon_rho"] = ds.lon_rho

# Now do v
v_name = "v_sur" if "v_sur" in ds else "v"
v = ds[v_name]

v_rho = default_da.copy()
v_rho.name = "v_rho"
v_rho.attrs["field"] = v.attrs["field"]
v_rho.attrs["units"] = v.attrs["units"]
v_rho.attrs["standard_name"] = v.attrs["standard_name"]
v_rho.attrs["long_name"] = v.attrs["long_name"]

# Have to rename the dimensions to match the rho grid, otherwise
# xarray will refuse
v_renamed = v.rename(
{
"xi_v": "xi_rho",
"eta_v": "eta_rho",
"lat_v": "lat_rho",
"lon_v": "lon_rho",
}
)

v_center = 0.5 * (
v_renamed.loc[dict(eta_rho=slice(0, -1))]
+ v_renamed.loc[dict(eta_rho=slice(1, None))]
)
v_first = v_renamed.loc[dict(eta_rho=0)]
v_last = v_renamed.loc[dict(eta_rho=-1)]
v_rho = xr.concat(
[v_first, v_center, v_last],
dim="eta_rho",
coords="minimal",
compat="override",
)
v_rho["lat_rho"] = ds.lat_rho
v_rho["lon_rho"] = ds.lon_rho

u_rotated = u_rho * np.cos(angle) - v_rho * np.sin(angle)
u_rotated = u_rotated.assign_attrs(u_rho.attrs)
u_rotated.name = f"{u_name}_rotated"
u_rotated.attrs["long_name"] = "u velocity rotated from ROMS grid"

v_rotated = v_rho * np.cos(angle) + u_rho * np.sin(angle)
v_rotated = v_rotated.assign_attrs(v_rho.attrs)
v_rotated.name = f"{v_name}_rotated"
v_rotated.attrs["long_name"] = "v velocity rotated from ROMS grid"

ds[f"{u_name}_rotated"] = u_rotated
ds[f"{v_name}_rotated"] = v_rotated

return ds

0 comments on commit 664b3ed

Please sign in to comment.