jerlov 0.2.0__tar.gz → 0.2.1__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.
Files changed (39) hide show
  1. {jerlov-0.2.0/jerlov.egg-info → jerlov-0.2.1}/PKG-INFO +3 -3
  2. {jerlov-0.2.0 → jerlov-0.2.1}/README.md +2 -2
  3. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/__init__.py +1 -1
  4. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/water.py +11 -4
  5. {jerlov-0.2.0 → jerlov-0.2.1/jerlov.egg-info}/PKG-INFO +3 -3
  6. {jerlov-0.2.0 → jerlov-0.2.1}/pyproject.toml +1 -1
  7. {jerlov-0.2.0 → jerlov-0.2.1}/tests/test_api.py +27 -0
  8. {jerlov-0.2.0 → jerlov-0.2.1}/tests/test_reproduces_papers.py +72 -0
  9. {jerlov-0.2.0 → jerlov-0.2.1}/LICENSE +0 -0
  10. {jerlov-0.2.0 → jerlov-0.2.1}/NOTICE +0 -0
  11. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/_data.py +0 -0
  12. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/colour.py +0 -0
  13. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/__init__.py +0 -0
  14. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/austin1986_kd.csv +0 -0
  15. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/austin1986_model.csv +0 -0
  16. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/cie1931_2deg_cmf.csv +0 -0
  17. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/cie_d65.csv +0 -0
  18. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/jerlov1968_kd.csv +0 -0
  19. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/jerlov1968_total_irradiance.csv +0 -0
  20. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/jerlov1976_kd.csv +0 -0
  21. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/paulson1977_shortwave.csv +0 -0
  22. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/smart2007_b_from_c.csv +0 -0
  23. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/solonenko2015_iop.csv +0 -0
  24. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/williamson2022_iop.csv +0 -0
  25. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/williamson2022_measured.csv +0 -0
  26. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/data/williamson2023_depth.csv +0 -0
  27. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/scene.py +0 -0
  28. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/shortwave.py +0 -0
  29. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov/sources.py +0 -0
  30. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov.egg-info/SOURCES.txt +0 -0
  31. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov.egg-info/dependency_links.txt +0 -0
  32. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov.egg-info/requires.txt +0 -0
  33. {jerlov-0.2.0 → jerlov-0.2.1}/jerlov.egg-info/top_level.txt +0 -0
  34. {jerlov-0.2.0 → jerlov-0.2.1}/setup.cfg +0 -0
  35. {jerlov-0.2.0 → jerlov-0.2.1}/tests/test_colour.py +0 -0
  36. {jerlov-0.2.0 → jerlov-0.2.1}/tests/test_depth.py +0 -0
  37. {jerlov-0.2.0 → jerlov-0.2.1}/tests/test_packaging.py +0 -0
  38. {jerlov-0.2.0 → jerlov-0.2.1}/tests/test_scene.py +0 -0
  39. {jerlov-0.2.0 → jerlov-0.2.1}/tests/test_shortwave.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jerlov
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Inherent optical properties of Jerlov water types, with provenance
5
5
  Author: T. Ishibashi
6
6
  License-Expression: Apache-2.0
@@ -271,8 +271,8 @@ Both are run by CI, so an example that has stopped working is a failed build.
271
271
  ## Provenance and design
272
272
 
273
273
  `DATA.md` records, for every shipped table, where it came from, what was
274
- verified, and what is known to be wrong with it. Fifteen entries are
275
- documented there: seven confirmed defects in the source literature, three
274
+ verified, and what is known to be wrong with it. Seventeen entries are
275
+ documented there: eight confirmed defects in the source literature, three
276
276
  questions the first edition of Jerlov settled, and the rest notes.
277
277
 
278
278
  `DECISIONS.md` records why the package is shaped the way it is, including the
@@ -246,8 +246,8 @@ Both are run by CI, so an example that has stopped working is a failed build.
246
246
  ## Provenance and design
247
247
 
248
248
  `DATA.md` records, for every shipped table, where it came from, what was
249
- verified, and what is known to be wrong with it. Fifteen entries are
250
- documented there: seven confirmed defects in the source literature, three
249
+ verified, and what is known to be wrong with it. Seventeen entries are
250
+ documented there: eight confirmed defects in the source literature, three
251
251
  questions the first edition of Jerlov settled, and the rest notes.
252
252
 
253
253
  `DECISIONS.md` records why the package is shaped the way it is, including the
@@ -64,4 +64,4 @@ __all__ = [
64
64
  "MissingQuantityError",
65
65
  ]
