jerlov 0.7.0__tar.gz → 0.7.2__tar.gz
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.
- {jerlov-0.7.0/jerlov.egg-info → jerlov-0.7.2}/PKG-INFO +6 -3
- {jerlov-0.7.0 → jerlov-0.7.2}/README.md +5 -2
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/__init__.py +1 -1
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/backscattering.py +8 -1
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/scene.py +4 -2
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/water.py +8 -1
- {jerlov-0.7.0 → jerlov-0.7.2/jerlov.egg-info}/PKG-INFO +6 -3
- {jerlov-0.7.0 → jerlov-0.7.2}/pyproject.toml +1 -1
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_api.py +30 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_backscattering.py +12 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_quoted_figures.py +108 -1
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_scene.py +8 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/LICENSE +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/NOTICE +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/_data.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/colour.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/__init__.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/austin1986_kd.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/austin1986_model.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/boss2001_chi.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/cie1931_2deg_cmf.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/cie_d65.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/jerlov1968_kd.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/jerlov1968_total_irradiance.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/jerlov1976_kd.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/paulson1977_shortwave.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/petzold1972_stations.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/petzold1972_vsf.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/smart2007_b_from_c.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/solonenko2015_iop.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/williamson2022_aw.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/williamson2022_iop.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/williamson2022_measured.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/data/williamson2023_depth.csv +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/petzold.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/py.typed +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/shortwave.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov/sources.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov.egg-info/SOURCES.txt +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov.egg-info/dependency_links.txt +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov.egg-info/requires.txt +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/jerlov.egg-info/top_level.txt +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/setup.cfg +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_colour.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_depth.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_packaging.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_petzold.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_reproduces_papers.py +0 -0
- {jerlov-0.7.0 → jerlov-0.7.2}/tests/test_shortwave.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jerlov
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: Inherent optical properties of Jerlov water types, with provenance
|
|
5
5
|
Author: T. Ishibashi
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -62,7 +62,7 @@ w.a(550), w.b(550), w.c(550)
|
|
|
62
62
|
The same Jerlov water type has different coefficients in different papers, and
|
|
63
63
|
the differences are not small. Solonenko & Mobley (2015) obtained a and b by
|
|
64
64
|
inverting Kd; Williamson & Hollins (2022) measured them. At 510 nm their
|
|
65
|
-
scattering coefficients differ by up to a factor of
|
|
65
|
+
scattering coefficients differ by up to a factor of 3.8, at Jerlov III.
|
|
66
66
|
|
|
67
67
|
The equations differ too. Both papers use the scattering model of Haltrin
|
|
68
68
|
(1999), but with different constants: Haltrin's Eq. (6) gives a
|
|
@@ -333,9 +333,12 @@ python examples/from_one_measurement.py from an instrument reading
|
|
|
333
333
|
python examples/synthetic_underwater_images.py appearance at range and depth
|
|
334
334
|
python examples/solar_heating.py for ocean circulation models
|
|
335
335
|
python examples/what_an_eye_sees.py any spectral sensitivity
|
|
336
|
+
python examples/light_at_depth.py light through the depth profile
|
|
337
|
+
python examples/measured_scattering.py Petzold's measured bb/b
|
|
338
|
+
python examples/what_is_in_the_water.py absorption without the water
|
|
336
339
|
```
|
|
337
340
|
|
|
338
|
-
|
|
341
|
+
Eight scripts, each aimed at a different reader; `examples/README.md` says
|
|
339
342
|
which to start with. CI runs all of them on every push, so an example that has
|
|
340
343
|
stopped working is a failed build. Every one ends with the assumptions it
|
|
341
344
|
made.
|
|
@@ -37,7 +37,7 @@ w.a(550), w.b(550), w.c(550)
|
|
|
37
37
|
The same Jerlov water type has different coefficients in different papers, and
|
|
38
38
|
the differences are not small. Solonenko & Mobley (2015) obtained a and b by
|
|
39
39
|
inverting Kd; Williamson & Hollins (2022) measured them. At 510 nm their
|
|
40
|
-
scattering coefficients differ by up to a factor of
|
|
40
|
+
scattering coefficients differ by up to a factor of 3.8, at Jerlov III.
|
|
41
41
|
|
|
42
42
|
The equations differ too. Both papers use the scattering model of Haltrin
|
|
43
43
|
(1999), but with different constants: Haltrin's Eq. (6) gives a
|
|
@@ -308,9 +308,12 @@ python examples/from_one_measurement.py from an instrument reading
|
|
|
308
308
|
python examples/synthetic_underwater_images.py appearance at range and depth
|
|
309
309
|
python examples/solar_heating.py for ocean circulation models
|
|
310
310
|
python examples/what_an_eye_sees.py any spectral sensitivity
|
|
311
|
+
python examples/light_at_depth.py light through the depth profile
|
|
312
|
+
python examples/measured_scattering.py Petzold's measured bb/b
|
|
313
|
+
python examples/what_is_in_the_water.py absorption without the water
|
|
311
314
|
```
|
|
312
315
|
|
|
313
|
-
|
|
316
|
+
Eight scripts, each aimed at a different reader; `examples/README.md` says
|
|
314
317
|
which to start with. CI runs all of them on every push, so an example that has
|
|
315
318
|
stopped working is a failed build. Every one ends with the assumptions it
|
|
316
319
|
made.
|
|
@@ -67,7 +67,14 @@ def _amplitude(wavelength_nm, salinity_psu) -> np.ndarray:
|
|
|
67
67
|
f"salinity_psu must be a finite number, 0 or more, not "
|
|
68
68
|
f"{salinity_psu!r}"
|
|
69
69
|
)
|
|
70
|
-
|
|
70
|
+
wavelength = np.asarray(wavelength_nm, dtype=float)
|
|
71
|
+
if not np.all(np.isfinite(wavelength)) or np.any(wavelength <= 0):
|
|
72
|
+
# Zero gave inf and a negative wavelength NaN, each with nothing but
|
|
73
|
+
# a NumPy RuntimeWarning.
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"wavelength_nm must be a positive number, not {wavelength_nm!r}"
|
|
76
|
+
)
|
|
77
|
+
return (1.38 * (wavelength / 500.0) ** -4.32
|
|
71
78
|
* (1 + 0.3 * salinity / 37.0) * 1e-4)
|
|
72
79
|
|
|
73
80
|
|
|
@@ -195,10 +195,12 @@ class Scene:
|
|
|
195
195
|
"the water must carry both a and b; c = a + b drives the path"
|
|
196
196
|
)
|
|
197
197
|
self.water = water
|
|
198
|
-
|
|
198
|
+
# Copies, so that changing the caller's arrays afterwards cannot
|
|
199
|
+
# leave the wavelengths out of step with c, evaluated once below.
|
|
200
|
+
self.wavelengths = np.array(wavelengths, dtype=float)
|
|
199
201
|
if self.wavelengths.ndim != 1 or self.wavelengths.size == 0:
|
|
200
202
|
raise ValueError("wavelengths must be a non-empty 1-D array")
|
|
201
|
-
self.downwelling = np.
|
|
203
|
+
self.downwelling = np.array(downwelling, dtype=float)
|
|
202
204
|
if self.downwelling.shape != self.wavelengths.shape:
|
|
203
205
|
raise ValueError("downwelling must have the same shape as wavelengths")
|
|
204
206
|
if np.any(self.downwelling < 0):
|
|
@@ -240,6 +240,9 @@ class Water:
|
|
|
240
240
|
f"(available: {available})"
|
|
241
241
|
)
|
|
242
242
|
query = _as_array(wl)
|
|
243
|
+
# NaN < lo is False, so a NaN wavelength passed the range check and
|
|
244
|
+
# came back as NaN, warned about the last sample of the table.
|
|
245
|
+
_require_number(query, "wavelength")
|
|
243
246
|
lo, hi = self.range_nm
|
|
244
247
|
if np.any(query < lo) or np.any(query > hi):
|
|
245
248
|
raise ValueError(
|
|
@@ -591,7 +594,8 @@ def descend(surface_water_type: str, depth_m: float, wavelengths, *,
|
|
|
591
594
|
f"{deepest:g} m, so there is no type to descend through to "
|
|
592
595
|
f"{depth_m:g} m"
|
|
593
596
|
)
|
|
594
|
-
|
|
597
|
+
# A copy: it is frozen below, and the caller's array must not be.
|
|
598
|
+
query = np.array(wavelengths, dtype=float, ndmin=1)
|
|
595
599
|
optical_depth = np.zeros_like(query)
|
|
596
600
|
layers: list[tuple[float, float, str]] = []
|
|
597
601
|
kd: dict[str, np.ndarray] = {}
|
|
@@ -723,6 +727,8 @@ def kd_spectrum(kd, wavelength_nm: float, at):
|
|
|
723
727
|
)
|
|
724
728
|
wavelength_nm = float(wavelength_nm)
|
|
725
729
|
query = _as_array(at)
|
|
730
|
+
_require_number(wavelength_nm, "wavelength_nm")
|
|
731
|
+
_require_number(query, "at")
|
|
726
732
|
for value, label in ((wavelength_nm, "wavelength_nm"), (query, "at")):
|
|
727
733
|
if np.any(np.asarray(value) < lo) or np.any(np.asarray(value) > hi):
|
|
728
734
|
raise ValueError(f"{label} outside the model range ({lo:g}-{hi:g} nm)")
|
|
@@ -800,6 +806,7 @@ def b_from_c(c, wavelength_nm, *, bw, cw, bound: str = "average"):
|
|
|
800
806
|
if bound not in ratios:
|
|
801
807
|
raise ValueError(f"bound must be one of {sorted(ratios)}")
|
|
802
808
|
query = _as_array(wavelength_nm)
|
|
809
|
+
_require_number(query, "wavelength_nm")
|
|
803
810
|
if np.any(query < wl[0]) or np.any(query > wl[-1]):
|
|
804
811
|
raise ValueError(
|
|
805
812
|
f"wavelength outside the measured range ({wl[0]:g}-{wl[-1]:g} nm)"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jerlov
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: Inherent optical properties of Jerlov water types, with provenance
|
|
5
5
|
Author: T. Ishibashi
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -62,7 +62,7 @@ w.a(550), w.b(550), w.c(550)
|
|
|
62
62
|
The same Jerlov water type has different coefficients in different papers, and
|
|
63
63
|
the differences are not small. Solonenko & Mobley (2015) obtained a and b by
|
|
64
64
|
inverting Kd; Williamson & Hollins (2022) measured them. At 510 nm their
|
|
65
|
-
scattering coefficients differ by up to a factor of
|
|
65
|
+
scattering coefficients differ by up to a factor of 3.8, at Jerlov III.
|
|
66
66
|
|
|
67
67
|
The equations differ too. Both papers use the scattering model of Haltrin
|
|
68
68
|
(1999), but with different constants: Haltrin's Eq. (6) gives a
|
|
@@ -333,9 +333,12 @@ python examples/from_one_measurement.py from an instrument reading
|
|
|
333
333
|
python examples/synthetic_underwater_images.py appearance at range and depth
|
|
334
334
|
python examples/solar_heating.py for ocean circulation models
|
|
335
335
|
python examples/what_an_eye_sees.py any spectral sensitivity
|
|
336
|
+
python examples/light_at_depth.py light through the depth profile
|
|
337
|
+
python examples/measured_scattering.py Petzold's measured bb/b
|
|
338
|
+
python examples/what_is_in_the_water.py absorption without the water
|
|
336
339
|
```
|
|
337
340
|
|
|
338
|
-
|
|
341
|
+
Eight scripts, each aimed at a different reader; `examples/README.md` says
|
|
339
342
|
which to start with. CI runs all of them on every push, so an example that has
|
|
340
343
|
stopped working is a failed build. Every one ends with the assumptions it
|
|
341
344
|
made.
|
|
@@ -588,3 +588,33 @@ def test_c_warns_once_for_a_wavelength_flagged_in_both_a_and_b():
|
|
|
588
588
|
assert messages[0].startswith("c for Jerlov 3C")
|
|
589
589
|
assert "a missing at 675 nm" in messages[0]
|
|
590
590
|
assert "b reconstructed at 675 nm" in messages[0]
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
# -- 0.7.2: inputs that slipped through -------------------------------------
|
|
594
|
+
|
|
595
|
+
@pytest.mark.parametrize("call", [
|
|
596
|
+
lambda: jerlov.water("III").a(float("nan")),
|
|
597
|
+
lambda: jerlov.water("III").c([500.0, float("nan")]),
|
|
598
|
+
lambda: jerlov.water("I", source="jerlov1976").kd(float("nan")),
|
|
599
|
+
lambda: jerlov.water("III", source="solonenko2015").kd_hydrolight(
|
|
600
|
+
float("nan")),
|
|
601
|
+
lambda: jerlov.kd_spectrum(0.06, 490.0, float("nan")),
|
|
602
|
+
lambda: jerlov.kd_spectrum(0.06, float("nan"), 500.0),
|
|
603
|
+
lambda: jerlov.b_from_c(0.5, float("nan"), bw=0.002, cw=0.066),
|
|
604
|
+
])
|
|
605
|
+
def test_a_wavelength_that_is_not_a_number_is_refused(call):
|
|
606
|
+
"""NaN < lo is False, so NaN passed the range check, came back as NaN,
|
|
607
|
+
and warned about the last sample of the table instead."""
|
|
608
|
+
with warnings.catch_warnings():
|
|
609
|
+
warnings.simplefilter("error") # and no misleading warning
|
|
610
|
+
with pytest.raises(ValueError, match="NaN"):
|
|
611
|
+
call()
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def test_descend_leaves_the_callers_array_alone():
|
|
615
|
+
wl = np.array([450.0, 550.0])
|
|
616
|
+
d = jerlov.descend("II", 30.0, wl)
|
|
617
|
+
assert wl.flags.writeable
|
|
618
|
+
wl[0] = 999.0
|
|
619
|
+
assert d.wavelengths[0] == 450.0
|
|
620
|
+
assert not d.wavelengths.flags.writeable
|
|
@@ -216,3 +216,15 @@ def test_a_salinity_that_is_not_one_is_refused():
|
|
|
216
216
|
with pytest.raises(ValueError, match="salinity_psu"):
|
|
217
217
|
call(bad)
|
|
218
218
|
jerlov.pure_water_vsf(120.0, 532.0, 0.0) # fresh water is fine
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def test_a_wavelength_that_is_not_one_is_refused():
|
|
222
|
+
for bad in (0.0, -500.0, float("nan"), float("inf")):
|
|
223
|
+
for call in (lambda w: jerlov.pure_water_vsf(120.0, w),
|
|
224
|
+
lambda w: jerlov.pure_water_backscattering(w),
|
|
225
|
+
lambda w: jerlov.pure_water_scattering(w),
|
|
226
|
+
lambda w: jerlov.bb_from_vsf(0.0021, 140.0, w)):
|
|
227
|
+
with warnings.catch_warnings():
|
|
228
|
+
warnings.simplefilter("error")
|
|
229
|
+
with pytest.raises(ValueError, match="wavelength_nm"):
|
|
230
|
+
call(bad)
|
|
@@ -37,7 +37,7 @@ def quiet():
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def test_scattering_at_510nm_differs_by_the_stated_factor():
|
|
40
|
-
"""
|
|
40
|
+
"""sources_disagree.py says 3.8 for Jerlov III."""
|
|
41
41
|
with quiet():
|
|
42
42
|
warnings.simplefilter("ignore")
|
|
43
43
|
measured = float(jerlov.water("III").b(510))
|
|
@@ -45,6 +45,30 @@ def test_scattering_at_510nm_differs_by_the_stated_factor():
|
|
|
45
45
|
assert inverted / measured == pytest.approx(3.8, abs=0.05)
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
@source_tree
|
|
49
|
+
def test_the_readme_states_the_largest_disagreement_at_510nm():
|
|
50
|
+
"""The README said "up to a factor of 2.6" while this test's docstring
|
|
51
|
+
claimed it said 3.8; nothing read the README, so nothing noticed."""
|
|
52
|
+
from jerlov.sources import SOURCES
|
|
53
|
+
|
|
54
|
+
readme = (ROOT / "README.md").read_text()
|
|
55
|
+
match = re.search(r"differ by up to a factor of ([\d.]+), at Jerlov (\w+)",
|
|
56
|
+
readme)
|
|
57
|
+
assert match, "the README no longer states the factor at 510 nm"
|
|
58
|
+
common = set(SOURCES["williamson2022"].water_types) & set(
|
|
59
|
+
SOURCES["solonenko2015"].water_types)
|
|
60
|
+
with quiet():
|
|
61
|
+
warnings.simplefilter("ignore")
|
|
62
|
+
factors = {}
|
|
63
|
+
for t in common:
|
|
64
|
+
one = float(jerlov.water(t).b(510))
|
|
65
|
+
other = float(jerlov.water(t, source="solonenko2015").b(510))
|
|
66
|
+
factors[t] = max(one, other) / min(one, other)
|
|
67
|
+
worst = max(factors, key=factors.get)
|
|
68
|
+
assert worst == match.group(2)
|
|
69
|
+
assert factors[worst] == pytest.approx(float(match.group(1)), abs=0.05)
|
|
70
|
+
|
|
71
|
+
|
|
48
72
|
def test_the_disagreement_does_not_run_one_way():
|
|
49
73
|
"""sources_disagree.py claims Jerlov IB goes the other direction."""
|
|
50
74
|
with quiet():
|
|
@@ -263,3 +287,86 @@ def test_DATA_md_section_13_states_where_the_coastal_profiles_end():
|
|
|
263
287
|
for t, depth in (("3C", 70.5), ("9C", 10.5), ("5C", 20.5), ("7C", 20.5)):
|
|
264
288
|
with pytest.raises(jerlov.MissingQuantityError):
|
|
265
289
|
jerlov.descend(t, depth, 500.0)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def test_DATA_md_section_20_on_the_measurements_at_715_nm():
|
|
293
|
+
"""1.004 with no spread for 1C, 3C, 5C; 1.018 for III; 14 to 16 percent
|
|
294
|
+
above the fit, which is aw there."""
|
|
295
|
+
import numpy as np
|
|
296
|
+
|
|
297
|
+
excess = []
|
|
298
|
+
for t in ("III", "1C", "3C", "5C"):
|
|
299
|
+
m = jerlov.measured_points(t, "a")
|
|
300
|
+
k = int(np.where(m.wavelengths == 715.0)[0][0])
|
|
301
|
+
if t == "III":
|
|
302
|
+
assert m.values[k] == pytest.approx(1.018, abs=0.0005)
|
|
303
|
+
else:
|
|
304
|
+
assert m.values[k] == 1.004
|
|
305
|
+
assert m.std_dev[k] < 1e-12
|
|
306
|
+
with warnings.catch_warnings():
|
|
307
|
+
warnings.simplefilter("ignore", jerlov.ProvenanceWarning)
|
|
308
|
+
fitted = jerlov.water(t).a(715.0)
|
|
309
|
+
assert fitted == pytest.approx(jerlov.pure_water_absorption(715.0),
|
|
310
|
+
rel=0.01)
|
|
311
|
+
excess.append(100 * (m.values[k] / fitted - 1))
|
|
312
|
+
assert 13.5 < min(excess) and max(excess) < 16.0
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def test_examples_README_figures_for_the_depth_profile():
|
|
316
|
+
"""3C receives 530 times more light at 60 m, I a third less; the 1
|
|
317
|
+
percent level of I rises from 197 to 133 m (all at 490 nm)."""
|
|
318
|
+
import math
|
|
319
|
+
|
|
320
|
+
def one_kd(t, z):
|
|
321
|
+
return math.exp(-jerlov.water(t, source="jerlov1976").kd(490.0) * z)
|
|
322
|
+
|
|
323
|
+
ratio_3c = jerlov.descend("3C", 60.0, 490.0).transmittance / one_kd("3C", 60.0)
|
|
324
|
+
ratio_i = jerlov.descend("I", 60.0, 490.0).transmittance / one_kd("I", 60.0)
|
|
325
|
+
assert round(ratio_3c, -1) == 530
|
|
326
|
+
assert ratio_i == pytest.approx(2 / 3, abs=0.02)
|
|
327
|
+
|
|
328
|
+
def depth_of_one_percent(t, layered):
|
|
329
|
+
for z in [k / 2 for k in range(1, 401)]:
|
|
330
|
+
t_z = (jerlov.descend(t, z, 490.0).transmittance if layered
|
|
331
|
+
else one_kd(t, z))
|
|
332
|
+
if t_z <= 0.01:
|
|
333
|
+
return z
|
|
334
|
+
|
|
335
|
+
assert depth_of_one_percent("I", False) == 197.0
|
|
336
|
+
assert depth_of_one_percent("I", True) == 133.0
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def test_examples_README_figures_for_absorption_by_the_contents():
|
|
340
|
+
"""Twelve times at 412 nm; pure water 78 to 98 percent at 600 nm."""
|
|
341
|
+
aw412, aw600 = (jerlov.pure_water_absorption(nm) for nm in (412, 600))
|
|
342
|
+
ratio = ((jerlov.water("5C").a(412) - aw412)
|
|
343
|
+
/ (jerlov.water("IB").a(412) - aw412))
|
|
344
|
+
assert round(ratio) == 12
|
|
345
|
+
shares = [aw600 / jerlov.water(t).a(600)
|
|
346
|
+
for t in jerlov.get_source("williamson2022").water_types]
|
|
347
|
+
assert (round(100 * min(shares)), round(100 * max(shares))) == (78, 98)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def test_examples_README_figure_for_measured_backscatter_ratios():
|
|
351
|
+
"""measured_scattering.py: contrast at 5 m from 4.0 to 2.6 at 550 nm
|
|
352
|
+
across the coastal and harbor stations' ratios."""
|
|
353
|
+
import numpy as np
|
|
354
|
+
|
|
355
|
+
wl = np.arange(450.0, 651.0, 50.0)
|
|
356
|
+
w = jerlov.water("1C")
|
|
357
|
+
with warnings.catch_warnings():
|
|
358
|
+
warnings.simplefilter("ignore", jerlov.ProvenanceWarning)
|
|
359
|
+
scene = jerlov.Scene.at_depth(
|
|
360
|
+
w, 10.0, np.interp(wl, *jerlov.d65()), wl,
|
|
361
|
+
kd=jerlov.water("1C", source="austin1986"))
|
|
362
|
+
contrasts = []
|
|
363
|
+
for s in jerlov.PETZOLD_STATIONS:
|
|
364
|
+
if s.startswith("AUTEC"):
|
|
365
|
+
continue
|
|
366
|
+
ratio = jerlov.petzold_scattering(s).backscatter_ratio
|
|
367
|
+
b_inf = jerlov.veiling_radiance_estimate(
|
|
368
|
+
w, scene.downwelling, wl, backscatter_ratio=ratio)
|
|
369
|
+
seen = scene.observe(np.full(wl.size, 0.3), 5.0,
|
|
370
|
+
veiling_radiance=b_inf)
|
|
371
|
+
contrasts.append(seen.contrast(b_inf)[2])
|
|
372
|
+
assert (round(max(contrasts), 1), round(min(contrasts), 1)) == (4.0, 2.6)
|
|
@@ -353,3 +353,11 @@ def test_an_observation_with_no_light_has_a_quiet_repr():
|
|
|
353
353
|
with warnings.catch_warnings():
|
|
354
354
|
warnings.simplefilter("error")
|
|
355
355
|
assert "veiling undefined" in repr(o)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def test_a_scene_does_not_follow_later_changes_to_the_callers_arrays():
|
|
359
|
+
wl, ed = WL.copy(), np.ones(WL.size)
|
|
360
|
+
s = Scene(jerlov.water("II"), ed, wl)
|
|
361
|
+
wl[0], ed[0] = 999.0, -1.0
|
|
362
|
+
assert s.wavelengths[0] == WL[0]
|
|
363
|
+
assert s.downwelling[0] == 1.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|