-
Notifications
You must be signed in to change notification settings - Fork 171
Expand file tree
/
Copy pathinterpolation.py
More file actions
116 lines (99 loc) · 3.97 KB
/
interpolation.py
File metadata and controls
116 lines (99 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
"""Collection of pre-built interpolation kernels."""
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy as np
from parcels.field import Field
if TYPE_CHECKING:
from parcels.uxgrid import _UXGRID_AXES
from parcels.xgrid import _XGRID_AXES
__all__ = [
"UXPiecewiseConstantFace",
"UXPiecewiseLinearNode",
]
def XTriCurviLinear(
field: Field,
ti: int,
position: dict[_XGRID_AXES, tuple[int, float | np.ndarray]],
tau: np.float32 | np.float64,
t: np.float32 | np.float64,
z: np.float32 | np.float64,
y: np.float32 | np.float64,
x: np.float32 | np.float64,
):
"""Trilinear interpolation on a curvilinear grid."""
xi, xsi = position["X"]
yi, eta = position["Y"]
zi, zeta = position["Z"]
data = field.data
axis_dim = field.grid.get_axis_dim_mapping(field.data.dims)
return (
(
(1 - xsi) * (1 - eta) * data.isel({axis_dim["Y"]: yi, axis_dim["X"]: xi})
+ xsi * (1 - eta) * data.isel({axis_dim["Y"]: yi, axis_dim["X"]: xi + 1})
+ xsi * eta * data.isel({axis_dim["Y"]: yi + 1, axis_dim["X"]: xi + 1})
+ (1 - xsi) * eta * data.isel({axis_dim["Y"]: yi + 1, axis_dim["X"]: xi})
)
.interp(time=t, **{axis_dim["Z"]: zi + zeta})
.values
)
def XTriRectiLinear(
field: Field,
ti: int,
position: dict[_XGRID_AXES, tuple[int, float | np.ndarray]],
tau: np.float32 | np.float64,
t: np.float32 | np.float64,
z: np.float32 | np.float64,
y: np.float32 | np.float64,
x: np.float32 | np.float64,
):
"""Trilinear interpolation on a rectilinear grid."""
axis_dim = field.grid.get_axis_dim_mapping(field.data.dims)
xi, xsi = position["X"]
yi, eta = position["Y"]
zi, zeta = position["Z"]
kwargs = {axis_dim["X"]: xi + xsi, axis_dim["Y"]: yi + eta, axis_dim["Z"]: zi + zeta}
return field.data.interp(time=t, **kwargs).values
def UXPiecewiseConstantFace(
field: Field,
ti: int,
position: dict[_UXGRID_AXES, tuple[int, float | np.ndarray]],
tau: np.float32 | np.float64,
t: np.float32 | np.float64,
z: np.float32 | np.float64,
y: np.float32 | np.float64,
x: np.float32 | np.float64,
):
"""
Piecewise constant interpolation kernel for face registered data.
This interpolation method is appropriate for fields that are
face registered, such as u,v in FESOM.
"""
return field.data.values[ti, position["Z"][0], position["FACE"][0]]
def UXPiecewiseLinearNode(
field: Field,
ti: int,
position: dict[_UXGRID_AXES, tuple[int, float | np.ndarray]],
tau: np.float32 | np.float64,
t: np.float32 | np.float64,
z: np.float32 | np.float64,
y: np.float32 | np.float64,
x: np.float32 | np.float64,
):
"""
Piecewise linear interpolation kernel for node registered data located at vertical interface levels.
This interpolation method is appropriate for fields that are node registered such as the vertical
velocity W in FESOM2. Effectively, it applies barycentric interpolation in the lateral direction
and piecewise linear interpolation in the vertical direction.
"""
k, fi = position["Z"][0], position["FACE"][0]
bcoords = position["FACE"][1]
node_ids = field.grid.uxgrid.face_node_connectivity[fi, :]
# The zi refers to the vertical layer index. The field in this routine are assumed to be defined at the vertical interface levels.
# For interface zi, the interface indices are [zi, zi+1], so we need to use the values at zi and zi+1.
# First, do barycentric interpolation in the lateral direction for each interface level
fzk = np.dot(field.data.values[ti, k, node_ids], bcoords)
fzkp1 = np.dot(field.data.values[ti, k + 1, node_ids], bcoords)
# Then, do piecewise linear interpolation in the vertical direction
zk = field.grid.z.values[k]
zkp1 = field.grid.z.values[k + 1]
return (fzk * (zkp1 - z) + fzkp1 * (z - zk)) / (zkp1 - zk) # Linear interpolation in the vertical direction