Skip to content

Commit c60aafb

Browse files
committed
Add module to compute nodal factor correction on amplitude and phase, and astronomical argument
1 parent 6bc2d10 commit c60aafb

1 file changed

Lines changed: 145 additions & 0 deletions

File tree

vtools/functions/ha_utils.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import numpy as np
2+
from utide.harmonics import FUV
3+
from utide._ut_constants import constit_index_dict
4+
from utide._time_conversion import _normalize_time
5+
6+
import pandas as pd
7+
8+
__all__=["nodal_factors"]
9+
10+
11+
def nodal_factors(
12+
t_dates,
13+
tref_date,
14+
constituents,
15+
lat_deg,
16+
nodal_linear_time=False,
17+
phase="Greenwich",
18+
):
19+
"""
20+
Compute UTide nodal factors F, nodal phase U (cycles),
21+
and astronomical argument V (cycles).
22+
23+
Parameters
24+
----------
25+
t_dates : array-like pandas.Timestamp or array-like of datetime
26+
Time in datetime.
27+
tref_date : datetime or pandas.Timestamp
28+
Reference date, used for nodal amp and phase correction calculations.
29+
Resulted nodal factors will be computed at this reference date if
30+
nodal_linear_time=True, otherwise nodal factors will be computed at t_dates.
31+
constituents : sequence[str]
32+
Constituent abbreviations, e.g. ["M2", "K1", "MK3", "MO3"].
33+
lat_deg : float
34+
Latitude in degrees.
35+
nodal_linear_time : bool
36+
Linearized nodal variation, check with tref_date for details.
37+
phase : {"Greenwich", "linear_time", "raw"}
38+
Tide Greenwich equilibrium phase correction convention.
39+
Greenwich: Greenwich equilibrium argument computed on all t_dates
40+
linear_time: single Greenwich equilibrium argument computed at tref_date (UT) and applied to all t_dates
41+
raw: no Greenwich equilibrium argument applied.
42+
43+
Returns
44+
-------
45+
F : ndarray (nt, nc)
46+
Nodal amplitude factors.
47+
U : ndarray (nt, nc)
48+
Nodal phase corrections (cycles).
49+
V : ndarray (nt, nc)
50+
Astronomical arguments (cycles).
51+
"""
52+
## check input t_dates and tref_date are pandas.Timestamp or datetime
53+
if not (isinstance(t_dates, pd.Series) or isinstance(t_dates, pd.DatetimeIndex) or isinstance(t_dates, pd.Timestamp)):
54+
raise ValueError("t_dates must be a pandas Series, DatetimeIndex, or Timestamp, or a datetime object")
55+
if not (isinstance(tref_date, pd.Timestamp) ):
56+
raise ValueError("tref_date must be a pandas Timestamp or datetime object")
57+
# Convert t_dates and tref_date to days since epoch
58+
t_days = _normalize_time(t_dates)
59+
tref_days = _normalize_time(tref_date)
60+
61+
nodal = True
62+
63+
return _fuv(
64+
t_days,
65+
tref_days,
66+
constituents,
67+
lat_deg,
68+
nodal=nodal,
69+
nodal_linear_time=nodal_linear_time,
70+
phase=phase
71+
)
72+
73+
74+
def _fuv(
75+
t_days,
76+
tref_days,
77+
constituents,
78+
lat_deg,
79+
*,
80+
nodal=True,
81+
nodal_linear_time=False,
82+
phase="Greenwich",
83+
):
84+
"""
85+
Compute nodal factors F, nodal phase U (cycles),
86+
and astronomical argument V (cycles).
87+
88+
Parameters
89+
----------
90+
t_days : array-like
91+
Time in days since epoch.
92+
tref_days : float
93+
Reference time in days since epoch.
94+
constituents : sequence[str]
95+
Constituent abbreviations, e.g. ["M2", "K1", "MK3", "MO3"].
96+
lat_deg : float
97+
Latitude in degrees.
98+
nodal : bool
99+
Apply nodal/satellite corrections.
100+
nodal_linear_time : bool
101+
Linearized nodal variation.
102+
phase : {"Greenwich", "linear_time", "raw"}
103+
Phase convention.
104+
105+
Returns
106+
-------
107+
F : ndarray (nt, nc)
108+
Nodal amplitude factors.
109+
U : ndarray (nt, nc)
110+
Nodal phase corrections (cycles).
111+
V : ndarray (nt, nc)
112+
Astronomical arguments (cycles).
113+
"""
114+
115+
if phase not in {"Greenwich", "linear_time", "raw"}:
116+
raise ValueError(f"Invalid phase={phase!r}")
117+
118+
try:
119+
lind = np.array([constit_index_dict[c] for c in constituents], dtype=int)
120+
except KeyError as e:
121+
raise KeyError(f"Unknown tide constituent {e.args[0]!r}") from None
122+
123+
ngflgs = np.zeros(4, dtype=bool)
124+
125+
if not nodal:
126+
ngflgs[1] = True
127+
elif nodal_linear_time:
128+
ngflgs[0] = True
129+
130+
if phase == "raw":
131+
ngflgs[3] = True
132+
elif phase == "linear_time":
133+
ngflgs[2] = True
134+
135+
t_days = np.asarray(t_days, dtype=float)
136+
137+
F, U, V = FUV(
138+
t_days,
139+
float(tref_days),
140+
lind,
141+
float(lat_deg),
142+
ngflgs,
143+
)
144+
145+
return F, U, V

0 commit comments

Comments
 (0)