microstructure-tpw 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- microstructure_tpw-0.3.0.dist-info/METADATA +234 -0
- microstructure_tpw-0.3.0.dist-info/RECORD +119 -0
- microstructure_tpw-0.3.0.dist-info/WHEEL +5 -0
- microstructure_tpw-0.3.0.dist-info/entry_points.txt +7 -0
- microstructure_tpw-0.3.0.dist-info/licenses/LICENSE +674 -0
- microstructure_tpw-0.3.0.dist-info/top_level.txt +1 -0
- odas_tpw/__init__.py +18 -0
- odas_tpw/chi/__init__.py +48 -0
- odas_tpw/chi/batchelor.py +189 -0
- odas_tpw/chi/chi.py +857 -0
- odas_tpw/chi/fp07.py +649 -0
- odas_tpw/chi/l2_chi.py +153 -0
- odas_tpw/chi/l3_chi.py +388 -0
- odas_tpw/chi/l4_chi.py +391 -0
- odas_tpw/config_base.py +423 -0
- odas_tpw/perturb/__init__.py +18 -0
- odas_tpw/perturb/adcp.py +274 -0
- odas_tpw/perturb/atomic_io.py +47 -0
- odas_tpw/perturb/binning.py +761 -0
- odas_tpw/perturb/cli.py +591 -0
- odas_tpw/perturb/combo.py +346 -0
- odas_tpw/perturb/config.py +1046 -0
- odas_tpw/perturb/ctd.py +424 -0
- odas_tpw/perturb/diag/__init__.py +12 -0
- odas_tpw/perturb/diag/_common.py +140 -0
- odas_tpw/perturb/diag/chi.py +42 -0
- odas_tpw/perturb/diag/cli.py +67 -0
- odas_tpw/perturb/diag/data.py +662 -0
- odas_tpw/perturb/diag/epsilon.py +45 -0
- odas_tpw/perturb/diag/inspector.py +342 -0
- odas_tpw/perturb/diag/mixing.py +94 -0
- odas_tpw/perturb/diag/render.py +543 -0
- odas_tpw/perturb/discover.py +40 -0
- odas_tpw/perturb/fp07_cal.py +354 -0
- odas_tpw/perturb/gps.py +458 -0
- odas_tpw/perturb/hotel.py +572 -0
- odas_tpw/perturb/logging_setup.py +181 -0
- odas_tpw/perturb/merge.py +320 -0
- odas_tpw/perturb/mk_sections.py +310 -0
- odas_tpw/perturb/netcdf_schema.py +520 -0
- odas_tpw/perturb/pipeline.py +2654 -0
- odas_tpw/perturb/plot/__init__.py +15 -0
- odas_tpw/perturb/plot/cli.py +107 -0
- odas_tpw/perturb/plot/diagnostics.py +195 -0
- odas_tpw/perturb/plot/eps_chi.py +524 -0
- odas_tpw/perturb/plot/figure.py +679 -0
- odas_tpw/perturb/plot/gamma_scaling.py +1097 -0
- odas_tpw/perturb/plot/grid.py +112 -0
- odas_tpw/perturb/plot/layout.py +361 -0
- odas_tpw/perturb/plot/overview.py +547 -0
- odas_tpw/perturb/plot/presets/eps-chi.yaml +16 -0
- odas_tpw/perturb/plot/presets/profiles.yaml +32 -0
- odas_tpw/perturb/plot/presets/scalar.yaml +21 -0
- odas_tpw/perturb/plot/profiles.py +652 -0
- odas_tpw/perturb/plot/scalar.py +391 -0
- odas_tpw/perturb/plot/sections.py +506 -0
- odas_tpw/perturb/plot/xaxis.py +396 -0
- odas_tpw/perturb/qc_gate.py +177 -0
- odas_tpw/perturb/qc_rules.py +373 -0
- odas_tpw/perturb/resolve.py +306 -0
- odas_tpw/perturb/seawater.py +76 -0
- odas_tpw/perturb/speed.py +14 -0
- odas_tpw/perturb/trim.py +313 -0
- odas_tpw/processing/__init__.py +62 -0
- odas_tpw/processing/bottom.py +215 -0
- odas_tpw/processing/chi_combine.py +300 -0
- odas_tpw/processing/ct_align.py +172 -0
- odas_tpw/processing/epsilon_combine.py +210 -0
- odas_tpw/processing/mixing.py +630 -0
- odas_tpw/processing/thorpe.py +458 -0
- odas_tpw/processing/top_trim.py +274 -0
- odas_tpw/pyturb/__init__.py +3 -0
- odas_tpw/pyturb/__main__.py +5 -0
- odas_tpw/pyturb/_compat.py +204 -0
- odas_tpw/pyturb/_profind.py +124 -0
- odas_tpw/pyturb/bin.py +113 -0
- odas_tpw/pyturb/cli.py +175 -0
- odas_tpw/pyturb/eps.py +353 -0
- odas_tpw/pyturb/merge.py +101 -0
- odas_tpw/pyturb/p2nc.py +76 -0
- odas_tpw/rsi/__init__.py +31 -0
- odas_tpw/rsi/adapter.py +314 -0
- odas_tpw/rsi/bench.py +904 -0
- odas_tpw/rsi/binning.py +193 -0
- odas_tpw/rsi/channels.py +376 -0
- odas_tpw/rsi/chi_io.py +980 -0
- odas_tpw/rsi/cli.py +1411 -0
- odas_tpw/rsi/combine.py +120 -0
- odas_tpw/rsi/config.py +126 -0
- odas_tpw/rsi/config_patch.py +790 -0
- odas_tpw/rsi/convert.py +651 -0
- odas_tpw/rsi/deconvolve.py +119 -0
- odas_tpw/rsi/diss_look.py +343 -0
- odas_tpw/rsi/dissipation.py +669 -0
- odas_tpw/rsi/helpers.py +527 -0
- odas_tpw/rsi/mixing_look.py +509 -0
- odas_tpw/rsi/p_file.py +771 -0
- odas_tpw/rsi/pipeline.py +924 -0
- odas_tpw/rsi/profile.py +624 -0
- odas_tpw/rsi/quick_look.py +758 -0
- odas_tpw/rsi/sensor_inventory.py +684 -0
- odas_tpw/rsi/shear_noise.py +128 -0
- odas_tpw/rsi/speed.py +221 -0
- odas_tpw/rsi/vehicle.py +74 -0
- odas_tpw/rsi/viewer_base.py +1071 -0
- odas_tpw/rsi/window.py +459 -0
- odas_tpw/scor160/__init__.py +36 -0
- odas_tpw/scor160/cli.py +242 -0
- odas_tpw/scor160/compare.py +484 -0
- odas_tpw/scor160/despike.py +227 -0
- odas_tpw/scor160/goodman.py +288 -0
- odas_tpw/scor160/io.py +690 -0
- odas_tpw/scor160/l2.py +311 -0
- odas_tpw/scor160/l3.py +279 -0
- odas_tpw/scor160/l4.py +850 -0
- odas_tpw/scor160/nasmyth.py +208 -0
- odas_tpw/scor160/ocean.py +287 -0
- odas_tpw/scor160/profile.py +231 -0
- odas_tpw/scor160/spectral.py +482 -0
odas_tpw/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# odas-tpw: Ocean microstructure turbulence processing (ODAS heritage)
|
|
2
|
+
#
|
|
3
|
+
# Subpackages:
|
|
4
|
+
# rsi — Rockland Scientific instrument I/O (.p files, NetCDF, profiles)
|
|
5
|
+
# chi — Chi (thermal variance dissipation) calculation
|
|
6
|
+
# scor160 — ATOMIX shear-probe benchmark processing (L1-L4)
|
|
7
|
+
# processing — Instrument-agnostic algorithms (top_trim, bottom, ct_align, etc.)
|
|
8
|
+
# perturb — Full processing pipeline (trim, merge, calibrate, compute, bin)
|
|
9
|
+
|
|
10
|
+
from importlib.metadata import PackageNotFoundError
|
|
11
|
+
from importlib.metadata import version as _pkg_version
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
__version__ = _pkg_version("microstructure-tpw")
|
|
15
|
+
except PackageNotFoundError: # pragma: no cover - running from an uninstalled source tree
|
|
16
|
+
__version__ = "0.0.0+unknown"
|
|
17
|
+
|
|
18
|
+
__all__ = ["__version__"]
|
odas_tpw/chi/__init__.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Chi (thermal variance dissipation) calculations
|
|
2
|
+
#
|
|
3
|
+
# Computes chi from temperature microstructure spectra using
|
|
4
|
+
# Batchelor/Kraichnan spectral fitting (Method 2) or from known
|
|
5
|
+
# epsilon via Dillon & Caldwell (Method 1).
|
|
6
|
+
|
|
7
|
+
from odas_tpw.chi.batchelor import (
|
|
8
|
+
KAPPA_T,
|
|
9
|
+
Q_BATCHELOR,
|
|
10
|
+
Q_KRAICHNAN,
|
|
11
|
+
batchelor_grad,
|
|
12
|
+
batchelor_kB,
|
|
13
|
+
kraichnan_grad,
|
|
14
|
+
)
|
|
15
|
+
from odas_tpw.chi.fp07 import (
|
|
16
|
+
default_tau_model,
|
|
17
|
+
fp07_double_pole,
|
|
18
|
+
fp07_tau,
|
|
19
|
+
fp07_tau_batch,
|
|
20
|
+
fp07_transfer,
|
|
21
|
+
fp07_transfer_batch,
|
|
22
|
+
)
|
|
23
|
+
from odas_tpw.chi.l2_chi import L2ChiData, L2ChiParams, process_l2_chi
|
|
24
|
+
from odas_tpw.chi.l3_chi import L3ChiData, process_l3_chi
|
|
25
|
+
from odas_tpw.chi.l4_chi import L4ChiData, process_l4_chi_epsilon, process_l4_chi_fit
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"KAPPA_T",
|
|
29
|
+
"Q_BATCHELOR",
|
|
30
|
+
"Q_KRAICHNAN",
|
|
31
|
+
"L2ChiData",
|
|
32
|
+
"L2ChiParams",
|
|
33
|
+
"L3ChiData",
|
|
34
|
+
"L4ChiData",
|
|
35
|
+
"batchelor_grad",
|
|
36
|
+
"batchelor_kB",
|
|
37
|
+
"default_tau_model",
|
|
38
|
+
"fp07_double_pole",
|
|
39
|
+
"fp07_tau",
|
|
40
|
+
"fp07_tau_batch",
|
|
41
|
+
"fp07_transfer",
|
|
42
|
+
"fp07_transfer_batch",
|
|
43
|
+
"kraichnan_grad",
|
|
44
|
+
"process_l2_chi",
|
|
45
|
+
"process_l3_chi",
|
|
46
|
+
"process_l4_chi_epsilon",
|
|
47
|
+
"process_l4_chi_fit",
|
|
48
|
+
]
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Mar-2026, Claude and Pat Welch, pat@mousebrains.com
|
|
2
|
+
"""Batchelor and Kraichnan temperature gradient spectra.
|
|
3
|
+
|
|
4
|
+
References
|
|
5
|
+
----------
|
|
6
|
+
Dillon, T.M. and D.R. Caldwell, 1980: The Batchelor spectrum and dissipation
|
|
7
|
+
in the upper ocean. J. Geophys. Res., 85, 1910-1916.
|
|
8
|
+
Bogucki, D., J.A. Domaradzki, and P.K. Yeung, 1997: Direct numerical
|
|
9
|
+
simulations of passive scalars with Pr > 1 advected by turbulent flow.
|
|
10
|
+
J. Fluid Mech., 343, 111-130.
|
|
11
|
+
Oakey, N.S., 1982: Determination of the rate of dissipation of turbulent
|
|
12
|
+
energy. J. Phys. Oceanogr., 12, 256-271.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
import numpy.typing as npt
|
|
17
|
+
from scipy.special import erfc
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Constants
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
# Thermal diffusivity of seawater [m^2/s] at a ~15 degC reference — the BACKWARD-
|
|
24
|
+
# COMPATIBLE FALLBACK only. The production chi pipeline now threads a per-window,
|
|
25
|
+
# temperature-dependent kappa_T(T,S,P) (Sharqawy-2010 conductivity + gsw rho/cp,
|
|
26
|
+
# see scor160/ocean.py:kappa_T) from the L3 stage through chi.py/l4_chi.py. That
|
|
27
|
+
# T-dependence spans ~1.39e-7 at -1 degC to ~1.51e-7 at 32 degC; since
|
|
28
|
+
# chi = 6*kappa_T*I and epsilon_T = (2*pi*kB)^4*nu*kappa_T^2, using it removed a
|
|
29
|
+
# chi bias that ran from ~-1% (cold) to ~+8% (warm) against this fixed value.
|
|
30
|
+
# This constant remains the default for the chi.py functions' `kappa_T=` argument
|
|
31
|
+
# so a caller that does not supply a per-window value still runs.
|
|
32
|
+
# See docs/chi_mathematics.md Section 11.
|
|
33
|
+
KAPPA_T = 1.4e-7
|
|
34
|
+
Q_BATCHELOR = 3.7 # Batchelor universal constant (Oakey 1982)
|
|
35
|
+
Q_KRAICHNAN = 5.26 # Kraichnan universal constant (Bogucki et al. 1997)
|
|
36
|
+
_SQ6Q_KRAICHNAN = np.sqrt(6 * Q_KRAICHNAN) # Precomputed for kraichnan_grad
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# Batchelor wavenumber
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def batchelor_kB(
|
|
45
|
+
epsilon: float | np.ndarray, nu: float, kappa_T: float = KAPPA_T
|
|
46
|
+
) -> float | np.ndarray:
|
|
47
|
+
"""Batchelor wavenumber [cpm].
|
|
48
|
+
|
|
49
|
+
kB = (1/(2*pi)) * (epsilon / (nu * kappa_T^2))^(1/4)
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
epsilon : float or array
|
|
54
|
+
TKE dissipation rate [W/kg].
|
|
55
|
+
nu : float
|
|
56
|
+
Kinematic viscosity [m^2/s].
|
|
57
|
+
kappa_T : float
|
|
58
|
+
Thermal diffusivity [m^2/s].
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
kB : float or array
|
|
63
|
+
Batchelor wavenumber [cpm].
|
|
64
|
+
"""
|
|
65
|
+
return (1 / (2 * np.pi)) * (epsilon / (nu * kappa_T**2)) ** 0.25
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
# Batchelor spectrum (Dillon & Caldwell 1980)
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def batchelor_nondim(alpha: npt.ArrayLike) -> np.ndarray:
|
|
74
|
+
"""Non-dimensional Batchelor gradient spectrum f_B(alpha).
|
|
75
|
+
|
|
76
|
+
f(alpha) = alpha * [exp(-alpha^2/2) - alpha * sqrt(pi/2) * erfc(alpha/sqrt(2))]
|
|
77
|
+
|
|
78
|
+
Dillon & Caldwell 1980, eq. 3. Integral over [0, inf) = 1/3.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
alpha : array_like
|
|
83
|
+
Non-dimensional wavenumber: alpha = sqrt(2*q) * k / kB.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
f : ndarray
|
|
88
|
+
"""
|
|
89
|
+
alpha = np.asarray(alpha, dtype=np.float64)
|
|
90
|
+
return alpha * (np.exp(-(alpha**2) / 2) - alpha * np.sqrt(np.pi / 2) * erfc(alpha / np.sqrt(2)))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def batchelor_grad(
|
|
94
|
+
k: npt.ArrayLike,
|
|
95
|
+
kB: float | np.ndarray,
|
|
96
|
+
chi: float,
|
|
97
|
+
kappa_T: float = KAPPA_T,
|
|
98
|
+
q: float = Q_BATCHELOR,
|
|
99
|
+
) -> np.ndarray:
|
|
100
|
+
"""Batchelor temperature gradient spectrum [(K/m)^2 / cpm].
|
|
101
|
+
|
|
102
|
+
S(k) = sqrt(q/2) * chi / (kB * kappa_T) * f(alpha)
|
|
103
|
+
where alpha = sqrt(2*q) * k / kB
|
|
104
|
+
|
|
105
|
+
Dillon & Caldwell 1980, eq. 1. k and kB in cpm.
|
|
106
|
+
Integrates to chi / (6 * kappa_T).
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
k : array_like
|
|
111
|
+
Wavenumber [cpm].
|
|
112
|
+
kB : float
|
|
113
|
+
Batchelor wavenumber [cpm].
|
|
114
|
+
chi : float
|
|
115
|
+
Thermal variance dissipation rate [K^2/s].
|
|
116
|
+
kappa_T : float
|
|
117
|
+
Thermal diffusivity [m^2/s].
|
|
118
|
+
q : float
|
|
119
|
+
Universal constant.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
S : ndarray
|
|
124
|
+
Gradient spectrum [(K/m)^2 / cpm].
|
|
125
|
+
"""
|
|
126
|
+
k = np.asarray(k, dtype=np.float64)
|
|
127
|
+
# Mirror kraichnan_grad: a degenerate kB (0 / NaN) otherwise yields
|
|
128
|
+
# NaN-with-warnings; sanitize to 0 so the spectrum stays finite (#16).
|
|
129
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
130
|
+
alpha = np.sqrt(2 * q) * k / kB
|
|
131
|
+
f = batchelor_nondim(alpha)
|
|
132
|
+
S = np.sqrt(q / 2) * chi / (kB * kappa_T) * f
|
|
133
|
+
return np.where(np.isfinite(S), S, 0.0)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# ---------------------------------------------------------------------------
|
|
137
|
+
# Kraichnan spectrum (Bogucki et al. 1997)
|
|
138
|
+
# ---------------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def kraichnan_grad(
|
|
142
|
+
k: npt.ArrayLike,
|
|
143
|
+
kB: float | np.ndarray,
|
|
144
|
+
chi: float,
|
|
145
|
+
kappa_T: float = KAPPA_T,
|
|
146
|
+
q: float = Q_KRAICHNAN,
|
|
147
|
+
) -> np.ndarray:
|
|
148
|
+
"""Kraichnan temperature gradient spectrum [(K/m)^2 / cpm].
|
|
149
|
+
|
|
150
|
+
S(k) = chi*q / (kappa_T*kB^2) * k * exp(-sqrt(6q)*y)
|
|
151
|
+
where y = k / kB.
|
|
152
|
+
|
|
153
|
+
This is the one-dimensional (along-path) gradient spectrum obtained by
|
|
154
|
+
applying the isotropic transform G1(k1) = k1^2 * int_{k1}^inf E(k)/k dk
|
|
155
|
+
to the three-dimensional Kraichnan scalar spectrum of Bogucki et al.
|
|
156
|
+
1997, eq. 11. The transform evaluates in closed form to the simple
|
|
157
|
+
exponential above (the same form as Peterson & Fer 2014, eq. 8).
|
|
158
|
+
Integrates to chi / (6 * kappa_T); peaks at k = kB / sqrt(6q).
|
|
159
|
+
|
|
160
|
+
Key difference from Batchelor: exponential rolloff instead of Gaussian,
|
|
161
|
+
which fits DNS and observed high-Prandtl-number spectra better
|
|
162
|
+
(Bogucki et al. 1997).
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
k : array_like
|
|
167
|
+
Wavenumber [cpm].
|
|
168
|
+
kB : float
|
|
169
|
+
Batchelor wavenumber [cpm].
|
|
170
|
+
chi : float
|
|
171
|
+
Thermal variance dissipation rate [K^2/s].
|
|
172
|
+
kappa_T : float
|
|
173
|
+
Thermal diffusivity [m^2/s].
|
|
174
|
+
q : float
|
|
175
|
+
Universal constant (default: 5.26).
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
S : ndarray
|
|
180
|
+
Gradient spectrum [(K/m)^2 / cpm].
|
|
181
|
+
"""
|
|
182
|
+
k = np.asarray(k, dtype=np.float64)
|
|
183
|
+
y = k / kB
|
|
184
|
+
sq6q = _SQ6Q_KRAICHNAN if q == Q_KRAICHNAN else np.sqrt(6 * q)
|
|
185
|
+
sq6q_y = sq6q * y
|
|
186
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
187
|
+
S = chi * q / (kappa_T * kB**2) * k * np.exp(-sq6q_y)
|
|
188
|
+
S = np.where(np.isfinite(S), S, 0.0)
|
|
189
|
+
return S
|