66
66
 
67
- __version__ = "0.2.0"
67
+ __version__ = "0.2.1"
@@ -131,11 +131,18 @@ class Water:
131
131
  values = self._series[quantity]
132
132
  out = np.interp(query, self.wavelengths, values)
133
133
  # np.interp happily bridges a NaN-free path around a NaN, so check the
134
- # bracketing samples explicitly.
134
+ # samples the answer actually rests on. A query that lands exactly on
135
+ # a sample rests on that sample alone: it is not interpolated, so a
136
+ # missing neighbour must not poison it.
135
137
  idx = np.searchsorted(self.wavelengths, query)
136
- for k, i in enumerate(idx):
137
- neighbours = values[max(i - 1, 0):min(i + 1, values.size) + 1]
138
- if np.any(np.isnan(neighbours)):
138
+ for k, (i, w_query) in enumerate(zip(idx, query)):
139
+ exact = i < self.wavelengths.size and self.wavelengths[i] == w_query
140
+ if exact:
141
+ if np.isnan(values[i]):
142
+ out[k] = np.nan
143
+ continue
144
+ left, right = max(i - 1, 0), min(i, values.size - 1)
145
+ if np.any(np.isnan(values[left:right + 1])):
139
146
  out[k] = np.nan
140
147
  return _like_input(out, wl)
141
148
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jerlov
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Inherent optical properties of Jerlov water types, with provenance
5
5
  Author: T. Ishibashi
6
6
  License-Expression: Apache-2.0
@@ -271,8 +271,8 @@ Both are run by CI, so an example that has stopped working is a failed build.
271
271
  ## Provenance and design
272
272
 
273
273
  `DATA.md` records, for every shipped table, where it came from, what was
274
- verified, and what is known to be wrong with it. Fifteen entries are
275
- documented there: seven confirmed defects in the source literature, three
274
+ verified, and what is known to be wrong with it. Seventeen entries are
275
+ documented there: eight confirmed defects in the source literature, three
276
276
  questions the first edition of Jerlov settled, and the rest notes.
277
277
 
278
278
  `DECISIONS.md` records why the package is shaped the way it is, including the
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jerlov"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "Inherent optical properties of Jerlov water types, with provenance"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -186,3 +186,30 @@ def test_a_missing_value_is_nan_whether_scalar_or_array():
186
186
  warnings.simplefilter("ignore", ProvenanceWarning)
187
187
  assert np.isnan(w.a(675))
188
188
  assert np.isnan(w.a([675.0])).all()
189
+
190
+
191
+ # -- landing exactly on a sample -----------------------------------------
192
+
193
+
194
+ def test_an_exact_hit_survives_a_missing_neighbour():
195
+ """A query on a sample is not interpolated, so a gap beside it is not its
196
+ problem. Found by checking the shipped 1976 file against the printed
197
+ table: Jerlov 7C has no data below 350 nm, and kd(350) was returning nan
198
+ although 350 nm itself is tabulated.
199
+ """
200
+ w = jerlov.water("7C", source="jerlov1976")
201
+ with warnings.catch_warnings():
202
+ warnings.simplefilter("ignore", ProvenanceWarning)
203
+ assert w.kd(350.0) == pytest.approx(3.0)
204
+ assert np.isnan(w.kd(349.0)) # inside the gap, still nan
205
+ assert np.isnan(w.kd(348.0))
206
+
207
+
208
+ def test_interpolating_across_a_gap_still_gives_nan():
209
+ """The guard this rests on must not have been loosened."""
210
+ w = jerlov.water("5C", source="solonenko2015")
211
+ with warnings.catch_warnings():
212
+ warnings.simplefilter("ignore", ProvenanceWarning)
213
+ assert np.isnan(w.a(650)) # a published value that is wrong
214
+ assert np.isnan(w.a(660)) # and interpolation across it
215
+ assert np.isnan(w.a(675))
@@ -221,3 +221,75 @@ def test_jerlov_type_I_falls_below_pure_sea_water():
221
221
  if j < float(np.interp(nm, wl_m, kw)):
222
222
  below += 1
223
223
  assert below == 9, f"{below} of {len(checked)} wavelengths below Kw"
