Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
621a948
[WIP] Draft implementation of the XField and XFieldset class
fluidnumerics-joe Mar 18, 2025
36e164a
Add notebook that illustrates created xarray and uxarray objects for …
fluidnumerics-joe Mar 21, 2025
5578201
Bring in remaining API from Field to XField.
fluidnumerics-joe Mar 21, 2025
10e29cb
Remove fieldtype attribute
fluidnumerics-joe Mar 24, 2025
dcf31a2
Add ravel/unravel index
fluidnumerics-joe Mar 24, 2025
65c5735
Add ravel/unravel; Add vector field interpolation support and access …
fluidnumerics-joe Mar 24, 2025
c6a9340
Add basic implementation for xfieldset
fluidnumerics-joe Mar 24, 2025
da84893
Add draft of unstructured grid index search.
fluidnumerics-joe Mar 25, 2025
7514e82
Swap grid for Field in _search_time_index
fluidnumerics-joe Mar 27, 2025
4465dc4
Enforce time as a datetime object in field.eval call-stack
fluidnumerics-joe Mar 27, 2025
de2ab3f
Set the time_origin to the minimum time dimension in the fieldset
fluidnumerics-joe Mar 27, 2025
737d258
Port over rectilinear search.
fluidnumerics-joe Mar 27, 2025
6b9fe52
Change vector field component names to uppercase
fluidnumerics-joe Mar 31, 2025
5e73050
Add simple tests
fluidnumerics-joe Mar 31, 2025
6e7c60a
Add uxarray to environment
fluidnumerics-joe Mar 31, 2025
7b5aba1
Resolve bugs for simple fesom fieldset loading
fluidnumerics-joe Mar 31, 2025
812875a
Add dimrange function and gridset_size property to fieldset
fluidnumerics-joe Mar 31, 2025
3136dbf
Add support for list of (U)xarray.(Ux)datasets in fieldset
fluidnumerics-joe Mar 31, 2025
2e0a1f8
Switch to using updated fieldset api for gridset_size and dimrange
fluidnumerics-joe Mar 31, 2025
a9b7f87
Add interpolation methods with test
fluidnumerics-joe Mar 31, 2025
3c2488f
Fix method to verify interpolation method call signature.
fluidnumerics-joe Mar 31, 2025
75f7916
Allow eval to accept particle, rather than ei
fluidnumerics-joe Mar 31, 2025
f04d729
Move tests to tests/v4
fluidnumerics-joe Apr 1, 2025
95c701c
Formatting fixes
fluidnumerics-joe Apr 2, 2025
b0967d9
Fix a few tests in test_fieldset up to fieldset.from_data
fluidnumerics-joe Apr 4, 2025
71ec7e4
Fix fieldset.from_data for test_fieldset_from_data_timedims test
fluidnumerics-joe Apr 7, 2025
06bd544
Add pytest markers for test_fieldset
fluidnumerics-joe Apr 7, 2025
7b9e9d3
Mark tests with `from_netcdf` for removal
fluidnumerics-joe Apr 7, 2025
9b04830
Remove test_grids
fluidnumerics-joe Apr 7, 2025
0357602
Mark interpolation tests for removal
fluidnumerics-joe Apr 7, 2025
f3903e4
Mark tests for v4alpha
fluidnumerics-joe Apr 7, 2025
f360ded
Mark tests with markers for fieldset_sampling
fluidnumerics-joe Apr 7, 2025
29fb964
Add FESOM periodic channel data
fluidnumerics-joe Apr 9, 2025
58a138e
Add particleset execute test for fesom channel
fluidnumerics-joe Apr 9, 2025
62cd324
Add grid attribute to field.
fluidnumerics-joe Apr 9, 2025
5f75a07
Merge branch 'v4-dev' into feature/uxarray_xarray_fields
fluidnumerics-joe Apr 9, 2025
884a620
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 9, 2025
9c8fbda
Formatting fixes
fluidnumerics-joe Apr 9, 2025
3906a91
Merge branch 'feature/uxarray_xarray_fields' of github.com:OceanParce…
fluidnumerics-joe Apr 9, 2025
4bf5096
Update test to use fesom download
VeckoTheGecko Apr 9, 2025
4736038
Add xfail markers
VeckoTheGecko Apr 10, 2025
8c8e947
Change "to do" to "TODO"
fluidnumerics-joe Apr 11, 2025
4ea5c2e
Merge branch 'feature/uxarray_xarray_fields' of github.com:OceanParce…
fluidnumerics-joe Apr 11, 2025
12557d9
Move _validate_* functions to be pure functions
fluidnumerics-joe Apr 11, 2025
81793d9
Return gridset_size as the number of fields
fluidnumerics-joe Apr 11, 2025
9d3a7e2
Remove precision requirment on constant field
fluidnumerics-joe Apr 11, 2025
89e18bd
Remove parse_wildcards
fluidnumerics-joe Apr 11, 2025
0af7de9
Remove fieldset.from_data
fluidnumerics-joe Apr 14, 2025
819a077
Change test markers; add TODO to remove `from_data` calls
fluidnumerics-joe Apr 14, 2025
687c1e1
Merge branch 'v4-dev' into feature/uxarray_xarray_fields
fluidnumerics-joe Apr 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
364 changes: 364 additions & 0 deletions docs/examples/tutorial_stommel_uxarray.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,364 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Stommel Gyre on Unstructured Grid\n",
"This tutorial walks through creating a UXArray dataset using the Stommel Gyre analytical solution for a closed rectangular domain on a beta-plane"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def stommel_fieldset_uxarray(xdim=200, ydim=200):\n",
" \"\"\"Simulate a periodic current along a western boundary, with significantly\n",
" larger velocities along the western edge than the rest of the region\n",
"\n",
" The original test description can be found in: N. Fabbroni, 2009,\n",
" Numerical Simulation of Passive tracers dispersion in the sea,\n",
" Ph.D. dissertation, University of Bologna\n",
" http://amsdottorato.unibo.it/1733/1/Fabbroni_Nicoletta_Tesi.pdf\n",
" \"\"\"\n",
" import math\n",
"\n",
" import numpy as np\n",
" import pandas as pd\n",
" import uxarray as ux\n",
"\n",
" a = b = 66666 * 1e3\n",
" scalefac = 0.00025 # to scale for physically meaningful velocities\n",
"\n",
" # Coordinates of the test fieldset\n",
" # Crowd points to the west edge of the domain\n",
" # using a polyonmial map on x-direction\n",
" x = np.linspace(0, 1, xdim, dtype=np.float32)\n",
" lon, lat = np.meshgrid(a * x, np.linspace(0, b, ydim, dtype=np.float32))\n",
" points = (lon.flatten() / 1111111.111111111, lat.flatten() / 1111111.111111111)\n",
"\n",
" # Create the grid\n",
" uxgrid = ux.Grid.from_points(points, method=\"regional_delaunay\")\n",
" uxgrid.construct_face_centers()\n",
"\n",
" # Define arrays U (zonal), V (meridional) and P (sea surface height)\n",
" U = np.zeros((1, 1, lat.size), dtype=np.float32)\n",
" V = np.zeros((1, 1, lat.size), dtype=np.float32)\n",
" P = np.zeros((1, 1, lat.size), dtype=np.float32)\n",
"\n",
" beta = 2e-11\n",
" r = 1 / (11.6 * 86400)\n",
" es = r / (beta * a)\n",
"\n",
" i = 0\n",
" for x, y in zip(lon.flatten(), lat.flatten()):\n",
" xi = x / a\n",
" yi = y / b\n",
" P[0, 0, i] = (\n",
" (1 - math.exp(-xi / es) - xi) * math.pi * np.sin(math.pi * yi) * scalefac\n",
" )\n",
" U[0, 0, i] = (\n",
" -(1 - math.exp(-xi / es) - xi)\n",
" * math.pi**2\n",
" * np.cos(math.pi * yi)\n",
" * scalefac\n",
" )\n",
" V[0, 0, i] = (\n",
" (math.exp(-xi / es) / es - 1) * math.pi * np.sin(math.pi * yi) * scalefac\n",
" )\n",
" i += 1\n",
"\n",
" u = ux.UxDataArray(\n",
" data=U,\n",
" name=\"u\",\n",
" uxgrid=uxgrid,\n",
" dims=[\"time\", \"nz1\", \"n_node\"],\n",
" coords=dict(\n",
" time=([\"time\"], pd.to_datetime([\"2000-01-01\"])),\n",
" nz1=([\"nz1\"], [0]),\n",
" ),\n",
" attrs=dict(\n",
" description=\"zonal velocity\",\n",
" units=\"m/s\",\n",
" location=\"node\",\n",
" mesh=\"delaunay\",\n",
" ),\n",
" )\n",
" v = ux.UxDataArray(\n",
" data=V,\n",
" name=\"v\",\n",
" uxgrid=uxgrid,\n",
" dims=[\"time\", \"nz1\", \"n_node\"],\n",
" coords=dict(\n",
" time=([\"time\"], pd.to_datetime([\"2000-01-01\"])),\n",
" nz1=([\"nz1\"], [0]),\n",
" ),\n",
" attrs=dict(\n",
" description=\"meridional velocity\",\n",
" units=\"m/s\",\n",
" location=\"node\",\n",
" mesh=\"delaunay\",\n",
" ),\n",
" )\n",
" p = ux.UxDataArray(\n",
" data=P,\n",
" name=\"p\",\n",
" uxgrid=uxgrid,\n",
" dims=[\"time\", \"nz1\", \"n_node\"],\n",
" coords=dict(\n",
" time=([\"time\"], pd.to_datetime([\"2000-01-01\"])),\n",
" nz1=([\"nz1\"], [0]),\n",
" ),\n",
" attrs=dict(\n",
" description=\"pressure\",\n",
" units=\"N/m^2\",\n",
" location=\"node\",\n",
" mesh=\"delaunay\",\n",
" ),\n",
" )\n",
"\n",
" return ux.UxDataset({\"u\": u, \"v\": v, \"p\": p}, uxgrid=uxgrid)\n",
"\n",
"\n",
"uxds = stommel_fieldset_uxarray(50, 50)\n",
"\n",
"uxds.uxgrid.plot(\n",
" line_width=0.5,\n",
" height=500,\n",
" width=1000,\n",
" title=\"Regional Delaunay Regions\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def stommel_fieldset_xarray(xdim=200, ydim=200, grid_type=\"A\"):\n",
" \"\"\"Simulate a periodic current along a western boundary, with significantly\n",
" larger velocities along the western edge than the rest of the region\n",
"\n",
" The original test description can be found in: N. Fabbroni, 2009,\n",
" Numerical Simulation of Passive tracers dispersion in the sea,\n",
" Ph.D. dissertation, University of Bologna\n",
" http://amsdottorato.unibo.it/1733/1/Fabbroni_Nicoletta_Tesi.pdf\n",
" \"\"\"\n",
" import math\n",
"\n",
" import numpy as np\n",
" import pandas as pd\n",
" import xarray as xr\n",
"\n",
" a = b = 10000 * 1e3\n",
" scalefac = 0.05 # to scale for physically meaningful velocities\n",
" dx, dy = a / xdim, b / ydim\n",
"\n",
" # Coordinates of the test fieldset (on A-grid in deg)\n",
" lon = np.linspace(0, a, xdim, dtype=np.float32)\n",
" lat = np.linspace(0, b, ydim, dtype=np.float32)\n",
"\n",
" # Define arrays U (zonal), V (meridional) and P (sea surface height)\n",
" U = np.zeros((1, 1, lat.size, lon.size), dtype=np.float32)\n",
" V = np.zeros((1, 1, lat.size, lon.size), dtype=np.float32)\n",
" P = np.zeros((1, 1, lat.size, lon.size), dtype=np.float32)\n",
"\n",
" beta = 2e-11\n",
" r = 1 / (11.6 * 86400)\n",
" es = r / (beta * a)\n",
"\n",
" for j in range(lat.size):\n",
" for i in range(lon.size):\n",
" xi = lon[i] / a\n",
" yi = lat[j] / b\n",
" P[..., j, i] = (\n",
" (1 - math.exp(-xi / es) - xi)\n",
" * math.pi\n",
" * np.sin(math.pi * yi)\n",
" * scalefac\n",
" )\n",
" if grid_type == \"A\":\n",
" U[..., j, i] = (\n",
" -(1 - math.exp(-xi / es) - xi)\n",
" * math.pi**2\n",
" * np.cos(math.pi * yi)\n",
" * scalefac\n",
" )\n",
" V[..., j, i] = (\n",
" (math.exp(-xi / es) / es - 1)\n",
" * math.pi\n",
" * np.sin(math.pi * yi)\n",
" * scalefac\n",
" )\n",
"\n",
" time = pd.to_datetime([\"2000-01-01\"])\n",
" z = [0]\n",
" if grid_type == \"C\":\n",
" V[..., :, 1:] = (P[..., :, 1:] - P[..., :, 0:-1]) / dx * a\n",
" U[..., 1:, :] = -(P[..., 1:, :] - P[..., 0:-1, :]) / dy * b\n",
" u_dims = [\"time\", \"nz1\", \"face_lat\", \"node_lon\"]\n",
" u_lat = lat\n",
" u_lon = lon - dx * 0.5\n",
" u_location = \"x_edge\"\n",
" v_dims = [\"time\", \"nz1\", \"node_lat\", \"face_lon\"]\n",
" v_lat = lat - dy * 0.5\n",
" v_lon = lon\n",
" v_location = \"y_edge\"\n",
" p_dims = [\"time\", \"nz1\", \"face_lat\", \"face_lon\"]\n",
" p_lat = lat\n",
" p_lon = lon\n",
" p_location = \"face\"\n",
"\n",
" else:\n",
" u_dims = [\"time\", \"nz1\", \"node_lat\", \"node_lon\"]\n",
" v_dims = [\"time\", \"nz1\", \"node_lat\", \"node_lon\"]\n",
" p_dims = [\"time\", \"nz1\", \"node_lat\", \"node_lon\"]\n",
" u_lat = lat\n",
" u_lon = lon\n",
" v_lat = lat\n",
" v_lon = lon\n",
" u_location = \"node\"\n",
" v_location = \"node\"\n",
" p_lat = lat\n",
" p_lon = lon\n",
" p_location = \"node\"\n",
"\n",
" u = xr.DataArray(\n",
" data=U,\n",
" name=\"u\",\n",
" dims=u_dims,\n",
" coords=[time, z, u_lat, u_lon],\n",
" attrs=dict(\n",
" description=\"zonal velocity\",\n",
" units=\"m/s\",\n",
" location=u_location,\n",
" mesh=f\"Arakawa-{grid_type}\",\n",
" ),\n",
" )\n",
" v = xr.DataArray(\n",
" data=V,\n",
" name=\"v\",\n",
" dims=v_dims,\n",
" coords=[time, z, v_lat, v_lon],\n",
" attrs=dict(\n",
" description=\"meridional velocity\",\n",
" units=\"m/s\",\n",
" location=v_location,\n",
" mesh=f\"Arakawa-{grid_type}\",\n",
" ),\n",
" )\n",
" p = xr.DataArray(\n",
" data=P,\n",
" name=\"p\",\n",
" dims=p_dims,\n",
" coords=[time, z, p_lat, p_lon],\n",
" attrs=dict(\n",
" description=\"pressure\",\n",
" units=\"N/m^2\",\n",
" location=p_location,\n",
" mesh=f\"Arakawa-{grid_type}\",\n",
" ),\n",
" )\n",
"\n",
" return xr.Dataset({\"u\": u, \"v\": v, \"p\": p})\n",
"\n",
"\n",
"ds_arakawa_a = stommel_fieldset_xarray(50, 50, \"A\")\n",
"ds_arakawa_c = stommel_fieldset_xarray(50, 50, \"C\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds_arakawa_a"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds_arakawa_a[\"u\"].attrs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds_arakawa_c"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"\n",
"min_length_scale = 1111111.111111111 * np.sqrt(np.min(uxds.uxgrid.face_areas))\n",
"print(min_length_scale)\n",
"\n",
"max_v = np.sqrt(uxds[\"u\"] ** 2 + uxds[\"v\"] ** 2).max()\n",
"print(max_v)\n",
"\n",
"cfl = 0.1\n",
"dt = cfl * min_length_scale / max_v\n",
"print(dt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from datetime import timedelta\n",
"\n",
"import numpy as np\n",
"import uxarray as ux\n",
"\n",
"from parcels import Particle, ParticleSet, UxAdvectionEuler, UXFieldSet\n",
"\n",
"npart = 10\n",
"fieldset = UXFieldSet(uxds)\n",
"# pset = ParticleSet(\n",
"# fieldset,\n",
"# pclass=Particle,\n",
"# lon=np.linspace(1, 59, npart),\n",
"# lat=np.zeros(npart)+30)\n",
"# pset.execute(UxAdvectionEuler, runtime=timedelta(hours=24), dt=timedelta(seconds=dt))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "parcels",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies: #! Keep in sync with [tool.pixi.dependencies] in pyproject.toml
- dask>=2.0
- scikit-learn
- zarr>=2.11.0,!=2.18.0,<3
- uxaray>=2025.3.0
- pooch

# Notebooks
Expand Down
Loading
Loading