Skip to content

Commit 0d5fa89

Browse files
committed
Added tests for nearest neighbour sampler with analytical test data
1 parent 5497a7e commit 0d5fa89

1 file changed

Lines changed: 142 additions & 0 deletions

File tree

tests/unit/test_sampler.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# ===================================================================
2+
# Copyright 2025 National Oceanography Centre
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
# http://www.apache.org/licenses/LICENSE-2.0.
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
11+
# implied. See the License for the specific language governing
12+
# permissions and limitations under the License.
13+
# ===================================================================
14+
"""
15+
test_sampler.py
16+
17+
Description:
18+
This module includes unit tests for extracting profiles.
19+
20+
Author:
21+
Benjamin Barton (benbar@noc.ac.uk)
22+
"""
23+
import pytest
24+
import datetime as dt
25+
import numpy as np
26+
import xarray as xr
27+
from OceanOSSE.sampling.sampler_nearest_neighbour import NNSampler
28+
29+
def test_sampler():
30+
"""
31+
Tests for extracting a profile that falls on a model grid point.
32+
"""
33+
# Build dataset
34+
ds = construct_ds()
35+
36+
# Synthetic profile
37+
prof_id = np.array([0])
38+
profile_lon = np.array([3])
39+
profile_lat = np.array([5])
40+
profile = xr.Dataset(
41+
{
42+
"lon": (("prof_id"), profile_lon),
43+
"lat": (("prof_id"), profile_lat)
44+
},
45+
coords={
46+
"profile_id": prof_id,
47+
},
48+
)
49+
50+
sampler = NNSampler()
51+
model_t = sampler.sample(ds, profile)
52+
53+
assert (model_t.votemper.to_numpy().squeeze() == ds.votemper[:, 5, 3]).all()
54+
55+
56+
def test_sampler_multi():
57+
"""
58+
Tests for extracting multiple profiles that falls on a model grid point.
59+
"""
60+
# Build dataset
61+
ds = construct_ds()
62+
63+
# Synthetic profile
64+
prof_id = np.array([0, 1])
65+
profile_lon = np.array([3, 8])
66+
profile_lat = np.array([5, 6])
67+
profile = xr.Dataset(
68+
{
69+
"lon": (("profile_id"), profile_lon),
70+
"lat": (("profile_id"), profile_lat)
71+
},
72+
coords={
73+
"profile_id": prof_id,
74+
},
75+
)
76+
77+
sampler = NNSampler()
78+
model_t = sampler.sample(ds, profile)
79+
80+
assert (model_t.votemper.isel(profile_id=1) == ds.votemper[:, 6, 8]).all()
81+
82+
83+
def test_sampler_nn():
84+
"""
85+
Test for extracting a profile that falls between model grid points that will use nearest
86+
neighbour against analytic form.
87+
"""
88+
# Build dataset
89+
ds = construct_ds()
90+
91+
# Synthetic profile
92+
prof_id = np.array([0, 1])
93+
profile_lon = np.array([3.5, 1.2])
94+
profile_lat = np.array([5.5, 2.2])
95+
profile = xr.Dataset(
96+
{
97+
"lon": (("profile_id"), profile_lon),
98+
"lat": (("profile_id"), profile_lat)
99+
},
100+
coords={
101+
"profile_id": prof_id,
102+
},
103+
)
104+
105+
sampler = NNSampler()
106+
model_t = sampler.sample(ds, profile)
107+
print(model_t)
108+
109+
assert ((model_t.votemper.isel(profile_id=0) == ds.votemper[:, 6, 4]).all()
110+
& (model_t.votemper.isel(profile_id=1) == ds.votemper[:, 2, 1]).all())
111+
112+
113+
def construct_ds():
114+
"""
115+
Build a dataset for testing.
116+
"""
117+
lat = np.arange(0, 8)
118+
lon = np.arange(0, 10)
119+
depth = np.arange(0, 150, 10)
120+
121+
# Broadcast to 3D (depth, lat, lon)
122+
d, y, x = np.meshgrid(depth, lat, lon, indexing='ij')
123+
124+
# Synthetic temperature field
125+
votemper = 15 - (y * 0.4) + (x * 0.2) - (d * 0.02)
126+
127+
# Build dataset
128+
ds = xr.Dataset(
129+
{
130+
"votemper": (("d", "j", "i"), votemper),
131+
"lat": (("j", "i"), y[0, :, :]),
132+
"lon": (("j", "i"), x[0, :, :]),
133+
"depth": (("d", "j", "i"), d)
134+
},
135+
coords={
136+
"d": depth,
137+
"j": lat,
138+
"i": lon,
139+
},
140+
)
141+
142+
return ds

0 commit comments

Comments
 (0)