224
+
225
+
226
+ # -- checked against independent transcriptions ---------------------------
227
+
228
+ #: Jerlov (1976) Table XXVII, Kd x 100 in 1/m, as reprinted by Paglierani et
229
+ #: al. (2023) Table 10 and by Wozniak & Pelevin (1991) Table 1. The two agree
230
+ #: with each other and with the original scan except at IB 700 nm, where
231
+ #: Wozniak & Pelevin print 59; see DATA.md section 16.
232
+ JERLOV1976_TABLE_XXVII = {
233
+ "I": [15, 6.2, 3.8, 2.8, 2.2, 1.9, 1.8, 2.7, 4.3, 6.3, 8.9, 23.5, 30.5,
234
+ 36, 42, 56],
235
+ "IA": [18, 7.8, 5.2, 3.8, 3.1, 2.6, 2.5, 3.2, 4.8, 6.7, 9.4, 24, 31, 37,
236
+ 43, 57],
237
+ "IB": [22, 10, 6.6, 5.1, 4.2, 3.6, 3.3, 4.2, 5.4, 7.2, 9.9, 24.5, 31.5,
238
+ 37.5, 43.5, 58],
239
+ "II": [37, 17.5, 12.2, 9.6, 8.1, 6.8, 6.2, 7.0, 7.6, 8.9, 11.5, 26, 33.5,
240
+ 40, 46.5, 61],
241
+ "III": [65, 32, 22, 18.5, 16, 13.5, 11.6, 11.5, 11.6, 12.0, 14.8, 29.5,
242
+ 37.5, 44.5, 52, 66],
243
+ "1C": [180, 120, 80, 51, 36, 25, 17, 14, 13, 12, 15, 30, 37, 45, 51, 65],
244
+ "3C": [240, 170, 110, 78, 54, 39, 29, 22, 20, 19, 21, 33, 40, 46, 56, 71],
245
+ "5C": [350, 230, 160, 110, 78, 56, 43, 36, 31, 30, 33, 40, 48, 54, 65, 80],
246
+ "7C": [None, 300, 210, 160, 120, 89, 71, 58, 49, 46, 46, 48, 54, 63, 78,
247
+ 92],
248
+ "9C": [None, 390, 300, 240, 190, 160, 123, 99, 78, 63, 58, 60, 65, 76, 92,
249
+ 110],
250
+ }
251
+ TABLE_XXVII_WAVELENGTHS = [310, 350, 375, 400, 425, 450, 475, 500, 525, 550,
252
+ 575, 600, 625, 650, 675, 700]
253
+
254
+
255
+ def test_the_shipped_1976_file_matches_the_printed_table():
256
+ """The Dstl file reaches us second-hand; the printed table does not."""
257
+ w = {t: jerlov.water(t, source="jerlov1976")
258
+ for t in JERLOV1976_TABLE_XXVII}
259
+ checked = 0
260
+ for water_type, row in JERLOV1976_TABLE_XXVII.items():
261
+ for nm, printed in zip(TABLE_XXVII_WAVELENGTHS, row):
262
+ if printed is None:
263
+ continue
264
+ got = w[water_type].kd(float(nm))
265
+ assert got == pytest.approx(printed / 100.0, rel=0.005), (
266
+ f"{water_type} at {nm} nm: shipped {got}, printed "
267
+ f"{printed / 100.0}"
268
+ )
269
+ checked += 1
270
+ assert checked == 158
271
+
272
+
273
+ def test_the_wozniak_pelevin_reprint_differs_at_exactly_one_cell():
274
+ """DATA.md section 16. A standing record of what that reprint got wrong."""
275
+ reprint = {k: list(v) for k, v in JERLOV1976_TABLE_XXVII.items()}
276
+ reprint["IB"][TABLE_XXVII_WAVELENGTHS.index(700)] = 59 # as printed
277
+ differing = [
278
+ (t, nm)
279
+ for t, row in reprint.items()
280
+ for nm, value in zip(TABLE_XXVII_WAVELENGTHS, row)
281
+ if value is not None
282
+ and value != JERLOV1976_TABLE_XXVII[t][
283
+ TABLE_XXVII_WAVELENGTHS.index(nm)]
284
+ ]
285
+ assert differing == [("IB", 700)]
286
+
287
+
288
+ def test_the_stated_unit_of_that_reprint_is_impossible():
289
+ """Its header says 1e-3 m^-1, which puts Jerlov I below pure sea water."""
290
+ printed = JERLOV1976_TABLE_XXVII["I"][TABLE_XXVII_WAVELENGTHS.index(475)]
291
+ as_stated = printed * 1e-3
292
+ correct = printed * 1e-2
293
+ pure_water_absorption_at_475 = 0.011 # Austin & Petzold Kw, 1/m
294
+ assert as_stated < pure_water_absorption_at_475
295
+ assert correct > pure_water_absorption_at_475
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