Skip to content

Commit 60e2460

Browse files
added error handling to all generate funcs and some tests for 2d maps
1 parent a5bcc43 commit 60e2460

8 files changed

+601
-25
lines changed

src/fluidsf/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .shift_array_1d import shift_array_1d
2020
from .shift_array_2d import shift_array_2d
2121
from .shift_array_3d import shift_array_3d
22+
from .shift_array_xy import shift_array_xy
2223

2324
__version__ = "0.2.0"
2425

@@ -38,5 +39,6 @@
3839
"shift_array_1d",
3940
"shift_array_2d",
4041
"shift_array_3d",
42+
"shift_array_xy",
4143
"bin_data",
4244
)

src/fluidsf/calculate_sf_maps_2d.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,13 @@ def calculate_sf_maps_2d( # noqa: D417, C901
9797
inputs.update(shifted_inputs)
9898
SF_dict = {}
9999

100-
if any("ASF_V" in t for t in sf_type):
100+
if "ASF_V" in sf_type:
101101
SF_dict["SF_advection_velocity_xy"] = np.nanmean(
102102
(inputs["adv_x_xy_shift"] - adv_x) * (inputs["u_xy_shift"] - u)
103103
+ (inputs["adv_y_xy_shift"] - adv_y) * (inputs["v_xy_shift"] - v)
104104
)
105105

106-
if any("ASF_S" in t for t in sf_type):
106+
if "ASF_S" in sf_type:
107107
SF_dict["SF_advection_scalar_xy"] = np.nanmean(
108108
(inputs["adv_scalar_xy_shift"] - adv_scalar)
109109
* (inputs["scalar_xy_shift"] - scalar)
@@ -115,34 +115,34 @@ def calculate_sf_maps_2d( # noqa: D417, C901
115115
cosine_angle = x_separation / np.sqrt(x_separation**2 + y_separation**2)
116116
sine_angle = y_separation / np.sqrt(x_separation**2 + y_separation**2)
117117

118-
if any("LL" in t for t in sf_type):
118+
if "LL" in sf_type:
119119
SF_dict["SF_LL_xy"] = np.nanmean(
120120
(
121121
(inputs["u_xy_shift"] - u) * cosine_angle
122122
+ (inputs["v_xy_shift"] - v) * sine_angle
123123
)
124124
** 2
125125
)
126-
if any("TT" in t for t in sf_type):
126+
if "TT" in sf_type:
127127
SF_dict["SF_TT_xy"] = np.nanmean(
128128
(
129129
(inputs["v_xy_shift"] - v) * cosine_angle
130130
- (inputs["u_xy_shift"] - u) * sine_angle
131131
)
132132
** 2
133133
)
134-
if any("SS" in t for t in sf_type):
134+
if "SS" in sf_type:
135135
SF_dict["SF_SS_xy"] = np.nanmean((inputs["scalar_xy_shift"] - scalar) ** 2)
136136

137-
if any("LLL" in t for t in sf_type):
137+
if "LLL" in sf_type:
138138
SF_dict["SF_LLL_xy"] = np.nanmean(
139139
(
140140
(inputs["u_xy_shift"] - u) * cosine_angle
141141
+ (inputs["v_xy_shift"] - v) * sine_angle
142142
)
143143
** 3
144144
)
145-
if any("LTT" in t for t in sf_type):
145+
if "LTT" in sf_type:
146146
SF_dict["SF_LTT_xy"] = np.nanmean(
147147
(
148148
(inputs["u_xy_shift"] - u) * cosine_angle
@@ -155,7 +155,7 @@ def calculate_sf_maps_2d( # noqa: D417, C901
155155
** 2
156156
)
157157

158-
if any("LSS" in t for t in sf_type):
158+
if "LSS" in sf_type:
159159
SF_dict["SF_LSS_xy"] = np.nanmean(
160160
(
161161
(inputs["u_xy_shift"] - u) * cosine_angle

src/fluidsf/generate_sf_maps_2d.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,51 @@ def generate_sf_maps_2d( # noqa: C901, D417
5454
distances for the x- and y-directions.
5555
5656
"""
57+
# Error handling
58+
59+
if not isinstance(sf_type, list):
60+
raise ValueError("sf_type must be a list of strings.")
61+
62+
if len(sf_type) == 0:
63+
raise ValueError(
64+
"sf_type cannot be an empty list. All elements in sf_type must be strings. "
65+
"Accepted strings are: ASF_V, ASF_S, LL, TT, SS, LLL, LTT, LSS."
66+
)
67+
68+
if not all(isinstance(t, str) for t in sf_type):
69+
raise ValueError(
70+
"All elements in sf_type must be strings. Accepted strings are: "
71+
"ASF_V, ASF_S, LL, TT, SS, LLL, LTT, LSS."
72+
)
73+
74+
for t in sf_type:
75+
if t not in ["ASF_V", "ASF_S", "LL", "TT", "SS", "LLL", "LTT", "LSS"]:
76+
raise ValueError(
77+
"All elements in sf_type must be one of the following: "
78+
"ASF_V, ASF_S, LL, TT, SS, LLL, LTT, LSS."
79+
)
80+
81+
if grid_type != "uniform":
82+
raise ValueError("grid_type must be 'uniform' for this method.")
83+
84+
if (
85+
scalar is not None
86+
and (("SS" not in sf_type) and ("LSS" not in sf_type))
87+
and ("ASF_S" not in sf_type)
88+
):
89+
raise ValueError(
90+
"If scalar is provided, you must include 'SS', 'LSS' or 'ASF_S' "
91+
"in SF_type."
92+
)
93+
94+
if scalar is None and (
95+
("SS" in sf_type) or ("LSS" in sf_type) or ("ASF_S" in sf_type)
96+
):
97+
raise ValueError(
98+
"If you include 'SS', 'LSS' or 'ASF_S' in SF_type, you must provide "
99+
"a scalar array."
100+
)
101+
57102
# Initialize variables as NoneType
58103
SF_adv = None
59104
adv_x = None

src/fluidsf/generate_structure_functions_3d.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,55 @@ def generate_structure_functions_3d( # noqa: C901, D417
5959
distances for the x, y, and z directions.
6060
6161
"""
62+
# Error handling
63+
64+
if not isinstance(sf_type, list):
65+
raise ValueError("sf_type must be a list of strings.")
66+
67+
if len(sf_type) == 0:
68+
raise ValueError("sf_type must contain at least one structure function type.")
69+
70+
if not all(isinstance(t, str) for t in sf_type):
71+
raise ValueError("All elements in sf_type must be strings.")
72+
73+
for t in sf_type:
74+
if t not in [
75+
"ASF_V",
76+
"ASF_S",
77+
"LL",
78+
"TT",
79+
"SS",
80+
"LLL",
81+
"LTT",
82+
"LSS",
83+
]:
84+
raise ValueError(
85+
"All elements in sf_type must be one of the following: "
86+
"ASF_V, ASF_S, LL, TT, SS, LLL, LTT, LSS."
87+
)
88+
89+
if boundary not in [None, "periodic-x", "periodic-y", "periodic-z", "periodic-all"]:
90+
raise ValueError(
91+
"boundary must be one of the following: "
92+
"None, 'periodic-x', 'periodic-y', 'periodic-z', 'periodic-all'."
93+
)
94+
95+
if scalar is not None and (
96+
("SS" not in sf_type) and ("LSS" not in sf_type) and ("ASF_S" not in sf_type)
97+
):
98+
raise ValueError(
99+
"If scalar is provided, you must include 'SS', 'LSS' or 'ASF_S' "
100+
"in SF_type."
101+
)
102+
103+
if scalar is None and (
104+
("SS" in sf_type) or ("LSS" in sf_type) or ("ASF_S" in sf_type)
105+
):
106+
raise ValueError(
107+
"If you include 'SS', 'LSS' or 'ASF_S' in SF_type, you must provide "
108+
"a scalar field."
109+
)
110+
62111
# Initialize variables as NoneType
63112
SF_adv_x = None
64113
SF_adv_y = None

tests/test_calculate_sf_maps_2d.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import numpy as np
2+
import pytest
3+
from fluidsf.calculate_sf_maps_2d import calculate_sf_maps_2d
4+
5+
6+
@pytest.mark.parametrize(
7+
"u, v, x, y, adv_x, adv_y, shift_in_x, shift_in_y, sf_type, scalar, adv_scalar, "
8+
"expected_sf_maps",
9+
[
10+
# Test 1: Test case with all zeros
11+
(
12+
np.zeros((3, 3)), # u
13+
np.zeros((3, 3)), # v
14+
np.array([0, 1, 2]), # x
15+
np.array([0, 1, 2]), # y
16+
np.zeros((3, 3)), # adv_x
17+
np.zeros((3, 3)), # adv_y
18+
1, # shift_in_x
19+
1, # shift_in_y
20+
["ASF_V", "LLL", "LTT", "LSS", "LL", "TT", "SS"], # sf_type
21+
np.zeros((3, 3)), # scalar
22+
np.zeros((3, 3)), # adv_scalar
23+
{
24+
"SF_LL_xy": 0.0,
25+
"SF_TT_xy": 0.0,
26+
"SF_SS_xy": 0.0,
27+
"SF_LLL_xy": 0.0,
28+
"SF_LTT_xy": 0.0,
29+
"SF_LSS_xy": 0.0,
30+
}, # expected_sf_maps
31+
),
32+
# Test 2: Test case with all ones
33+
(
34+
np.ones((3, 3)), # u
35+
np.ones((3, 3)), # v
36+
np.array([0, 1, 2]), # x
37+
np.array([0, 1, 2]), # y
38+
np.ones((3, 3)), # adv_x
39+
np.ones((3, 3)), # adv_y
40+
1, # shift_in_x
41+
1, # shift_in_y
42+
["ASF_V", "LLL", "LTT", "LSS", "LL", "TT", "SS"], # sf_type
43+
np.ones((3, 3)), # scalar
44+
np.ones((3, 3)), # adv_scalar
45+
{
46+
"SF_LL_xy": 0.0,
47+
"SF_TT_xy": 0.0,
48+
"SF_SS_xy": 0.0,
49+
"SF_LLL_xy": 0.0,
50+
"SF_LTT_xy": 0.0,
51+
"SF_LSS_xy": 0.0,
52+
}, # expected_sf_maps
53+
),
54+
# Test 3: slanted velocities np.arange(10) tiled in y no scalar only LL, LLL
55+
# with shift 5
56+
(
57+
np.tile(np.tile(np.arange(10), 10), (10**2, 1)), # u
58+
np.tile(np.tile(np.arange(10), 10), (10**2, 1)), # v
59+
np.linspace(0, 10**2, 10**2), # x
60+
np.linspace(0, 10**2, 10**2), # y
61+
None, # adv_x
62+
None, # adv_y
63+
5, # shift_x
64+
5, # shift_y
65+
["LL", "LLL"], # sf_type
66+
None, # scalar
67+
None, # adv_scalar
68+
{
69+
"SF_LL_xy": 10 * (10 / 2),
70+
"SF_LLL_xy": 0,
71+
},
72+
),
73+
# Test 4: slanted velocities np.arange(12) tiled in y no scalar only LL, LLL
74+
# with shift 6
75+
(
76+
np.tile(np.tile(np.arange(12), 12), (12**2, 1)), # u
77+
np.tile(np.tile(np.arange(12), 12), (12**2, 1)), # v
78+
np.linspace(0, 12**2, 12**2), # x
79+
np.linspace(0, 12**2, 12**2), # y
80+
None, # adv_x
81+
None, # adv_y
82+
6, # shift_x
83+
6, # shift_y
84+
["LL", "LLL"], # sf_type
85+
None, # scalar
86+
None, # adv_scalar
87+
{
88+
"SF_LL_xy": 12 * (12 / 2),
89+
"SF_LLL_xy": 0,
90+
},
91+
),
92+
# Test 5: slanted velocities np.arange(10) tiled in y no scalar only LL, LLL
93+
# with shift 10
94+
(
95+
np.tile(np.tile(np.arange(10), 10), (10**2, 1)), # u
96+
np.tile(np.tile(np.arange(10), 10), (10**2, 1)), # v
97+
np.linspace(0, 10**2, 10**2), # x
98+
np.linspace(0, 10**2, 10**2), # y
99+
None, # adv_x
100+
None, # adv_y
101+
10, # shift_x
102+
10, # shift_y
103+
["LL", "LLL"], # sf_type
104+
None, # scalar
105+
None, # adv_scalar
106+
{
107+
"SF_LL_xy": 0,
108+
"SF_LLL_xy": 0,
109+
},
110+
),
111+
# Test 6: slanted velocities np.arange(10) tiled in y no scalar only LL, LLL
112+
# TT, LTT with shift 5
113+
(
114+
np.tile(np.tile(np.arange(10), 10), (10**2, 1)), # u
115+
np.tile(np.tile(np.arange(10), 10), (10**2, 1)), # v
116+
np.linspace(0, 10**2, 10**2), # x
117+
np.linspace(0, 10**2, 10**2), # y
118+
None, # adv_x
119+
None, # adv_y
120+
5, # shift_x
121+
5, # shift_y
122+
["LL", "LLL", "TT", "LTT"], # sf_type
123+
None, # scalar
124+
None, # adv_scalar
125+
{
126+
"SF_LL_xy": 10 * (10 / 2),
127+
"SF_TT_xy": 0,
128+
"SF_LTT_xy": 0,
129+
"SF_LLL_xy": 0,
130+
},
131+
),
132+
],
133+
)
134+
def test_calculate_sf_maps_2d(
135+
u,
136+
v,
137+
x,
138+
y,
139+
adv_x,
140+
adv_y,
141+
shift_in_x,
142+
shift_in_y,
143+
sf_type,
144+
scalar,
145+
adv_scalar,
146+
expected_sf_maps,
147+
):
148+
output_sf_maps = calculate_sf_maps_2d(
149+
u, v, x, y, adv_x, adv_y, shift_in_x, shift_in_y, sf_type, scalar, adv_scalar
150+
)
151+
152+
for key, value in expected_sf_maps.items():
153+
if key in output_sf_maps:
154+
if not np.allclose(output_sf_maps[key], value):
155+
print(output_sf_maps[key])
156+
print(expected_sf_maps[key])
157+
raise AssertionError(
158+
f"Output dict value for key '{key}' does not match "
159+
f"expected value '{output_sf_maps[key]}'."
160+
)
161+
else:
162+
raise AssertionError(f"Output dict does not contain key '{key}'.")

0 commit comments

Comments
 (0)