oceanarray 0.5.1__tar.gz → 0.6.0__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 (427) hide show
  1. {oceanarray-0.5.1 → oceanarray-0.6.0}/.gitattributes +4 -0
  2. {oceanarray-0.5.1 → oceanarray-0.6.0}/.github/workflows/tests.yml +5 -0
  3. oceanarray-0.6.0/CHANGELOG.md +384 -0
  4. {oceanarray-0.5.1 → oceanarray-0.6.0}/CONTRIBUTING.md +28 -9
  5. {oceanarray-0.5.1/oceanarray.egg-info → oceanarray-0.6.0}/PKG-INFO +9 -6
  6. {oceanarray-0.5.1 → oceanarray-0.6.0}/README.md +8 -5
  7. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/demo/dune2/dune2_1_2026_grid_report.html +1 -1
  8. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/demo/dune2/dune2_1_2026_report.html +1 -1
  9. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/rotary_spectrum_plan.rst +2 -2
  10. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/cli_reference.rst +159 -28
  11. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/clock_offset.rst +2 -2
  12. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/directory_structure.rst +7 -4
  13. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/file_naming_conventions.rst +8 -2
  14. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/index.rst +2 -1
  15. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/legacy.rst +13 -5
  16. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/auto_qc.rst +25 -10
  17. oceanarray-0.6.0/docs/source/methods/calibration.rst +281 -0
  18. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/nortek_coordinate_transform.rst +4 -4
  19. oceanarray-0.6.0/docs/source/methods/oceansites_export.rst +97 -0
  20. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/standardisation.rst +10 -11
  21. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/time_gridding.rst +35 -16
  22. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/trimming.rst +2 -2
  23. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/vertical_gridding.rst +13 -9
  24. oceanarray-0.6.0/docs/source/migrating_0_6_0.rst +124 -0
  25. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/migration.rst +55 -1
  26. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/oceanSITES_manual.rst +1 -1
  27. oceanarray-0.6.0/docs/source/oceanarray.rst +476 -0
  28. oceanarray-0.6.0/docs/source/oceanarray_format.rst +170 -0
  29. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/processing_framework.rst +19 -13
  30. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/project_structure.md +68 -58
  31. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/quickstart.rst +73 -2
  32. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/reports.rst +21 -10
  33. oceanarray-0.6.0/docs/source/roadmap.rst +148 -0
  34. oceanarray-0.6.0/docs/source/style_guide.md +119 -0
  35. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/troubleshooting.rst +9 -12
  36. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/yaml_configuration.rst +202 -22
  37. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/demo_climatology.ipynb +2 -3
  38. oceanarray-0.6.0/notebooks/demo_mooring.ipynb +516 -0
  39. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/README.md +1 -1
  40. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_batch_instrument.ipynb +3 -3
  41. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_clock_offset.ipynb +1 -1
  42. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_instrument.ipynb +2 -2
  43. oceanarray-0.6.0/oceanarray/__init__.py +115 -0
  44. oceanarray-0.6.0/oceanarray/__main__.py +6 -0
  45. oceanarray-0.6.0/oceanarray/_deprecated.py +115 -0
  46. oceanarray-0.6.0/oceanarray/_version.py +1 -0
  47. oceanarray-0.6.0/oceanarray/analysis/__init__.py +10 -0
  48. oceanarray-0.5.1/oceanarray/analysis/hydrographic.py → oceanarray-0.6.0/oceanarray/analysis/hydrography.py +2 -3
  49. oceanarray-0.6.0/oceanarray/cli/__init__.py +140 -0
  50. oceanarray-0.6.0/oceanarray/cli/_common.py +289 -0
  51. oceanarray-0.6.0/oceanarray/cli/_deprecate.py +40 -0
  52. oceanarray-0.6.0/oceanarray/cli/animate.py +244 -0
  53. oceanarray-0.6.0/oceanarray/cli/export.py +100 -0
  54. oceanarray-0.6.0/oceanarray/cli/init.py +52 -0
  55. oceanarray-0.6.0/oceanarray/cli/list.py +66 -0
  56. oceanarray-0.6.0/oceanarray/cli/plot.py +148 -0
  57. oceanarray-0.6.0/oceanarray/cli/process.py +235 -0
  58. oceanarray-0.6.0/oceanarray/cli/report.py +331 -0
  59. oceanarray-0.6.0/oceanarray/cli/run.py +208 -0
  60. oceanarray-0.6.0/oceanarray/cli/stamp.py +70 -0
  61. oceanarray-0.6.0/oceanarray/cli/validate.py +98 -0
  62. oceanarray-0.6.0/oceanarray/config/__init__.py +7 -0
  63. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/config/logging.yaml +2 -2
  64. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/config/parameters.py +36 -54
  65. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/config/unit_tables.py +24 -5
  66. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/config/validation.py +132 -101
  67. oceanarray-0.6.0/oceanarray/exceptions.py +25 -0
  68. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/inspect.py +13 -6
  69. oceanarray-0.6.0/oceanarray/instruments.py +115 -0
  70. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/__init__.py +4 -2
  71. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/caldip.py +0 -1
  72. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/convertOS.py +53 -4
  73. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/mooring_rodb.py +57 -3
  74. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/process_rodb.py +19 -9
  75. oceanarray-0.6.0/oceanarray/legacy/qc_rodb.py +92 -0
  76. oceanarray-0.6.0/oceanarray/location.py +177 -0
  77. oceanarray-0.6.0/oceanarray/logger.py +382 -0
  78. oceanarray-0.6.0/oceanarray/mooring.py +997 -0
  79. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/paths.py +241 -5
  80. oceanarray-0.6.0/oceanarray/pipeline/__init__.py +627 -0
  81. oceanarray-0.6.0/oceanarray/pipeline/_run.py +376 -0
  82. oceanarray-0.6.0/oceanarray/pipeline/_stage.py +156 -0
  83. oceanarray-0.6.0/oceanarray/pipeline/calibration/__init__.py +149 -0
  84. oceanarray-0.6.0/oceanarray/pipeline/calibration/caldip.py +275 -0
  85. oceanarray-0.6.0/oceanarray/pipeline/calibration/dips.py +216 -0
  86. oceanarray-0.6.0/oceanarray/pipeline/calibration/stops.py +644 -0
  87. oceanarray-0.6.0/oceanarray/pipeline/clock/__init__.py +7 -0
  88. oceanarray-0.5.1/oceanarray/legacy/find_deployment.py → oceanarray-0.6.0/oceanarray/pipeline/clock/deployment.py +11 -7
  89. oceanarray-0.5.1/oceanarray/analysis/clock.py → oceanarray-0.6.0/oceanarray/pipeline/clock/offsets.py +113 -13
  90. oceanarray-0.6.0/oceanarray/pipeline/coordinate.py +372 -0
  91. oceanarray-0.6.0/oceanarray/pipeline/dataset.py +59 -0
  92. oceanarray-0.6.0/oceanarray/pipeline/export.py +163 -0
  93. oceanarray-0.6.0/oceanarray/pipeline/grid.py +357 -0
  94. oceanarray-0.6.0/oceanarray/pipeline/gridders/__init__.py +8 -0
  95. oceanarray-0.6.0/oceanarray/pipeline/gridders/climatology.py +165 -0
  96. oceanarray-0.6.0/oceanarray/pipeline/gridders/filters.py +55 -0
  97. {oceanarray-0.5.1/oceanarray/tools → oceanarray-0.6.0/oceanarray/pipeline/gridders}/rapid_interp.py +154 -8
  98. oceanarray-0.6.0/oceanarray/pipeline/oceansites.py +757 -0
  99. {oceanarray-0.5.1/oceanarray/processors → oceanarray-0.6.0/oceanarray/pipeline}/pressure.py +30 -13
  100. oceanarray-0.5.1/oceanarray/processors/qc.py → oceanarray-0.6.0/oceanarray/pipeline/qc/__init__.py +53 -34
  101. oceanarray-0.5.1/oceanarray/processors/coordinate.py → oceanarray-0.6.0/oceanarray/pipeline/qc/adcp.py +4 -354
  102. oceanarray-0.6.0/oceanarray/pipeline/raw_files.py +540 -0
  103. oceanarray-0.6.0/oceanarray/pipeline/read_mooring.py +356 -0
  104. oceanarray-0.6.0/oceanarray/pipeline/stack.py +1276 -0
  105. oceanarray-0.6.0/oceanarray/pipeline/stage1.py +902 -0
  106. oceanarray-0.6.0/oceanarray/pipeline/stage2.py +836 -0
  107. oceanarray-0.6.0/oceanarray/pipeline/stage3.py +806 -0
  108. oceanarray-0.6.0/oceanarray/pipeline/stamp.py +77 -0
  109. {oceanarray-0.5.1/oceanarray/processors → oceanarray-0.6.0/oceanarray/pipeline}/units.py +12 -107
  110. oceanarray-0.6.0/oceanarray/pipeline/write_mooring.py +81 -0
  111. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/__init__.py +38 -52
  112. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/_cli_legacy.py +12 -10
  113. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/animation.py +2 -2
  114. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/current.py +408 -52
  115. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/diagnostic.py +90 -78
  116. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/helpers.py +52 -68
  117. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/hydrography.py +8 -8
  118. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/primitives.py +127 -5
  119. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/spectrum.py +15 -23
  120. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/timeseries.py +150 -12
  121. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/plotters/ts.py +19 -45
  122. oceanarray-0.6.0/oceanarray/readers/__init__.py +299 -0
  123. oceanarray-0.6.0/oceanarray/readers/netcdf.py +27 -0
  124. oceanarray-0.6.0/oceanarray/readers/nortek.py +504 -0
  125. oceanarray-0.6.0/oceanarray/readers/oceansites.py +139 -0
  126. oceanarray-0.6.0/oceanarray/readers/rodb.py +150 -0
  127. oceanarray-0.6.0/oceanarray/readers/sbe.py +35 -0
  128. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/__init__.py +7 -2
  129. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_array.py +81 -169
  130. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_env.py +5 -5
  131. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_figdebug.py +4 -8
  132. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_grid.py +132 -96
  133. oceanarray-0.6.0/oceanarray/reports/_html_helpers.py +356 -0
  134. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_instrument.py +64 -57
  135. oceanarray-0.6.0/oceanarray/reports/_masthead.py +243 -0
  136. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_mooring.py +198 -108
  137. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_navs.py +15 -29
  138. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_pdf.py +15 -99
  139. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_plots.py +117 -347
  140. oceanarray-0.6.0/oceanarray/reports/_read.py +434 -0
  141. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_recovery_table.py +27 -54
  142. oceanarray-0.6.0/oceanarray/reports/_stack.py +697 -0
  143. oceanarray-0.6.0/oceanarray/reports/_summary.py +129 -0
  144. oceanarray-0.6.0/oceanarray/reports/_verb.py +316 -0
  145. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_grid_history.html +1 -1
  146. oceanarray-0.6.0/oceanarray/reports/templates/_magnetic_north_note.html +6 -0
  147. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_clock_table.html +1 -1
  148. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_instruments.html +3 -3
  149. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_pipeline.html +2 -2
  150. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_timing.html +20 -10
  151. oceanarray-0.6.0/oceanarray/reports/templates/_mooring_timing_imported.html +43 -0
  152. oceanarray-0.6.0/oceanarray/reports/templates/_quicklook_note.html +9 -0
  153. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/base.html +7 -1
  154. oceanarray-0.6.0/oceanarray/reports/templates/grid.html +26 -0
  155. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/instrument.html +1 -1
  156. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/mooring.html +0 -11
  157. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/recovery_table.html +0 -8
  158. oceanarray-0.6.0/oceanarray/reports/templates/stack.html +14 -0
  159. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/writers/__init__.py +1 -1
  160. oceanarray-0.6.0/oceanarray/writers/dtypes.py +94 -0
  161. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/writers/netcdf.py +91 -139
  162. {oceanarray-0.5.1 → oceanarray-0.6.0/oceanarray.egg-info}/PKG-INFO +9 -6
  163. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray.egg-info/SOURCES.txt +98 -29
  164. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray.egg-info/scm_file_list.json +98 -29
  165. oceanarray-0.6.0/oceanarray.egg-info/scm_version.json +8 -0
  166. {oceanarray-0.5.1 → oceanarray-0.6.0}/pyproject.toml +5 -4
  167. oceanarray-0.6.0/scripts/survey_mooring_keys.py +70 -0
  168. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/golden/dune2/dune2_1_2026_grid_report.html +16 -11
  169. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/golden/dune2/dune2_1_2026_report.html +26 -31
  170. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/golden/dune2/dune2_1_2026_stack_report.html +23 -18
  171. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/golden/dune2/instrument/dune2_1_2026_2941_report.html +63 -45
  172. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/golden/dune2/instrument/dune2_1_2026_9920_report.html +71 -48
  173. oceanarray-0.6.0/tests/fixtures/init_template_golden.yaml +53 -0
  174. oceanarray-0.6.0/tests/fixtures/proc/dune2_1_2026/aquadopp/dune2_1_2026_9920_stage1.nc +0 -0
  175. oceanarray-0.6.0/tests/fixtures/proc/dune2_1_2026/aquadopp/dune2_1_2026_9920_stage2.nc +0 -0
  176. oceanarray-0.6.0/tests/fixtures/proc/dune2_1_2026/aquadopp/dune2_1_2026_9920_stage3.nc +0 -0
  177. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/proc/dune2_1_2026/dune2_1_2026.mooring.yaml +5 -1
  178. oceanarray-0.6.0/tests/fixtures/proc/dune2_1_2026/microcat/dune2_1_2026_2941_stage1.nc +0 -0
  179. oceanarray-0.6.0/tests/fixtures/proc/dune2_1_2026/microcat/dune2_1_2026_2941_stage2.nc +0 -0
  180. oceanarray-0.6.0/tests/fixtures/proc/dune2_1_2026/microcat/dune2_1_2026_2941_stage3.nc +0 -0
  181. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/osnap/README.md +1 -1
  182. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/osnap/run_example.sh +1 -1
  183. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/regenerate_dune2_microcat.py +3 -3
  184. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/conftest.py +1 -1
  185. oceanarray-0.6.0/tests/integration/test_cli_paths.py +268 -0
  186. oceanarray-0.6.0/tests/integration/test_osnap_pipeline.py +316 -0
  187. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/test_pipeline.py +4 -4
  188. oceanarray-0.6.0/tests/integration/test_process_verb.py +287 -0
  189. oceanarray-0.6.0/tests/integration/test_read.py +124 -0
  190. oceanarray-0.6.0/tests/integration/test_read_mooring.py +154 -0
  191. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/test_readers.py +8 -111
  192. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/test_recovery_table.py +24 -0
  193. oceanarray-0.6.0/tests/integration/test_report_verb.py +255 -0
  194. oceanarray-0.6.0/tests/integration/test_run_verb.py +479 -0
  195. oceanarray-0.6.0/tests/integration/test_stack_grid_pure.py +138 -0
  196. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/test_stage1_from_raw.py +4 -6
  197. oceanarray-0.6.0/tests/integration/test_stage1_pure.py +260 -0
  198. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/test_stage2.py +1 -1
  199. oceanarray-0.6.0/tests/integration/test_stage2_pure.py +150 -0
  200. oceanarray-0.6.0/tests/integration/test_stage3_pure.py +256 -0
  201. oceanarray-0.6.0/tests/integration/test_stamp.py +110 -0
  202. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_array.py +102 -29
  203. oceanarray-0.6.0/tests/unit/test_caldip.py +359 -0
  204. oceanarray-0.6.0/tests/unit/test_caldip_stops.py +250 -0
  205. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_canonical_units.py +34 -25
  206. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_cli.py +10 -10
  207. oceanarray-0.6.0/tests/unit/test_config_sites.py +48 -0
  208. oceanarray-0.6.0/tests/unit/test_coordinate_unknown.py +64 -0
  209. oceanarray-0.6.0/tests/unit/test_deprecated.py +105 -0
  210. oceanarray-0.6.0/tests/unit/test_doc_package_refs.py +55 -0
  211. oceanarray-0.6.0/tests/unit/test_export.py +118 -0
  212. oceanarray-0.6.0/tests/unit/test_filename_literals.py +59 -0
  213. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_flag_merge.py +2 -3
  214. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_helpers.py +12 -91
  215. oceanarray-0.6.0/tests/unit/test_masthead.py +176 -0
  216. oceanarray-0.6.0/tests/unit/test_mooring.py +484 -0
  217. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_nav.py +1 -0
  218. oceanarray-0.6.0/tests/unit/test_oceansites_export_files.py +307 -0
  219. oceanarray-0.6.0/tests/unit/test_osnap_readers.py +343 -0
  220. oceanarray-0.6.0/tests/unit/test_package_boundaries.py +54 -0
  221. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_paths.py +85 -17
  222. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_pdf_report.py +7 -6
  223. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_plot_guard.py +98 -26
  224. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_plotters.py +14 -14
  225. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_pressure.py +3 -3
  226. oceanarray-0.6.0/tests/unit/test_private_names.py +60 -0
  227. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_process_api.py +18 -17
  228. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_qc.py +8 -8
  229. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_recovery_table.py +13 -13
  230. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_report.py +175 -24
  231. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_report_golden.py +32 -6
  232. oceanarray-0.5.1/tests/unit/test_utilities.py → oceanarray-0.6.0/tests/unit/test_shared_helpers.py +158 -70
  233. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_stack_omission.py +49 -1
  234. oceanarray-0.6.0/tests/unit/test_stack_plotters.py +105 -0
  235. oceanarray-0.6.0/tests/unit/test_stack_time_step.py +344 -0
  236. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_stage1.py +38 -59
  237. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_stage2.py +66 -114
  238. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_stage3.py +13 -14
  239. oceanarray-0.6.0/tests/unit/test_stage_marker.py +58 -0
  240. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_tools.py +38 -27
  241. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_validation.py +120 -32
  242. oceanarray-0.6.0/tests/unit/test_write_mooring.py +77 -0
  243. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_writers_netcdf.py +23 -13
  244. oceanarray-0.5.1/CHANGELOG.md +0 -227
  245. oceanarray-0.5.1/docs/source/methods/calibration.rst +0 -236
  246. oceanarray-0.5.1/docs/source/methods/conversion.rst +0 -163
  247. oceanarray-0.5.1/docs/source/oceanarray.rst +0 -299
  248. oceanarray-0.5.1/docs/source/oceanarray_format.rst +0 -680
  249. oceanarray-0.5.1/docs/source/roadmap.rst +0 -163
  250. oceanarray-0.5.1/docs/source/style_guide.md +0 -139
  251. oceanarray-0.5.1/notebooks/demo_mooring.ipynb +0 -363
  252. oceanarray-0.5.1/oceanarray/__init__.py +0 -41
  253. oceanarray-0.5.1/oceanarray/_version.py +0 -1
  254. oceanarray-0.5.1/oceanarray/analysis/__init__.py +0 -20
  255. oceanarray-0.5.1/oceanarray/analysis/science.py +0 -226
  256. oceanarray-0.5.1/oceanarray/analysis/temporal.py +0 -217
  257. oceanarray-0.5.1/oceanarray/analysis/vector.py +0 -115
  258. oceanarray-0.5.1/oceanarray/cli.py +0 -1490
  259. oceanarray-0.5.1/oceanarray/config/__init__.py +0 -7
  260. oceanarray-0.5.1/oceanarray/legacy/tools.py +0 -852
  261. oceanarray-0.5.1/oceanarray/logger.py +0 -192
  262. oceanarray-0.5.1/oceanarray/processors/__init__.py +0 -390
  263. oceanarray-0.5.1/oceanarray/processors/caldip.py +0 -311
  264. oceanarray-0.5.1/oceanarray/processors/grid.py +0 -1176
  265. oceanarray-0.5.1/oceanarray/processors/helpers.py +0 -369
  266. oceanarray-0.5.1/oceanarray/processors/stack.py +0 -768
  267. oceanarray-0.5.1/oceanarray/processors/stage1.py +0 -1990
  268. oceanarray-0.5.1/oceanarray/processors/stage2.py +0 -1057
  269. oceanarray-0.5.1/oceanarray/processors/stage3.py +0 -771
  270. oceanarray-0.5.1/oceanarray/reports/_html_helpers.py +0 -963
  271. oceanarray-0.5.1/oceanarray/reports/_stack.py +0 -1121
  272. oceanarray-0.5.1/oceanarray/reports/templates/grid.html +0 -43
  273. oceanarray-0.5.1/oceanarray/reports/templates/stack.html +0 -28
  274. oceanarray-0.5.1/oceanarray/tools/__init__.py +0 -32
  275. oceanarray-0.5.1/oceanarray/tools/readers.py +0 -558
  276. oceanarray-0.5.1/oceanarray/utilities.py +0 -793
  277. oceanarray-0.5.1/oceanarray.egg-info/scm_version.json +0 -8
  278. oceanarray-0.5.1/tests/fixtures/proc/dune2_1_2026/aquadopp/dune2_1_2026_9920_stage1.nc +0 -0
  279. oceanarray-0.5.1/tests/fixtures/proc/dune2_1_2026/aquadopp/dune2_1_2026_9920_stage2.nc +0 -0
  280. oceanarray-0.5.1/tests/fixtures/proc/dune2_1_2026/aquadopp/dune2_1_2026_9920_stage3.nc +0 -0
  281. oceanarray-0.5.1/tests/fixtures/proc/dune2_1_2026/microcat/dune2_1_2026_2941_stage1.nc +0 -0
  282. oceanarray-0.5.1/tests/fixtures/proc/dune2_1_2026/microcat/dune2_1_2026_2941_stage2.nc +0 -0
  283. oceanarray-0.5.1/tests/fixtures/proc/dune2_1_2026/microcat/dune2_1_2026_2941_stage3.nc +0 -0
  284. oceanarray-0.5.1/tests/integration/test_osnap_pipeline.py +0 -141
  285. oceanarray-0.5.1/tests/integration/test_time_gridding.py +0 -241
  286. oceanarray-0.5.1/tests/unit/test_caldip.py +0 -164
  287. oceanarray-0.5.1/tests/unit/test_grid_clamp.py +0 -45
  288. oceanarray-0.5.1/tests/unit/test_osnap_readers.py +0 -155
  289. oceanarray-0.5.1/tests/unit/test_time_gridding.py +0 -398
  290. {oceanarray-0.5.1 → oceanarray-0.6.0}/.github/ISSUE_TEMPLATE.md +0 -0
  291. {oceanarray-0.5.1 → oceanarray-0.6.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  292. {oceanarray-0.5.1 → oceanarray-0.6.0}/.github/dependabot.yml +0 -0
  293. {oceanarray-0.5.1 → oceanarray-0.6.0}/.github/workflows/docs.yml +0 -0
  294. {oceanarray-0.5.1 → oceanarray-0.6.0}/.github/workflows/docs_deploy.yml +0 -0
  295. {oceanarray-0.5.1 → oceanarray-0.6.0}/.github/workflows/pypi.yml +0 -0
  296. {oceanarray-0.5.1 → oceanarray-0.6.0}/.gitignore +0 -0
  297. {oceanarray-0.5.1 → oceanarray-0.6.0}/CITATION.cff +0 -0
  298. {oceanarray-0.5.1 → oceanarray-0.6.0}/LICENSE +0 -0
  299. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/Makefile +0 -0
  300. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/environment.yml +0 -0
  301. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/How do I transform a coordinate system manually_ /342/200/223 Nortek Support Center.pdf" +0 -0
  302. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/array_processing.png +0 -0
  303. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/array_processing_v2.png +0 -0
  304. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/3_beam_transformation.py +0 -0
  305. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/auto_filt.m +0 -0
  306. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/hydro_grid.m +0 -0
  307. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/microcat2rodb_2.m +0 -0
  308. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/microcat2rodb_3.m +0 -0
  309. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/microcat_apply_cal.m +0 -0
  310. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/microcat_apply_cal_plus.m +0 -0
  311. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/microcat_raw2use_003.m +0 -0
  312. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/code/mooring_interp_wb2_3_5.m +0 -0
  313. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/css/custom.css +0 -0
  314. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/demo/dune2/dune2_1_2026_stack_report.html +0 -0
  315. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/demo/dune2/instrument/dune2_1_2026_2941_report.html +0 -0
  316. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/demo/dune2/instrument/dune2_1_2026_9920_report.html +0 -0
  317. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/github_solo_workflow.png +0 -0
  318. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/github_workflow2.png +0 -0
  319. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/instrument_processing.png +0 -0
  320. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/instrument_processing_v2.png +0 -0
  321. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/instrument_processing_v4.png +0 -0
  322. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/instrument_processing_v5.png +0 -0
  323. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/instrument_processing_v6.png +0 -0
  324. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/logo.png +0 -0
  325. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/mooring_processing.png +0 -0
  326. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/mooring_processing_V2.png +0 -0
  327. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/mooring_processing_v3.png +0 -0
  328. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/mooring_processing_v4.png +0 -0
  329. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/oceanarray_grid_report.png +0 -0
  330. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/oceanarray_icon.png +0 -0
  331. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/oceanarray_instrument_report.png +0 -0
  332. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/oceanarray_report_header.png +0 -0
  333. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/_static/oceanarray_stack_report.png +0 -0
  334. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/calibration_dips.rst +0 -0
  335. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/conf.py +0 -0
  336. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/installation.rst +0 -0
  337. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/acquisition.rst +0 -0
  338. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/concatenation.rst +0 -0
  339. {oceanarray-0.5.1 → oceanarray-0.6.0}/docs/source/methods/multisite_merging.rst +0 -0
  340. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/dsE_1_2018_microcat_7518_temperature.png +0 -0
  341. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_check_clock.ipynb +0 -0
  342. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_instrument_rdb.ipynb +0 -0
  343. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_mooring_rdb.ipynb +0 -0
  344. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_stage1.ipynb +0 -0
  345. {oceanarray-0.5.1 → oceanarray-0.6.0}/notebooks/legacy/demo_stage2.ipynb +0 -0
  346. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/analysis/spectral.py +0 -0
  347. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/config/legacy/project_RAPID.yaml +0 -0
  348. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/config/legacy/rodb_keys.txt +0 -0
  349. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/config/legacy/rodb_keys.yaml +0 -0
  350. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/OS1_sensor_attributes.yaml +0 -0
  351. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/OS1_variable_attributes.yaml +0 -0
  352. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/OS1_variable_names.yaml +0 -0
  353. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/legacy/rodb.py +0 -0
  354. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_slots.py +0 -0
  355. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/MANIFEST.txt +0 -0
  356. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/README.md +0 -0
  357. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/__init__.py +0 -0
  358. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/check.py +0 -0
  359. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/css.py +0 -0
  360. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/design_tokens.py +0 -0
  361. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/figure_png.py +0 -0
  362. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/leaflet/LICENSE +0 -0
  363. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/leaflet/leaflet.min.css +0 -0
  364. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/leaflet/leaflet.min.js +0 -0
  365. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/leaflet.py +0 -0
  366. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/nc_tables.py +0 -0
  367. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/page_model.py +0 -0
  368. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/report.mplstyle +0 -0
  369. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/templates/_map.html +0 -0
  370. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/templates/_nav.html +0 -0
  371. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/templates/_nc_tables.html +0 -0
  372. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/units.py +0 -0
  373. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/_vendored/units_tables.py +0 -0
  374. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/design.py +0 -0
  375. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_instrument_analog_yaml.html +0 -0
  376. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_instrument_files.html +0 -0
  377. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_instrument_qc.html +0 -0
  378. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_instrument_rose_note.html +0 -0
  379. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_instrument_windows_note.html +0 -0
  380. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_macros.html +0 -0
  381. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_calibration.html +0 -0
  382. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_diagram.html +0 -0
  383. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_issues.html +0 -0
  384. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_mooring_qc.html +0 -0
  385. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_stack_instr_table.html +0 -0
  386. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/_stack_roses_note.html +0 -0
  387. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray/reports/templates/array.html +0 -0
  388. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray.egg-info/dependency_links.txt +0 -0
  389. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray.egg-info/entry_points.txt +0 -0
  390. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray.egg-info/requires.txt +0 -0
  391. {oceanarray-0.5.1 → oceanarray-0.6.0}/oceanarray.egg-info/top_level.txt +0 -0
  392. {oceanarray-0.5.1 → oceanarray-0.6.0}/setup.cfg +0 -0
  393. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/conftest.py +0 -0
  394. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/adcp/dsG2_adcp_stage3_knockdown.nc +0 -0
  395. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/caldip/castM4_caldip.nc +0 -0
  396. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/proc/MIXSED2026.array.yaml +0 -0
  397. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/proc/dune2_1_2026/dune2_1_2026_grid.nc +0 -0
  398. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/proc/dune2_1_2026/dune2_1_2026_stack.nc +0 -0
  399. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/dune2_1_2026/aquadopp/9920_recovery.dat +0 -0
  400. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/dune2_1_2026/aquadopp/9920_recovery.hdr +0 -0
  401. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/dune2_1_2026/microcat/2941_recovery.asc +0 -0
  402. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/osnap/CF7_MCTD_2020_22225_50m.nc +0 -0
  403. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/osnap/OS_OSNAP-10633_KPO_1111_K7_201408_D_MCTD_OSNAPstyleOceanSITES.nc +0 -0
  404. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/osnap/OS_OSNAP_WHOI_CF7_202007_CM_500m.nc +0 -0
  405. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/osnap/rtwb1_01_2014_001.microcat +0 -0
  406. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/fixtures/raw/osnap/rtwb1_01_2014_11021.edt +0 -0
  407. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/__init__.py +0 -0
  408. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/integration/test_stage1.py +0 -0
  409. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/legacy/__init__.py +0 -0
  410. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/legacy/test_convertOS.py +0 -0
  411. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/legacy/test_mooring_rodb.py +0 -0
  412. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/legacy/test_process_rodb.py +0 -0
  413. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/legacy/test_rodb.py +0 -0
  414. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/test_imports.py +0 -0
  415. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/__init__.py +0 -0
  416. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_base_css_no_vendored_dup.py +0 -0
  417. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_grid_manifest.py +0 -0
  418. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_instrument_manifest.py +0 -0
  419. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_logger.py +0 -0
  420. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_manifest.py +0 -0
  421. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_mooring_manifest.py +0 -0
  422. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_nc_tables.py +0 -0
  423. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_parameters.py +0 -0
  424. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_report_tokens.py +0 -0
  425. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_stub_reason.py +0 -0
  426. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_unit_label_literals.py +0 -0
  427. {oceanarray-0.5.1 → oceanarray-0.6.0}/tests/unit/test_vendored.py +0 -0
@@ -6,3 +6,7 @@
6
6
  # remain tracked/committed (the demo suite is served from _static by Sphinx).
7
7
  tests/fixtures/golden/** linguist-generated=true
8
8
  docs/source/_static/demo/** linguist-generated=true binary
9
+
10
+ # The init-template golden is compared byte-for-byte against mooring.save output
11
+ # (which writes LF on every platform); keep it LF so Windows autocrlf cannot flip it.
12
+ tests/fixtures/init_template_golden.yaml text eol=lf
@@ -25,6 +25,10 @@ jobs:
25
25
  # ubuntu-only to keep the job count down.
26
26
  - { os: ubuntu-latest, python-version: "3.12" }
27
27
  - { os: ubuntu-latest, python-version: "3.13" }
28
+ # Forward-looking probe for 3.14: allowed to fail (experimental) so a
29
+ # dependency not yet 3.14-ready does not block the required check. Not
30
+ # in the supported range / pyproject classifiers yet.
31
+ - { os: ubuntu-latest, python-version: "3.14", experimental: true }
28
32
 
29
33
  steps:
30
34
  - uses: actions/checkout@v7
@@ -33,6 +37,7 @@ jobs:
33
37
  uses: actions/setup-python@v7
34
38
  with:
35
39
  python-version: ${{ matrix.python-version }}
40
+ allow-prereleases: ${{ matrix.experimental == true }}
36
41
  cache: "pip"
37
42
 
38
43
  - name: Install oceanarray (test extra = runtime + pytest)
@@ -0,0 +1,384 @@
1
+ # Changelog
2
+
3
+ All notable changes to oceanarray are documented here.
4
+
5
+ ---
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ - `location.parse_coordinate` reads one latitude or longitude value; a non-finite position counts as unknown (#132).
12
+ - Reports for moorings built from imported originator files (OceanSITES/RODB): an imported current meter holding only pressure and velocity no longer crashes the instrument page (its temperature, speed, trajectory and hodograph panels show as not applicable); a `currentmeter` instrument gets the "Current meter" masthead label; the deployment-timing table adapts (all-imported → a trimmed "Record first/last" table; mixed → imported rows marked and not falsely flagged as stopped-early); the array report accepts a mooring entry's `config:` as a path relative to the array description; and the instrument inventory names the directory it searched when no stage file is found.
13
+ - `report_sections` in the mooring YAML turns on optional report sections, keyed by page: `report_sections: {grid: [overflow]}`, resolved by `oceanarray.mooring.resolve_report_sections`.
14
+ - Pressure in `kPa` (converted to dbar, ×0.1) and the OOI ERDDAP unit spellings `decibars`, `m.s-1`, `mS.cm-1` and `1e-3` (practical salinity). A `units_override` entry can be `{units, reason}`; the reason is kept in the variable's `units_override_reason` attribute.
15
+ - Reducing a calibration dip: `oceanarray.pipeline.calibration.reduce_dip(record, variable, scheme=, deployment_pressure=)` gives one dip's correction per variable as a `Reduction` (value, the rule, the stops used, and for a slope its σ and residual). `standard`: temperature at the deepest stop; conductivity as the Sea-Bird AN31 slope through the origin over the stable stops below 500 dbar (200 dbar when fewer than two qualify; never shallower), weighted by `N / cond_std²`; a stop is stable when the CTD's std there is ≤ 0.002 °C (T) or ≤ 0.003 mS/cm (C), when the cast carries it; pressure as the mean offset near the deployment pressure. `rapid`: RAPID's deep-interval average for temperature and conductivity and its interpolation to depth for pressure. In a schema-1 caldip cast, `flagged` stops (reading off by more than caldip's tolerance) are used; `no_data` / `missing` / `unknown` never are. Not yet applied in stage 3.
16
+ - The mooring YAML's `caldip:` block (the cast for each end of the deployment, `scheme: standard | rapid`, a per-variable `override`), checked by `validate` (every shape mistake an ERROR). `oceanarray.pipeline.calibration.caldip_ends` finds each end's `{cast}_caldip.nc` beneath the caldip root (`caldip_dir=`, else the block's `root`); `assign_dip_role` and `cast_time` say whether a cast is an instrument's pre- or post-deployment dip. Not yet applied in stage 3.
17
+ - Reading caldip casts: `oceanarray.pipeline.calibration.read_caldip_cast` opens a `{cast}_caldip.nc`, refuses one with missing provenance, another schema version, an unrecognised units string or a repeated serial, rewrites its temperature, conductivity and pressure units to the registry spelling and its serials to the join key; `instrument_record` returns one instrument's per-stop record. Not yet applied in stage 3.
18
+ - `oceanarray.export(mooring, *, mooring_dir=None, out_dir=None, array=None, grid=True, overwrite=False, dry_run=False)` and `oceanarray export MOORING [--array YAML] [-o DIR] [--no-grid] [--force] [-n]` — write a mooring's stage-3 files and grid as OceanSITES 1.4 files (default `<mooring folder>/oceansites/`); instruments that cannot be exported are listed and left out. The data-format page (`oceanarray_format`) now describes these files, with the earlier departures from OceanSITES (`N_LEVELS`, `contributor_*`, compact times) dropped.
19
+ - `oceanarray.pipeline.oceansites.to_oceansites(ds, mooring, *, array=None, stack=None, source_file=None)` — one instrument's stage-3 dataset as an OceanSITES 1.4 deployment data file: variables on `(TIME, DEPTH)` with `DEPTH` the nominal instrument depth, `<PARAM>_QC` (reference table 2, the same flags), a data mode per variable (`DM_indicator`; `D` only with the calibration-dip correction recorded) and the §2.2 globals. `oceansites_filename` gives `OS_<platform>_<YYYYMM>_<mode>_<type>-<serial>-<depth>m.nc`. An ADCP is one file with its bins on `DEPTH` (nominal transducer depth ± range, by orientation; refused without one), `PRES` the pressure at each bin and `TRANSDUCER_PRES(TIME)` the measured transducer pressure and a failed or suspect `seabed_qc` merged into the velocity flags. A grid becomes a gridded file (`GRD`, §4.2): `OS_<platform>-<YYYYMM>_<start>-<end>_GRD_<interval>-DP<step>.nc`, `DEPTH` the pressure levels converted with `gsw.z_from_p`, `PRES` the levels, and `history` naming the stage files (pass `stack=`); only a provisional (`P`) grid is exported. The mooring description gains `platform_code` and `deployment_code` (default: the month of `deployment_time`); `site_code` comes from the array description and is left out when absent. The OceanSITES reader also reads `CSPD`, `CDIR`, `DOX2` and `TURB`.
20
+ - `oceanarray.pipeline.read_mooring.read_mooring(mooring, *, stage=None, serials=None, allow_missing=False, mooring_dir=None, raw_dir=None)` — reads every instrument of one mooring into a dict of datasets keyed by serial. A mooring's identity is its `name:` field (every file is `<name>_<serial>_stage<N>.nc`); `mooring` may be a dict, a `*.mooring.yaml` path, or a directory holding one. `stage=None` finds and reads each raw file (from `raw_dir`) as stage 1 does — a missing `filename` found by the recovery-file naming convention, the Nortek header (also in a legacy `nortek/` folder), the raw header's calibration metadata — and returns it unmarked; entries marked `skip` are left out; `stage=1|2|3` opens the stage files (from `mooring_dir`) and checks the marker; on every path the description's facts are stamped (per-instrument: serial, instrument, hab, clamp_id, sample_interval_seconds, file_type, source_file; per-mooring: mooring_name, latitude/longitude + source, deployment/recovery window + source, waterdepth, density_reference). A dataset whose `serial` contradicts the description, or whose `mooring_name` differs from `name:` by more than case, raises `MooringError`; a case-only difference is corrected with a `history` line. Position and window keep their placeholders when absent, loudly (`location_source`/`deployment_window_source` = `"none"`, a WARNING). A listed instrument with no file at the requested stage raises unless `allow_missing=True`.
21
+ - `oceanarray.pipeline.write_mooring.write_mooring(datasets, mooring_dir, *, overwrite=False)` — writes a dict of per-instrument datasets to `<mooring_dir>/<instrument>/<name>_<serial>_stage<N>.nc`, taking the name, instrument, serial and stage from each dataset's attributes; refuses a dataset whose `serial` attribute does not match its key.
22
+ - `oceanarray.paths.stage_file(mooring_dir, name, instrument, serial, stage, *, tag="")` and `oceanarray.paths.product_file(mooring_dir, name, product)` (`product` in `paths.PRODUCTS` = `{"stack", "grid"}`) — the full-path builders for a mooring's stage files and products, keyed on the mooring `name`; `read_mooring`/`write_mooring` use them. With them, `paths.stage_suffix`, `stage_glob` and `product_glob` give the filename endings and search patterns; no other module spells `_stageN`, `_stack.nc` or `_grid.nc` (a test enforces it).
23
+ - `oceanarray.readers` — a package reading one raw instrument file to a canonical dataset. `readers.read(path, *, file_type=None)` sniffs the file content (never the suffix) to pick the format, finds the Nortek `.hdr` beside a data file, and dispatches to a per-format module (`sbe`, `nortek`, `rodb`, `oceansites`, `netcdf`). A netCDF is read as OceanSITES when it carries a `TIME` dimension and an OceanSITES parameter code, and returned unchanged otherwise; an unrecognised file with no `file_type=` raises. The per-format reader bodies moved here unchanged from `processors.stage1` and the former `tools.readers`.
24
+ - `oceanarray.pipeline._stage` — the `processing_stage` marker: `stamp(ds, stage, *, source=)` writes the marker, a `history` line and `source_file`; `require(datasets, stage, next_stage)` raises `StageError` when a dataset is at the wrong stage, naming the stage to run first. A file written before the marker existed is tolerated for one release (a missing marker on read is a WARNING).
25
+ - `oceanarray.mooring` — the single seam for reading a mooring description: `load` (path, name + `proc_dir`, or dict; validates and raises `MooringError` on an invalid config), `check` (never raises; adds an unknown-top-level-key warning), `template` and `save`, plus `oceanarray.MooringError`. Every stage, report and CLI path now receives the loaded dict instead of calling `yaml.safe_load` itself; a test (`test_config_sites`) fails if a new mooring-config `safe_load` appears outside the loader. `scripts/survey_mooring_keys.py` lists the top-level keys on a processed-data root that are not yet in `mooring.KNOWN_KEYS`.
26
+ - `oceanarray.pipeline.stage1.stage1(datasets, mooring)`, `oceanarray.pipeline.stage2.stage2(datasets, mooring)`, `oceanarray.pipeline.stage3.stage3(datasets, mooring, *, caldip_dir=None)`, `oceanarray.pipeline.stack.stack(datasets, mooring, *, dt_seconds=None)` and `oceanarray.pipeline.grid.grid(ds_stack, *, pmin, pmax, dp)` — the processing steps as pure functions over datasets, with no file I/O. `MooringProcessor`, `Stage2Processor`, `Stage3Processor`, `MooringStacker` and `MooringGridder` now read, call these, and write; stages 1–3 are unchanged in value, the stack (and so the grid) changes as below. `oceanarray.pipeline.raw_files` holds stage 1's raw-file finding (`resolve_raw_file`, `guess_instrument_filename`) and reading (`read_raw_file`).
27
+ - `oceanarray stamp FILE... --declare N` and `oceanarray.pipeline.stamp.stamp_file(path, stage)` — write the `processing_stage` marker into a stage file written before it existed (`history`: "declared via stamp"). Refuses a stage that contradicts the filename or an existing marker; leaves an already-marked file untouched.
28
+ - `oceanarray.process(mooring, *, stages=(1, 2, 3), serials=None, force=False, keep_going=True, mooring_dir=None, raw_dir=None, caldip_dir=None) -> list[Path]` — runs stages 1–3 for one mooring from its `*.mooring.yaml` path (or a directory holding one, or a loaded description with `mooring_dir=`), writing each stage's files and a log per stage, and returns every stage file of the stages run — written, or kept because it was already there (`force=True` rewrites; stage 1 also rewrites a file older than its raw file); each stage prints how many it wrote and kept. By default it carries on past a failed instrument (see `keep_going` below); `keep_going=False` raises `MooringError` naming the instruments that failed, after the stage has written the rest, and runs nothing after it. Stacking and gridding are not part of it. The previous form, `process(name, stage, proc_dir=…)` (all five stages, returns a bool), still works for one release (see *Deprecated*).
29
+ - `oceanarray.run(mooring, *, stages=None, from_stage=None, serials=None, force=False, keep_going=True, mooring_dir=None, raw_dir=None, caldip_dir=None, dt_seconds=None, pmin=None, pmax=None, dp=None, stack_stage=3, report=False) -> list[Path]` — stages 1–3 (through `process`), then the stack (`<name>_stack.nc`) and the grid (`<name>_grid.nc`), rebuilt on every call; returns the stage files, then the stack and grid. `stages` lists the stages to run (default all); because the stack is rebuilt from the stage-3 files, they must run from the first one given through stage 3, so the stack never takes files older than the ones just written — `stages=(2, 3)` (or `from_stage=2`) re-runs stages 2 and 3 from the stage-1 files without `raw_dir`, while `stages=2` or `(1, 3)` is refused before anything runs. To run one stage on its own, use `process`. `stack_stage=2` (CLI `--stack-stage 2`) is a quick look at sea: it runs through stage 2 only and stacks and grids the stage-2 files (no QC flags, no interpolated pressure, no magnetic declination; every level's `source_stage` is 2). By default it carries on past failures (see `keep_going` below). With `keep_going=False` any failure raises, an instrument with no stage-3 file stops the stack, and a stack that left an instrument out is written but not gridded. The stack and grid settings come from the call, else from new optional `stack:` (`dt_seconds`) and `grid:` (`pmin`, `pmax`, `dp`) blocks in the mooring description, else 3600 s and 200–1000 dbar every 20 dbar; the merged settings are checked before anything runs, and `mooring.check` refuses a malformed block. When a strict run stops after it has rewritten stage files, or its new stack cannot be gridded, the stack and grid that no longer match are renamed `<name>_stack.stale.nc` / `<name>_grid.stale.nc` (a line says so; one stale copy per product, replaced by the next) — whatever the error that stopped it.
30
+ - `keep_going` on `process` and `run`, **on by default** — as much as possible on a first pass, troubleshoot later: a failed instrument is logged and left out and the next stage runs on what has files; a stage-3 failure is logged, not raised; `run` stacks each instrument's stage-3 file, else its stage-2 file. What was taken from stage 2 is recorded in the stack's new per-level `source_stage` variable and in a `stage2_instruments` attribute (the grid inherits it); instruments with neither, or that failed in this run (their older files are not used), are named in `instruments_omitted`; after a stage-3 failure every instrument is stacked from stage 2; what failed is recorded in a `keep_going_failures` attribute on the stack and grid; an instrument that failed in one stage is left out of the later stages of the same run (its older files are neither rebuilt from nor used as another instrument's pressure source); a stack that cannot be gridded (e.g. no pressure left) is kept, with a warning and no grid.
31
+ - `data_mode = "P"` (OceanSITES provisional) on every stage-3, stack and grid file. Nothing earns delayed mode (`D`) yet.
32
+ - A stage-3 instrument whose pressure is interpolated records the stage-2 files it came from: `pressure_source_serials` and `pressure_source_files` (file name, SHA-256, modification time) on its `pressure` variable. When stage 3 keeps or skips such a file and its sources have changed since, a WARNING names it.
33
+ - `oceanarray.reports.report(mooring, *, kind="mooring", pdf=False, ...) -> Path` — builds a mooring's report (summary page and, unless switched off, its instrument, stack and grid pages, plus an A4 PDF with `pdf=True`), the array index (`kind="array"`, from an `*.array.yaml`) or the recovery table (`kind="recovery"`), and returns the main page. Instruments and their files come from the mooring description. A failure raises `MooringError`; a PDF without the `pdf` extra raises rather than skipping. A loaded description is used as given. The mooring's folder is wherever its description is, under any name: the pages are written to its `report/` subfolder and named, and the stage, stack and grid files found, from `name:` (before, the report assumed `<proc-dir>/<name>/` and failed on any other layout). `oceanarray report` calls it; when the mooring report fails, it now stops there (no recovery table or PDF) and exits 1, and a recovery table that cannot be built exits 1 (before: ignored).
34
+ - `oceanarray.reports.report_paths(mooring, *, mooring_dir=None, out_dir=None, report_dir=None, pdf_dir=None)` — where `report` writes each page, without building any (the description is read only for its `name:`, so a half-filled one works); `oceanarray report --dry-run` prints these.
35
+ - `paths.resolve_report_dir(..., mooring_dir=)` — the default report location is `<mooring_dir>/report` when the mooring's folder is given.
36
+ - `oceanarray.reports.summary(mooring)` — the console summary `oceanarray process --report` prints (one line per instrument: records, time span, depth, interval, variables), listing the instruments of the description rather than the files in the folder.
37
+ - `run(..., report=True)` builds the report after the grid and returns its summary page last.
38
+ - `import oceanarray as oa` gives the whole public API: `oa.mooring`, `oa.read`, `oa.read_mooring`, `oa.stage1`, `oa.stage2`, `oa.stage3`, `oa.process`, `oa.stack`, `oa.grid`, `oa.run`, `oa.write`, `oa.write_mooring`, `oa.report`, `oa.MooringError` and `oa.StageError` — every name in `oceanarray.__all__` resolves after a bare import, loaded on first use (importing the package no longer imports xarray).
39
+ - `oceanarray.paths.stale_file(path)` — where a product that no longer matches its stage files is set aside (`<name>_stack.stale.nc`).
40
+ - A migration page, *Upgrading from 0.5 to 0.6* (`docs/source/migrating_0_6_0.rst`), with every renamed name and its replacement; a test keeps it in step with the deprecation table.
41
+ - `oceanarray process`, `run`, `report`, `animate` and `plot` take the mooring as a path — its `*.mooring.yaml` or the folder holding it, under any name — as well as a name with `--proc-dir`.
42
+ - `--only SERIAL ...` on `process`, `run`, `report` and `animate` (was `--serial`, still accepted until 0.7.0 with a note on stderr); `plot --var-y` / `--var-color` (the underscore spellings likewise).
43
+ - `-v` / `--verbose` now does something: each stage names every file it wrote or kept (DEBUG).
44
+ - Stack and grid pages carry an amber note when instruments were stacked from stage 2 (naming them, and that they have no QC flags or interpolated pressure), and a second one above the velocity figures when their velocities have no magnetic declination (magnetic north); the stack records those instruments in a new `stage2_magnetic_north` attribute (the grid inherits it).
45
+ - `oceanarray init` writes the optional `stack:` and `grid:` blocks, commented out with their defaults (`mooring.save(..., optional_blocks=True)`); the `name:` comment no longer says it must match the directory.
46
+ - `oceanarray.instruments.instrument_entries(mooring)` — the one place the `clamp`/legacy-`instruments` fallback and the inline merge live, used by every stage, report and the CLI; it treats a present-but-null `clamp:`/`inline:` as empty (previously a `TypeError`).
47
+
48
+ ### Changed
49
+
50
+ - Report mastheads (mooring, stack, grid, recovery table) come from one fact list: four cruise/ship fields (recovery `UNK` unless given), positions in degrees and decimal minutes, durations over 6 months in months (`11.2mon`, `1y 10.0mon`), instruments counted by type; the mooring page lists an entry with no `hab` as not stacked; `validate` warns on a position key without its pair, and on a recovered mooring that gives only the legacy `cruise`/`ship` (deployment values only) (#132).
51
+ - Stack: default step 3600 s (was 60 s); each instrument takes its nearest sample within ±dt/2, with no time interpolation, on a time axis of whole steps; instruments slower than the step are named in `instruments_slower_than_step` (#133).
52
+ - The command-line help says, for every subcommand, what it reads and writes, with an `Examples:` block; flags follow the family conventions. Renamed (old spellings accepted until 0.7.0 with a note on stderr): `process --report` → `--summary`, `plot --downsample` → `--downsample-seconds`, `export --overwrite` → `--force`, `stamp --stage` → `--declare`. All deprecated spellings now share one mechanism and message ("… is deprecated and removed in 0.7.0; use …").
53
+ - `oceanarray validate` takes a mooring the way the other commands do (its `*.mooring.yaml`, its folder, or a name with `--proc-dir`) and gains `--strict` (exit 1 on warnings too; the default still exits 0 when there are only warnings).
54
+ - A usage error (a removed flag, a missing `--raw-dir` or `--proc-dir`, an option that does not combine) exits 2 with an `ERROR:` line on stderr; a processing failure still exits 1. A mooring name with `--proc-dir` whose folder does not exist is an error naming the folder.
55
+ - `python -m oceanarray` runs the CLI; `-v` is accepted after the subcommand as well as before it; `export -n/--dry-run` lists the files it would write.
56
+ - `process --stage` help marks `stack` and `grid` as deprecated (use `run`), and their tuning flags are hidden from `process --help`.
57
+ - Private helpers follow one naming table (CONTRIBUTING, "Private helpers"): one verb per job, figure helpers `_draw_<what>` / `_make_<what>_b64` with no `_fig` suffix, 85 renamed; their docstrings are one line, with the reasons the code cannot show kept as comments (≈ −1,400 lines). The three private `_safe_serial` wrappers are gone (`paths.safe_serial`). Four dead helpers deleted, the duplicate `_times_to_float` and the three module `_log`s collapsed (into `oceanarray.logger.log_message`), and four one-line wrappers inlined. No public name or behaviour changes; report `source:` lines name the new helpers.
58
+ - `oceanarray process --dry-run` lists the file every stage would write (new, keep or rewrite) and, for stage 3, which instruments get interpolated pressure; it works by path and needs no `--raw-dir` (before: stage 3 only, by name under `--proc-dir`). The README, the demo notebook and the method pages use the verbs.
59
+ - The report page switches lose their short forms (`-i`, `-s`, `-g`, `-A`; accepted with a note until 0.7.0): the short flags are `-o` (always an output directory), `-n` (`--dry-run`) and `-v`.
60
+ - The CLI is a package, `oceanarray.cli`, with one module per subcommand (as ctdcast's); `oceanarray.cli.build_parser` and `main` are unchanged. `animate -o DIR` is now the output directory, as on `report`, `run` and `plot` (`--output FILE` names a single GIF; an old `-o FILE.gif` is still read as the file, with a note). `process --stage stack|grid` prints that it is removed in 0.7.0 (`oceanarray run` builds the stack and grid).
61
+ - `oceanarray process` runs stages 1–3 through `oceanarray.process`: it carries on past a failed instrument and exits 0 when it finishes (before: exit 1 if any instrument failed); `--strict` stops at the first failure and exits 1, as on `run`; a description error exits 1. `--stage stack` / `grid` still run the pre-0.6 way, with a note, and need `--proc-dir` (`oceanarray run` builds the stack and grid); `--strict` with them is refused.
62
+ - `oceanarray animate` finds each instrument's file from the description (stage 3, else stage 2) instead of searching the folder; `--only` matches a serial exactly (before: any file whose name contained it), and a serial not in the description is named in a warning.
63
+ - `oceanarray plot --colormap` / `--downsample` are passed to the plot instead of overwriting `parameters.DEFAULT_COLORMAP` / `DOWNSAMPLE_SECONDS` for the rest of the process.
64
+ - The stack page's figures are drawn by `plotters` functions instead of inside the page builder: `plotters.timeseries.draw_stack_timeseries` (the P/T/S and U/V/W panels, oxygen, turbidity), `plotters.diagnostic.draw_instrument_spacing` and `plotters.current.draw_aquadopp_tilt_panels`, with the shared per-level line colours in `plotters.helpers.level_line_styles`. The time-series figures now render at the full slot width with the legend inside the canvas (they were cropped to a tight box around an outside legend, so the page rescaled them), and every figure's `source:` caption names its draw function.
65
+ - Stages 1, 2 and 3 return their datasets holding the values their files will hold — float64 stored as float32 (time and position excepted), time rounded to the file's float64-seconds encoding — so a dataset passed on in memory equals the same file read back, and a full run and a later single-stage re-run agree exactly. Written files are unchanged. `oceanarray.writers.netcdf.as_stored(ds)` does the conversion.
66
+ - Stage 3 always reads the whole mooring's stage-2 files and writes only the instruments asked for (`serials=` / `--serials`). Before, a run for one sensorless instrument read only its own file, found no pressure source, and wrote it without pressure.
67
+ - Required mooring-config keys are now `name` and `waterdepth` only; `deployment_time` and `recovery_time` are recommended — absent, they produce a WARNING (Stage 2 can detect the window from the records) rather than the ERROR `validate` used to report.
68
+ - Stage 2 raises `MooringError` on a present-but-unparseable `deployment_time`/`recovery_time` (a log-sheet typo) instead of silently treating it as absent; a genuinely absent value is still tolerated (`NaT`).
69
+ - `stack` raises `MooringError` naming both keys when the config has no deployment window (the common time axis is that window) instead of a bare `KeyError`.
70
+ - Stage 1 names its output files from the description's `name:`, as stages 2 and 3 do (previously from the mooring directory name).
71
+ - Stage 1, 2 and 3 files carry `processing_stage` and the description's stamped facts (instrument, serial, hab, position, deployment window, …).
72
+ - Stacking detects each instrument's sampling interval from its time stamps; `sample_interval_seconds` in the mooring description is no longer read.
73
+ - `oceanarray report --dry-run` previews a half-filled config without raising: it prints the validation issues and lists what parses, and only stops on a file that is not YAML at all.
74
+ - `oceanarray init` builds its stub through `mooring.template` + `mooring.save`; the written file is byte-identical to before.
75
+ - `mooring.KNOWN_KEYS` (the vocabulary the unknown-key warning checks against) gains the position tiers `seabed_*` / `deployment_*` / `planned_*`, `qc_ranges` and `directory`, confirmed against real mooring descriptions.
76
+ - An instrument's `hab` is filled from `hab_bottom` (downward) or `hab_top` (upward) by its `orientation`, for `clamp` and `inline` entries alike (before: `inline` only, `hab_bottom` only); explicit `hab` wins. `validate` ERRORs when an `orientation` lacks its hab key, and names a stacked instrument with no resolvable `hab` in `instruments_omitted` (a strict run stops before the grid) rather than omitting it silently.
77
+
78
+ ### Deprecated
79
+
80
+ Every old name below still works, warns (`DeprecationWarning`, naming its replacement) and is removed in 0.7.0; the list lives in one table, `oceanarray._deprecated.RENAMED`.
81
+
82
+ - `oceanarray.parameters` — use `oceanarray.config.parameters`.
83
+ - `MooringProcessor`, `Stage2Processor`, `Stage3Processor`, `MooringStacker`, `MooringGridder` — use `oceanarray.process` / `oceanarray.run`, or the pure `stage1`/`stage2`/`stage3`/`stack`/`grid` on datasets.
84
+ - `oceanarray.inspect.vars` / `attrs` → `inspect.variables` / `inspect.attributes` (the old names shadow the builtin `vars`).
85
+ - Names with a British/American variant spelling: `legacy.process_rodb.normalize_by_middle_percent` / `normalize_dataset_by_middle_percent` → `to_zscore` / `to_zscore_dataset` (they return z-scores over the central `percent`).
86
+ - `oceanarray.process(name, stage, proc_dir=…)` — warns (`DeprecationWarning`) and is removed in 0.7.0. Pass the `*.mooring.yaml`: `oceanarray.process(yaml_path, raw_dir=…)` runs stages 1–3, `oceanarray.run(yaml_path, …)` runs stages 1–3, stack and grid.
87
+ - `plotters.timeseries.draw_grid` — use xarray's `DataArray.plot.pcolormesh` (or `.plot.contourf`) on the grid variable; it had no caller in the package.
88
+ - `config.validation.validate_mooring_yaml(path)` — use `oceanarray.mooring.check`, which reads the file once and adds the unknown-key check. The wrapper warns and is removed in 0.7.0.
89
+ - Stage files without a `processing_stage` marker (written before 0.6) — read with a WARNING and their stage inferred from the filename; refused from 0.7.0. Mark them once with `oceanarray stamp`.
90
+ - `directory:` in a mooring description — a raw-data root belongs to `raw_dir` / `--raw-dir`, not the YAML; `check` warns, and the stage-1 absolute-path override is removed in 0.7.0.
91
+
92
+ ### Breaking changes
93
+
94
+ - A `clamp` ADCP whose HAB was given only as `hab_bottom`/`hab_top` is now placed in the stack instead of being silently omitted — the `stack`/`grid` files for any such mooring change on rebuild.
95
+ - The grid report's **Overflow** section is off by default; turn it on with a `report_sections` block (`report_sections: {grid: [overflow]}`) in the mooring YAML. An overflow mooring whose YAML does not set it loses the section.
96
+ - A mooring description whose QC override blocks (`qc_ranges`, `qc_spike`, `tilt_qc`, `qc_flat_line`, at mooring or instrument level) hold an unknown field, a span that is not two increasing numbers, a threshold that is not a number, or a new variable without a `fail_span` is now refused by `load` and reported as an ERROR by `oceanarray validate`; before, the mistake was dropped and QC ran with the defaults. A variable outside the registry is a WARNING. `qc_spike`, `tilt_qc` and `qc_flat_line` are no longer reported as unknown top-level keys.
97
+ - `current_direction` is written with `standard_name = "sea_water_velocity_to_direction"`; CF deprecated `direction_of_sea_water_velocity`. Files written before keep the old name.
98
+ - Modules moved to the package layout (no aliases: nothing outside oceanarray imported them). Old → new:
99
+
100
+ | old | new |
101
+ |---|---|
102
+ | `oceanarray.utilities` (`instrument_entries`, `extract_inline_instruments`) | `oceanarray.instruments` |
103
+ | `oceanarray.utilities` (`parse_latlon`, `parse_latlon_with_source`, `format_latlon`, …) | `oceanarray.location` |
104
+ | `oceanarray.utilities` (`find_best_dtype`, `cast_output_dtypes`) | `oceanarray.writers.dtypes` |
105
+ | `oceanarray.utilities` (`should_skip_regeneration`) | `oceanarray.paths` |
106
+ | `oceanarray.utilities` (`drop_all_zero_vars`) | `oceanarray.pipeline.dataset` |
107
+ | `oceanarray.utilities` (`nice_colorbar_ticks`, `period_axis_ticks`; `_nice_colorbar_bounds` → `nice_colorbar_bounds`) | `oceanarray.plotters.primitives` |
108
+ | `oceanarray.utilities._status`, `_format_rel_path` | `oceanarray.logger.status`, `logger.format_rel_path` |
109
+ | `oceanarray.tools.rapid_interp` | `oceanarray.pipeline.gridders.rapid_interp` |
110
+ | `oceanarray.tools.process_dataset`, `analysis.science.process_dataset`, `analysis.temporal.downsample_to_sparse` | `oceanarray.pipeline.gridders.climatology` |
111
+ | `oceanarray.tools` / `analysis.science` re-exports `calc_psal`, `calc_ds_difference`, `find_cold_entry_exit`, `isopycnal_dataset`, `isopycnal_pressure_series` | `oceanarray.analysis.hydrography` |
112
+ | `oceanarray.tools` / `analysis.science` re-exports `welch_psd`, `welch_psd_gapaware`, `compute_cwt` | `oceanarray.analysis.spectral` |
113
+ | `oceanarray.tools` re-exports `lag_correlation`, `split_value`, `downsample_to_sparse` | `oceanarray.pipeline.clock.offsets` (`lag_correlation`, `split_value`), `oceanarray.pipeline.gridders.climatology` (`downsample_to_sparse`) |
114
+ | `oceanarray.tools` re-exports `flag_salinity_outliers`, `flag_temporal_spikes`, `flag_vertical_inconsistencies`, `run_qc` | `oceanarray.legacy.qc_rodb` |
115
+ | `oceanarray.pipeline.helpers` (was `processors.helpers`): `STACK_VARS` and the stack helpers | `oceanarray.pipeline.stack`; the QC mask and worst-flag merge → `oceanarray.pipeline.qc` |
116
+ | `oceanarray.analysis.temporal.filter_sigma_tukey` | `oceanarray.pipeline.gridders.filters` |
117
+ | `oceanarray.analysis.clock` (`analyze_deployment_timing` → `deployment_timing`; + `analysis.temporal.lag_correlation`, `split_value`) | `oceanarray.pipeline.clock.offsets` |
118
+ | `oceanarray.analysis.vector.progressive_vector` | `oceanarray.plotters.current.progressive_vector` |
119
+ | `oceanarray.utilities` (`get_dims`, `check_necessary_variables`, `get_time_key`) | `oceanarray.pipeline.gridders.rapid_interp` |
120
+ | `oceanarray.utilities` (`concat_with_scalar_vars`) | `oceanarray.legacy.mooring_rodb` |
121
+ | `oceanarray.utilities` (`iso8601_duration_from_seconds`, `is_iso8601_utc`) | `oceanarray.legacy.convertOS` |
122
+ | `oceanarray.config.validation.print_validation_report` | removed (`oceanarray validate` prints the report) |
123
+ | `oceanarray.legacy.find_deployment` | `oceanarray.pipeline.clock.deployment` |
124
+ | `oceanarray.pipeline.caldip` (`normalize_serial` → `canonical_serial`) | `oceanarray.pipeline.calibration` |
125
+ | `oceanarray.pipeline.coordinate.apply_adcp_seabed_qc` / `_surface_qc` / `_velocity_qc` | `oceanarray.pipeline.qc.adcp` |
126
+ | `oceanarray.analysis.hydrographic` | `oceanarray.analysis.hydrography` |
127
+ | `oceanarray.analysis.science` QC flaggers (`flag_salinity_outliers`, `run_qc`, …) | `oceanarray.legacy.qc_rodb` |
128
+ | `oceanarray.analysis.vector.xyz_to_enu_2d` | `oceanarray.pipeline.coordinate.xyz_to_enu` (same values; returns `up` too) |
129
+ | `oceanarray.config.validation.serial_collision_errors` | `oceanarray.mooring.serial_collision_errors` |
130
+ | `oceanarray.pipeline._resolve_mooring` | `oceanarray.pipeline.resolve_mooring` (public) |
131
+
132
+ `oceanarray.tools`, `oceanarray.utilities`, `oceanarray.pipeline.helpers` and `oceanarray.legacy.tools` are gone.
133
+ `utilities.apply_defaults` is removed (no caller). `plotters.timeseries.draw_grid` is deprecated (see Deprecated).
134
+ - Plotting functions that return a Figure are `draw_<what>`, with no alias: `plotters.diagnostic.plot_knockdown_pressure` / `_hab` / `_anomaly` / `_displacement` / `plot_clock_offset_check`, `plotters.current.plot_temperature_trajectory` / `plot_speed_boxplot` / `plot_multi_aquadopp_trajectories` / `plot_hodograph` / `plot_aquadopp_speed_profile` / `plot_adcp_trajectories`, `plotters.primitives.plot_trajectory` and `plotters.plot_microcat_raw` / `plot_aquadopp_raw` / `plot_mooring_timeseries` → `draw_*`; `draw_isopycnal_ts_fig`, `draw_overflow_temperature_fig`, `draw_grid_fig` → `draw_isopycnal_ts`, `draw_overflow_temperature`, `draw_grid` (itself deprecated, see above). Report `source:` captions name the new functions.
135
+ - Removed, as their 0.5 deprecation warnings said: `pipeline.units.canonicalise_units` (use `to_canonical_units`), `pipeline.units.format_units` (use `config.unit_tables.unit_label`), `config.parameters.UNIT_ALIASES` and `VARIABLE_UNIT_ALIASES` (use `config.unit_tables.TABLES`).
136
+ - `readers.nortek.normalize_nortek_variables` → `to_canonical_nortek`, `readers.sbe.normalize_sbe_ascii` → `repair_sbe_ascii` (no alias: the `readers` package is new in 0.6).
137
+ - `TimeGriddingProcessor`, `time_gridding_mooring` and `process_multiple_moorings_time_gridding` are removed from `oceanarray.pipeline.grid`, with their optional low-pass/de-tiding/band-pass filters. No notebook or CLI verb used them; the stack (`oceanarray.pipeline.stack.stack`) is the one way to put a mooring on a common time axis.
138
+ - `oceanarray run` now calls `oceanarray.run`. It still carries on past failures, as before, and now records what it left out in the products (`instruments_omitted`, `keep_going_failures`, `source_stage`). It exits 0 when it finishes, even with instruments left out (before: 1). `--strict` stops at the first failing stage with exit code 1 and builds no report; `--stage` lists the stages (they must run through stage 3: `--stage 2 3`), `--from N` starts at stage N (`--from 2` runs stages 2 and 3 from the stage-1 files without `--raw-dir`). `--dry-run` lists every stage, stack, grid and report file the run would write; `--skip-existing` keeps report pages that exist. `--dt-seconds` (was `--dt`, accepted until 0.7.0), `--pmin`, `--pmax` and `--dp` on `run` default to the description's `stack:`/`grid:` blocks, and `pmin` / `pmax` are also the Python keywords and YAML keys.
139
+ - `oceanarray.processors` is renamed to `oceanarray.pipeline` (the verbs' bodies). Old → new: every `oceanarray.processors.*` import becomes `oceanarray.pipeline.*` (`stage1`, `stage2`, `stage3`, `stack`, `grid`, `qc`, `coordinate`, `pressure`, `units`, `process`, `run`); `processors.caldip` and `processors.helpers` moved again, see the table above. No deprecation shim.
140
+ - `oceanarray.writers.write(ds, path)` now refuses to replace an existing file by default — pass `overwrite=True` to replace one (the processing stages do). It logs an INFO line (`overwriting <path>`) when it replaces a file, and returns the `Path` written instead of `None`. Previously it overwrote silently.
141
+ - Output filenames are built from the mooring's `name:` field, not its directory name. A directory whose basename differs from `name:` is a WARNING (previously framed as "name must match the directory"); the files are named from `name`.
142
+ - `oceanarray.tools.readers` is removed; its readers moved to the `oceanarray.readers` package. Old → new: `oceanarray.tools.readers.read_oceansites` → `oceanarray.readers.read_oceansites` (or `oceanarray.readers.oceansites.read_oceansites`); `read_rodb` → `oceanarray.readers.read_rodb`; `load_nortek_csv` → `oceanarray.readers.load_nortek_csv`. The dead `load_dataset` and `rodbload_old` are removed with no replacement — use `oceanarray.readers.read` and `read_rodb`.
143
+
144
+ ### Fixed
145
+
146
+ - Positions no longer print `60.00′` or a hemisphere on zero, a `nan` position reads `—` instead of crashing the report, and the array report pairs latitude and longitude from one key pair and skips `(0, 0)` (#132).
147
+ - `oceanarray report --dry-run` honours `--only` and lists the recovery table with `--cruise-table`; `process --report` on an invalid description prints an ERROR line instead of a traceback; a loaded description passed to `oceanarray.report` rebuilds the summary page even when the page is newer than the YAML file.
148
+ - The stack T–S diagram, the instrument data histograms and the stack pressure range also leave out flag 3 (they left out only 4 and 9).
149
+ - A stack whose Aquadopps carry no east/north velocity (a stage-2 stack of beam-coordinate data) no longer loses its stack page.
150
+ - `oceanarray report --dry-run` lists the instrument pages at the paths they are written to (it printed paths in the processed-data directory).
151
+ - A report whose summary page is newer than its inputs still builds a missing or stale stack, grid or instrument page; before, the fresh summary stopped them all.
152
+ - The summary page is rebuilt when the stack or grid file is newer than it (it lists which instruments they hold), and is no longer rewritten on every run when it is up to date.
153
+ - On phones the report text no longer changes size between full-width and half-width sections: browser text autosizing is turned off (`text-size-adjust: 100%`), so every class renders at the size the stylesheet sets.
154
+ - Every report plot now leaves out only QC flags 3, 4 and 9 (`parameters.QC_BAD_FLAGS`): ADCP/Aquadopp current plots, roses, spectra and the grid velocity panels hid nominal (7) and interpolated (8) values too; the instrument rose's "good" panel (flags ≤ 2) now takes every usable flag (0–2, 7, 8).
155
+ - The stack report's Hydrography and Velocity panels left out values flagged nominal (7) or interpolated (8), so a sensorless instrument's interpolated pressure was missing from the pressure row; they now leave out only flags 3, 4 and 9 (`parameters.QC_BAD_FLAGS`). Both panels now carry their `source:` caption.
156
+ - An extrapolated pressure's `pressure_source` says what it is out of range of: the target's height above bottom against the range the pressure sources span.
157
+ - The netCDF writer stores `bool` attributes as `int8` (0/1) instead of failing: netCDF has no boolean attribute type.
158
+ - A Nortek header whose coordinate system cannot be read is now marked `coordinate_system = "UNK"` instead of being assumed `"ENU"`, and stage 3 refuses to rotate `UNK` velocities (with a WARNING) rather than passing them through as if geographic. Previously a BEAM/XYZ instrument with an unrecognised header was silently labelled ENU, skipping the BEAM→ENU transform and magnetic-declination correction — a silent physical error in the velocity output.
159
+ - Every reader drops records with no time (`NaT`, e.g. an originator's padding of a record that ended early), with a warning naming the file and the count; stage 1 records the count in a new `n_records_without_time` global attribute and a `history` line. A file with no timed record raises `ValueError`. (Before, only the OceanSITES reader dropped them, without a record in the file.)
160
+ - A RODB record with a fill (`-9999`) in `YY`, `MM`, `DD` or `HH` is dropped as having no time; a fill in `HH` could be read as midnight of that day.
161
+ - A RODB file with no data rows after its header raises `ValueError` "no data rows after the RODB header" instead of numpy's column-count error.
162
+ - Stage 2 refuses a stage-1 file with records that have no time (`MooringError` naming the instrument and the count; re-run stage 1), instead of failing in the deployment-window trim.
163
+ - Stage 3 no longer fails on a BEAM/XYZ Aquadopp in a mooring with no position: its `history` says "declination not applied (position unknown)".
164
+ - The stack no longer fails on an instrument whose `magnetic_declination` is `"UNK"`: its level is NaN in the per-level `magnetic_declination`, whose `comment` names the levels with an unknown declination.
165
+
166
+ ## [0.5.1] — 2026-10-23
167
+
168
+ > The units-display entries — *Units tables come from the shared report layer*, *N² keeps the spelling it arrives with*, *Legacy vocabulary files moved and renamed*, and the two *Deprecated* items — landed as direct-to-main commits (`cdcffc9`/`8982831`/`735adaa`, the units display sweep), not a pull request; [#107](https://github.com/ocean-uhh/oceanarray/pull/107) documented the sweep and added the derived-quantity guard. See `.claude/done/ROADMAP.md`.
169
+
170
+ ### Changed
171
+
172
+ - **Post-release tidy** ([#105](https://github.com/ocean-uhh/oceanarray/pull/105)): `find_best_dtype` passes `timedelta64` variables through with their native kind instead of miscasting them; the dead `proc_machine` report-context key is removed; the CLI reference page is generated from the argument parser (`sphinx-argparse`); CONTRIBUTING and the README scope line refreshed.
173
+
174
+ - **Vendored report-design layer adopted** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)): the report presentation layer moves to `oceanarray/reports/_vendored/`, a directory copied byte-identical from ctdcast `15fa38b` that carries its own `MANIFEST.txt` and self-check (`check.py`). The six scattered vendored files (`config/report_tokens.py`, `config/report.mplstyle`, `reports/_encode.py`, `_css.py`, `_manifest.py`, `templates/_nav.html`), the root `VENDORED.txt`, and `scripts/check_vendored.py` are removed; a new owned `reports/design.py` holds the oceanarray-specific configuration (package accent, QC/sensor predicates, `ATTR_GROUP_EXTRAS`, the per-figure source toggle). `reports/__init__.py` resolves its public names lazily so importing the vendored layer does not pull the page pipeline. No change to the NetCDF outputs or the public API.
175
+ - **NetCDF-inventory tables rendered by the vendored builders** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)): the coordinates/variables/scalars/globals tables now come from the shared `nc_tables` builders and `_nc_tables.html` macros. Type labels read `string` rather than `str`, each table carries a `source:` caption, the coordinates table gains a Dims column, and the `history` global attribute is shown once (in its dedicated processing-history panel, excluded from the globals table via the builder's `exclude=`). An all-empty Standard/long-name column drops along with units/min-max/attributes (`optional=` includes `stdname`). The QC-companion marker shows the file's real suffix — `(_qc)` for oceanarray's lowercase QC variables, not a hard-coded `(_QC)` — and is coloured with the shared `--qc-mark` token. The local inventory templates and row builders are removed.
176
+ - **Processing-history panel is now tables** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)): the instrument/grid/stack reports render the processing history as a key/value `properties_table` for the header items plus a sortable Time·Event table for the dated entries (a `|`-joined entry splits into same-time rows), replacing the `dl`-style list that wrapped long entries into orphan rows. The Time·Event table carries a leading `#` column — the row's 1-based position in the `history` attribute — so sorting any column never loses the original sequence (events sharing one timestamp would otherwise be unorderable).
177
+ - **Array page map** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)): the mooring-position map is the vendored Leaflet `track_map` (a marker per mooring, each carrying a permanent name label in the marker's colour, hover-linked to the mooring list via `data-track-id`, offline bundled assets) behind the `design.ARRAY_MAP_LEAFLET` flag — the interactive map on screen, its matplotlib PNG fallback when printing (never both). The static PNG gains a `source:` caption, a Mercator-square framed extent (a line of moorings no longer renders as a sliver), and family marker colours; the mooring name links to its report and the jump-nav uses the family markup.
178
+ - **Array masthead metadata** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)): the array summary masthead gains deployment/recovery and duration, position and mooring extent, water-depth range, an instrument by-type breakdown, deployment status, and processed-to counts — all read or derived from the array/mooring YAMLs at render (a missing value is an em-dash).
179
+ - **base.html de-duplicated against the shared stylesheet** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)): report chrome rules that `emit_css()` already provides are removed from the per-page `<style>` block (only the oceanarray-specific additions remain), guarded by `test_no_base_rule_duplicates_vendored_css`.
180
+ - **Absent figure panels say why** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)): a figure whose draw raises now renders a short stub with the reason instead of vanishing (`as_panel`, ported from ctdcast).
181
+ - **Coverage floor raised** ([#106](https://github.com/ocean-uhh/oceanarray/pull/106)) from 38% to 58%: `main` and this branch both measure 59% unit coverage, so the CI `--cov-fail-under` gate is ratcheted to one point below.
182
+ - **Units tables come from the shared report layer**: the vendored layer is re-copied from ctdcast `f2af1d8`, where `units_display.py` became `units.py` + `units_tables.py` (canonical spellings, accepted aliases with factors, display labels, keyed by CF `standard_name`). `oceanarray.config.unit_tables` holds oceanarray's differences from those tables (N² stored as `s-2`; the `ml l-1`, `mL/L` and `s⁻²` spellings) and `unit_label()`, the display entry point the plotters now call. The storage pass is `processors.units.to_canonical_units`. It accepts the same spellings as before for every registry quantity (N² aside, below), still takes each variable's canonical spelling from `parameters.VARIABLES`, still raises on a missing units attribute, and still records `units_converted_from` / `units_conversion_factor` on a conversion; the dune2 goldens are byte-identical.
183
+ - **Plot-axis units derived from the registry through the pipeline** ([#107](https://github.com/ocean-uhh/oceanarray/pull/107)): `parameters.vunit`/`vlabel` now format each variable's canonical CF `units` through `unit_label` (`degree_Celsius` → `°C`), so every axis/colorbar label is produced by the one display rule; the duplicate `label_units` column is removed from `VARIABLES`. The attitude/engineering variables `pitch`, `roll`, `heading`, `tilt`, `current_direction`, `bin_pressure` are registered (canonical CF `degree`/`dbar`), and the reader spellings `degrees`/`volts` are accepted as aliases of `degree`/`V`; the storage pass rewrites a stored `degrees` to `degree` at factor 1. Rendered labels are unchanged.
184
+ - **Derived-quantity unit guard** ([#107](https://github.com/ocean-uhh/oceanarray/pull/107)): a plot whose output unit is computed from a source variable (displacement in km from velocity, height-above-seabed in m from pressure, instrument spacing in dbar, temperature PSD) warns via `unit_tables.warn_if_not_canonical` when the source variable does not carry the canonical unit the derivation assumes. Silent on every oceanarray-written file (the storage pass guarantees canonical units); it catches a foreign or hand-edited file the derivation would otherwise mislabel.
185
+ - **N² keeps the spelling it arrives with**: `s-2` and `rad2 s-2` are both accepted and neither is rewritten into the other (`rad2 s-2` used to be refused), so N² is the one quantity whose stored spelling can differ between files.
186
+ - **Legacy vocabulary files moved and renamed**: `config/OS1_var_names.yaml`, `config/OS1_sensor_attrs.yaml` and `legacy/OS1_vocab_attrs.yaml` are now `legacy/OS1_variable_names.yaml`, `legacy/OS1_sensor_attributes.yaml` and `legacy/OS1_variable_attributes.yaml`, beside the legacy `convertOS.py` that takes them as inputs. No other oceanarray code reads them; the wheel no longer ships them.
187
+ - **Report figure layout** ([#110](https://github.com/ocean-uhh/oceanarray/pull/110)): a single-tier current rose (one QC tier, no magnetic panel) renders as a third-slot circle centred in whitespace instead of a full-slot-width square; the knockdown-displacement figure reserves left margin for its pressure y-labels so a deep mooring's four-digit dbar labels no longer clip. The unreachable `GRID_COMBINED_HYDRO` grid profile is removed (T-S stays its own section).
188
+ - **`°` accepted as a degree spelling** ([#110](https://github.com/ocean-uhh/oceanarray/pull/110)): the storage pass accepts the `°` symbol as the canonical `degree` (factor 1) for attitude variables. `deg` is not accepted here — it is scoped to latitude/longitude in the vendored unit tables and arrives, scoped, at the next vendored sync.
189
+ - **Report layer re-vendored from ctdcast v0.4.0** ([#111](https://github.com/ocean-uhh/oceanarray/pull/111)): the `degree`/`degrees`/`°` alias moves into the vendored family tables (the duplicate package-side copy is removed; unit resolution is unchanged). The array-map graticule gains edge labels drawn inside the west/south edges, a bottom-right scale bar, and antimeridian handling for basin-scale tracks.
190
+ - **ADCP bin pressures are tilt-corrected for knock-down** ([#112](https://github.com/ocean-uhh/oceanarray/pull/112)): `compute_adcp_bin_pressure` reduces each bin's vertical range by `cos(θ)` (θ = instrument tilt from pitch/roll, `arccos(cos P_true·cos R)`) before converting to pressure, so a knocked-down profiler's bins are placed at their true depth; `bin_pressure` gains `tilt_correction` / `tilt_definition` attributes. When the firmware recorded earth coordinates with bin mapping on (RDI `EX` command), it has already tilt-placed the bins, so the correction is **not** applied (`tilt_correction = "none (firmware bin mapping)"`). Every current UHH deployment is earth + bin-mapping, so stored outputs are unchanged; the correction is exercised only by beam-coordinate input. Stage 1 surfaces `firmware_coordinate_system` / `firmware_bin_mapping` from the raw metadata for the guard.
191
+
192
+ ### Added
193
+
194
+ - **Readers for files already processed by their originator** ([#108](https://github.com/ocean-uhh/oceanarray/pull/108)): `file_type: oceansites` (OceanSITES 1.3 netCDF, and the OSNAP variant with variables on `TIME`) and `file_type: rodb` (RAPID/BODC `.microcat`, `.edt`, `.lowedt`), in `oceanarray.tools.readers` (`read_oceansites`, `read_rodb`). Variables are renamed to oceanarray names; the originator's QC flags are kept as `<name>_qc_originator`; the originator's metadata as `originator_*` attributes. Velocities are geographic, so Stage 3 applies no rotation and no second magnetic declination (`originator_magnetic_declination`). New instrument class `currentmeter` for a processed point current meter. Tested on trimmed real OSNAP files (WHOI, GEOMAR, Scripps, RODB) in `tests/fixtures/raw/osnap/`.
195
+ - **`units_override`** ([#108](https://github.com/ocean-uhh/oceanarray/pull/108)) per instrument in the mooring YAML corrects a file whose units attribute is wrong; Stage 1 refuses an imported (`oceansites` / `rodb`) instrument whose values fall outside the registry's valid range for the stated units, naming this key.
196
+ - **`stack: false`** ([#108](https://github.com/ocean-uhh/oceanarray/pull/108)) per instrument in the mooring YAML keeps an instrument out of the stack and grid while it is still processed through stages 1-3 and reported (reference data); the stack names it in an `instruments_excluded` attribute. A low-passed file (`originator_low_passed`, e.g. RODB `.lowedt`) reaching the stack without it is omitted with an error naming the key.
197
+ - Unit spellings accepted: `decibar`, `meter/second`, `meter`, `psu` (practical salinity only), and RODB `cm s-1` (converted ×0.01 to `m s-1`).
198
+
199
+ ### Deprecated
200
+
201
+ - `oceanarray.processors.units.canonicalise_units` → `to_canonical_units`, and `oceanarray.processors.units.format_units` → `oceanarray.config.unit_tables.unit_label`. The old names warn and are removed in 0.6.0.
202
+ - `oceanarray.parameters.UNIT_ALIASES` and `VARIABLE_UNIT_ALIASES`: the spellings now live in the shared units tables (`oceanarray.config.unit_tables.TABLES`, with `PSU` / `NTU` scoped by CF `standard_name`). Both names still resolve, rebuilt from those tables, with a warning; removed in 0.6.0.
203
+
204
+ ### Breaking changes
205
+
206
+ - None. The NetCDF outputs and the public API (`oceanarray` CLI, `from oceanarray.reports import MooringReport`) are unchanged. The report HTML changes (masthead nav, inventory-table layout and type labels, `source:` captions); the committed report goldens are rebaselined to match.
207
+
208
+ ## [0.5.0] — 2026-10-12
209
+
210
+ ### Added
211
+
212
+ - **Serial-uniqueness validation** ([#101](https://github.com/ocean-uhh/oceanarray/pull/101)): `validate` refuses duplicate serials within a mooring, a blank serial, and the reserved names `stack`/`grid` (which would collide the per-instrument report filenames `{mooring}_{serial}_report.html`). A trailing `*` is stripped before every check — `1234` and `1234*` on one mooring are a duplicate, a serial that is only `*` is blank — and stays a diagram-only "pay attention to this sensor" annotation, never carried into filenames or nav labels.
213
+
214
+ ### Changed
215
+
216
+ - **Report NetCDF-inventory appendix restyled** ([#103](https://github.com/ocean-uhh/oceanarray/pull/103)): the instrument, stack and grid reports share one inventory appendix — a Coordinates table (one row per coordinate variable: type, units, standard/long name, min/max, N valid, attributes), variables grouped by dimension set, QC companions shown inline as a green `(_QC)`, and global attributes split into named groups with a Type column; the per-page variable/scalar/globals templates collapse to one shared set, and the grid page gains a coordinates table it never had. The dune2 test fixture units were canonicalised in place (14 attribute edits, data byte-identical) and the hosted dune2 example suite regenerated. `demo_mooring.ipynb` is ported to `oceanarray.processors.process` and runs on the committed fixture from a clean checkout; `demo_step1.ipynb` is removed, and five old-API demo notebooks move to `notebooks/legacy/`.
217
+ - **Shared masthead nav** ([#100](https://github.com/ocean-uhh/oceanarray/pull/100)): the report masthead navigation is rebuilt from the shared vendored macro, and the six report-design files are re-vendored from ctdcast with a vendoring guard (`scripts/check_vendored.py`).
218
+ - **Canonical units at every stage** ([#102](https://github.com/ocean-uhh/oceanarray/pull/102)): one canonical spelling per quantity is now written to every file — `degree_Celsius`, `mS cm-1`, `dbar`, `m`, `m s-1`, `umol kg-1`, `g kg-1`, `kg m-3`, `1` (practical salinity and turbidity). A registry-scoped pass (`oceanarray.processors.units.canonicalise_units`) runs on the way out of every stage, rewriting the reader spellings (`degC`, `mS/cm`, `meters`, `db`, `S/m`→×10) to the canonical and recording any value conversion in `units_converted_from` / `units_conversion_factor`. Temperature variables carry CF-1.11 `units_metadata = "temperature: on_scale"`. Plot labels are derived from the canonical string by `format_units` (slash form: `mS/cm`, `m/s`, `kg/m³`, `µmol/kg`, `°C`, `PSU`, `NTU`).
219
+
220
+ - **Single netCDF writer** ([#98](https://github.com/ocean-uhh/oceanarray/pull/98)): the six write paths the processing stages used before now go through one `oceanarray.writers.write` seam. The files that were written uncompressed — the seasenselib-written stage files, whose compression parameters its writer silently discarded, and the bare-`to_netcdf` stage3 output — shrink 58–66% on the dune2 fixtures. The two that were already zlib level-5 compressed — the pressure-gridded and stacked outputs — grow about 1% as they move to the common level-4 setting. Decoded values, dtypes, attributes, and time encoding are unchanged; raw values are byte-identical, verified per stage against the old writer. The private `_get_netcdf_writer_params` methods are removed, including the `quantize` key, which was never a valid netCDF4 encoding parameter and never took effect.
221
+ - **Windows log encoding** ([#98](https://github.com/ocean-uhh/oceanarray/pull/98)): `stage1/2/3` open their per-stage log file as UTF-8. On Windows the default cp1252 encoding raised on the ADCP `BEAM→ENU` log message, which aborted the instrument and silently dropped it from the output.
222
+ - **`oceanarray.writers` exposed** ([#99](https://github.com/ocean-uhh/oceanarray/pull/99)): `import oceanarray as oa; oa.writers.write(ds, path)` now resolves after a bare import.
223
+ - **cftime time coordinates preserved** ([#99](https://github.com/ocean-uhh/oceanarray/pull/99)): a time coordinate decoded with `use_cftime=True` (object dtype, e.g. a non-standard calendar) now keeps its `units` and `calendar` on write instead of letting xarray re-guess the epoch from the data. Numpy `datetime64` time is still pinned to the 1970 epoch; only object-dtype cftime time is affected.
224
+ - **Python 3.13 supported** ([#99](https://github.com/ocean-uhh/oceanarray/pull/99)): added to the classifiers and promoted to a required (no longer allow-failure) CI leg.
225
+
226
+ ### Breaking changes
227
+
228
+ - **Units spellings in output files changed** ([#102](https://github.com/ocean-uhh/oceanarray/pull/102)): every processed file now carries the canonical units spelling per quantity (above), so a reader matching the old strings (`degC`, `mS/cm`, `meters`, `S/m`, …) must adapt. An unrecognised or missing `units` on a registered variable now **stops that instrument** (`UnitsError`) rather than passing through silently — one bad instrument is logged with its file and skipped, the rest process; the stack still builds but records the omission in an `instruments_omitted` attribute and exits 1. The `dissolved_oxygen` registry entry is corrected to per-mass `umol kg-1` (standard_name `moles_of_oxygen_per_unit_mass_in_sea_water`); turbidity is dimensionless `1` (display label `NTU`). Conductivity in `S/m` is converted ×10 to `mS cm-1` by the units pass, replacing the old `conductivity_normalised_from` attribute with `units_converted_from` / `units_conversion_factor`.
229
+ - **`process` runs stage 3 by default** ([#102](https://github.com/ocean-uhh/oceanarray/pull/102)): `oceanarray process MOORING` with no `--stage` now runs stages 1, 2 and 3 (was 1 and 2). Pass `--stage 1 2` for the old raw→trim-only behaviour. The help text already described "stages 1-3"; the code now matches it.
230
+ - **Oxygen saturation / AOU recomputed on the correct basis** ([#102](https://github.com/ocean-uhh/oceanarray/pull/102)): `derive_oxygen_saturation` previously divided per-mass `dissolved_oxygen` by in-situ density as if it were per-volume, making `oxygen_saturation_pct` and `apparent_oxygen_utilization` ~2.5% low. It now uses a per-mass (`umol kg-1`) input directly and divides only a genuine per-volume (`umol L-1`) variable. Regenerated oxygen products change by the density factor; moorings without an oxygen sensor (the dune2 example) are unaffected.
231
+ - **Minimum Python raised to 3.11** ([#99](https://github.com/ocean-uhh/oceanarray/pull/99)): `requires-python` is now `>=3.11`; the 3.10 classifier and CI leg are dropped. Python 3.10 reached end-of-life, and the core dependencies (xarray, pandas, numpy, matplotlib, gsw, scipy) already require 3.11 — so a 3.10 install silently resolved years-old, untested versions of the whole stack.
232
+
233
+ - **Dead output helpers removed** ([#99](https://github.com/ocean-uhh/oceanarray/pull/99)): `oceanarray.tools.writers.save_dataset` and `save_OS_instrument` are deleted, and `oceanarray/tools/writers.py` with them. Neither had a working caller (only tests and a dead `if 0:` notebook cell); `save_dataset` also wrote `NETCDF4_CLASSIC`, a format nothing else produced. Use `oceanarray.writers.write`. Two legacy notebooks (`notebooks/legacy/demo_batch_instrument.ipynb`, `notebooks/legacy/demo_instrument_rdb.ipynb`) still reference `save_OS_instrument` and no longer run; they are not CI-executed and are left for the notebook refresh.
234
+ - **`None` attributes dropped, not blanked** ([#99](https://github.com/ocean-uhh/oceanarray/pull/99)): a `None`-valued attribute (global or per-variable) is now dropped with a warning instead of written as `""`. `UNK` belongs where a value is determined, not the write seam. On the dune2 fixtures no attribute is affected (0/84 globals are empty); this is a guardrail.
235
+ - **Time encoding pinned** ([#99](https://github.com/ocean-uhh/oceanarray/pull/99)): every datetime variable is written as `seconds since 1970-01-01` (float64, `proleptic_gregorian`) rather than xarray's per-file guess. Decoded instants change by at most 0.13 µs (float64 seconds have ~238 ns spacing at the 2026 epoch, so ≤119 ns rounding; ~0.5 µs by 2050) — negligible against clock drift, which is corrected in whole seconds. **Raw stored values change**, so a reader using `decode_times=False`/`decode_cf=False` sees different numbers. This also removes a pandas-version dependence in the units string (space vs `T`).
236
+
237
+ ### Known issues
238
+
239
+ - **Empty-units turbidity files**: a registered variable with an empty `units` fails that one instrument at stage 1 — the handler logs `ERROR: <file>: <reason>`, skips the instrument, and the mooring completes with the others and a non-zero exit (the family rule). Six turbidity files on the drive are affected; the reader fix lands in 0.5.1.
240
+ - **dune2 test fixture stack/grid**: the committed `_stack.nc`/`_grid.nc` fixtures reference instruments not present in the committed raw and YAML — they were built from the full mooring before the fixture was trimmed to two instruments — so running `oceanarray run` on the fixture collapses the stack to those two. A known fixture inconsistency, rebuilt in 0.5.1.
241
+
242
+ ## [0.4.0] — 2026-09-08
243
+
244
+ ### Added
245
+
246
+ - **caldip calibration-dip stub** ([#92](https://github.com/ocean-uhh/oceanarray/pull/92)): `processors/caldip.py` carries the shared contract (constants, `normalize_serial`, `Offsets`) and a five-function interface for the planned front-of-Stage-3 correction. Stage 3 gains a `caldip_dir` argument that is a null action — it logs a warning and stamps a `caldip_applied` provenance attribute — until the correction lands.
247
+ - **PDF reports**: `report --pdf` renders a merged A4 PDF per mooring ([#69](https://github.com/ocean-uhh/oceanarray/pull/69)); `report --pdf-dir DIR` collects each mooring's PDF into one directory ([#90](https://github.com/ocean-uhh/oceanarray/pull/90)), which also sped up PDF rendering (~50 s → ~6 s).
248
+ - **Manifest-driven report system**: a section-manifest model and resolver ([#78](https://github.com/ocean-uhh/oceanarray/pull/78)) now drive the grid ([#79](https://github.com/ocean-uhh/oceanarray/pull/79)) and stack / instrument / mooring ([#80](https://github.com/ocean-uhh/oceanarray/pull/80)) report pages — per-page registries, automatic panel numbering, generated jump-nav, and defect-visible stubs.
249
+ - **`oceanarray run` report redirection** ([#88](https://github.com/ocean-uhh/oceanarray/pull/88)): `run` accepts `-o/--output-dir`, `--report-dir`, and `--sig-level`, threaded through to the report step, so the full pipeline can write a portable central report tree with custom grid isopycnal targets in one command.
250
+ - **Zenodo DOI** ([#68](https://github.com/ocean-uhh/oceanarray/pull/68)): concept-DOI badge in the README and `CITATION.cff`.
251
+ - A hosted, clickable dune2 example report suite in the docs ([#82](https://github.com/ocean-uhh/oceanarray/pull/82)).
252
+
253
+ ### Changed
254
+
255
+ - **Report subsystem refactor**: vendored the shared design tokens, encoder, and CSS ([#71](https://github.com/ocean-uhh/oceanarray/pull/71)); added a golden-file regression net ([#72](https://github.com/ocean-uhh/oceanarray/pull/72)); renamed `report/` → `reports/` ([#73](https://github.com/ocean-uhh/oceanarray/pull/73)); reworked page templates ([#74](https://github.com/ocean-uhh/oceanarray/pull/74)); encoder / figure sizing ([#75](https://github.com/ocean-uhh/oceanarray/pull/75)); uniform layout fixes ([#76](https://github.com/ocean-uhh/oceanarray/pull/76), [#77](https://github.com/ocean-uhh/oceanarray/pull/77)); plot polish — colorbar ticks, cyclic current direction, T-S bounds, tilt panels ([#83](https://github.com/ocean-uhh/oceanarray/pull/83)); layout polish — shared title helper, trajectory y-labels, clock legend, rose whitespace ([#84](https://github.com/ocean-uhh/oceanarray/pull/84)); smaller files, updated fonts, and multi-panel pagination ([#70](https://github.com/ocean-uhh/oceanarray/pull/70)).
256
+ - **Packaging**: consolidated configuration into `pyproject.toml`, expanded the CI test matrix, and added a ruff lint gate ([#86](https://github.com/ocean-uhh/oceanarray/pull/86)); moved the dev install to pyproject extras ([#85](https://github.com/ocean-uhh/oceanarray/pull/85)); dropped the unused direct `dolfyn` dependency ([#81](https://github.com/ocean-uhh/oceanarray/pull/81)).
257
+ - **Docs**: PyPI-first install instructions ([#81](https://github.com/ocean-uhh/oceanarray/pull/81)); caldip documented as the planned optional front-of-Stage-3 correction ([#91](https://github.com/ocean-uhh/oceanarray/pull/91)).
258
+
259
+ ### Fixed
260
+
261
+ - Cross-page links now resolve in the merged PDF — the document is built once and rendered once, with per-page anchor-id namespacing ([#89](https://github.com/ocean-uhh/oceanarray/pull/89)).
262
+ - Conservative QC-flag resampling fix, with unit tests added for the pressure, helpers, and qc paths ([#87](https://github.com/ocean-uhh/oceanarray/pull/87)).
263
+ - `process` / `report` / `run` `--help` no longer crash on Python 3.11 — an argparse usage-formatting `AssertionError` from a single-member mutually-exclusive group around the suppressed `--basedir` flag; the group is removed ([#88](https://github.com/ocean-uhh/oceanarray/pull/88)).
264
+
265
+ ### Breaking changes
266
+
267
+ - **`oceanarray stack` / `oceanarray grid` removed** ([#88](https://github.com/ocean-uhh/oceanarray/pull/88)): the standalone subcommands (deprecated since 0.2.0) are deleted. Use `oceanarray process MOORING --stage stack grid` — all flags (`--dt`, `--dp`, `--pmin`, `--pmax`, `--force`, `--proc-dir`) carry over; `stack`/`grid` remain available as `--stage` tokens.
268
+ - **`oceanarray logsheet` removed** ([#88](https://github.com/ocean-uhh/oceanarray/pull/88)): the disabled subcommand is deleted (now an argparse "invalid choice" error, not a `DeprecationWarning`). Use the standalone [`logsheet`](https://github.com/eleanorfrajka/logsheet) package.
269
+ - **Python 3.9 dropped** ([#85](https://github.com/ocean-uhh/oceanarray/pull/85)): the minimum supported version is now 3.10.
270
+ - Internal: `oceanarray.cli.cmd_stub` renamed to `cmd_init`; `cmd_stack`, `cmd_grid`, `cmd_logsheet` deleted. Affects only code importing these functions directly; the `oceanarray init` command is unchanged.
271
+
272
+ ---
273
+
274
+ ## [0.3.0] — 2026-08-11
275
+
276
+ ### Breaking changes
277
+
278
+ - **`oceanarray.logsheet` subpackage deleted** ([#66](https://github.com/ocean-uhh/oceanarray/pull/66)): the deprecated `logsheet` subpackage has been removed from the tree. `oceanarray logsheet` still emits a `DeprecationWarning` and exits 1. Use the standalone [`logsheet`](https://github.com/eleanorfrajka/logsheet) package: `pip install git+https://github.com/eleanorfrajka/logsheet`, then `logsheet build ...`.
279
+ - **`oceanarray run` skips grid when stack fails** ([#65](https://github.com/ocean-uhh/oceanarray/pull/65)): if the stack stage fails, the grid stage is now skipped rather than attempted on incomplete input. This matches `process()` behaviour.
280
+
281
+ ### Bug fixes
282
+
283
+ - **Grid report N² computed at latitude 0**: the grid report derived buoyancy frequency (N²) at latitude 0° because its `_dms_to_deg` import still pointed at the removed `mooring_level` module and failed silently inside a broad `except`. The import now resolves from `utilities`, so N² uses the mooring's actual latitude.
284
+
285
+ ### Refactoring
286
+
287
+ - **`STAGES` registry as single source of truth in CLI dispatch** ([#65](https://github.com/ocean-uhh/oceanarray/pull/65)): `process()` accepts a stage list (always applied in `STAGES` order); `cmd_process` and `cmd_run` route through a single `process()` call; argparse `choices` are derived from `STAGES`.
288
+ - **Plot/report hardening** ([#64](https://github.com/ocean-uhh/oceanarray/pull/64)): `render_b64` guard, `plt.style.context`, `vlabel()` helper, `SIGMA_GRID` fix, and a `VARIABLES` registry (21 entries with `valid_min`/`valid_max`).
289
+
290
+ ### Documentation
291
+
292
+ - Updated developer docs (`project_structure.md`, `methods/standardisation.rst`, `methods/vertical_gridding.rst`, `methods/nortek_coordinate_transform.rst`, `legacy.rst`) to the current `oceanarray.processors.*` module layout after the reorg; fixed broken import examples and API references.
293
+
294
+ ### Tests
295
+
296
+ - Golden Stage 1 tests, reader and `_array` helper tests, plus associated bug fixes and dead-code removal ([#63](https://github.com/ocean-uhh/oceanarray/pull/63)).
297
+
298
+ ---
299
+
300
+ ## [0.2.0] — 2026-08-07
301
+
302
+ ### Breaking changes
303
+
304
+ - **`oceanarray logsheet` disabled**: calling `oceanarray logsheet` now emits a `DeprecationWarning` and exits 1. The `logsheet` subpackage remains in the tree but is unused (deleted in v0.3.0). Use the standalone [`logsheet`](https://github.com/eleanorfrajka/logsheet) package: `pip install git+https://github.com/eleanorfrajka/logsheet`, then `logsheet build ...`.
305
+ - **`--basedir` removed** ([#52](https://github.com/ocean-uhh/oceanarray/pull/52)): use `--raw-dir` and `--proc-dir` instead. See the [migration guide](https://ocean-uhh.github.io/oceanarray/migration.html).
306
+ - **`plotter.py` retired** ([#53](https://github.com/ocean-uhh/oceanarray/pull/53)): the monolithic `oceanarray/plotter.py` and all backward-compatibility re-export shims have been removed. Import from canonical modules (`oceanarray.plotters.current`, `oceanarray.plotters.timeseries`, etc.).
307
+ - **Subpackage reorganisation** ([#49](https://github.com/ocean-uhh/oceanarray/pull/49), [#59](https://github.com/ocean-uhh/oceanarray/pull/59)): processing modules moved from `oceanarray/instrument/` and `oceanarray/mooring/` into `oceanarray.processors.*`. Top-level `oceanarray` imports unchanged; internal paths have moved.
308
+
309
+ ### New features
310
+
311
+ - **`--stage stack grid` in `oceanarray process`**: the `--stage` flag now accepts `stack` and `grid` in addition to `1`, `2`, `3`. Run the full pipeline as `oceanarray process MOORING --stage 1 2 3 stack grid`. New flags `--dt`, `--dp`, `--pmin`, `--pmax` added to `process` (same defaults as `oceanarray run`).
312
+ - **`process()` public API** ([#58](https://github.com/ocean-uhh/oceanarray/pull/58)): `oceanarray.process(mooring_yaml, proc_dir, stages=…)` runs any combination of Stage 1–3, stack, and grid in a single call. `oceanarray.STAGES` is the registry of available stages.
313
+ - **Array report** ([#48](https://github.com/ocean-uhh/oceanarray/pull/48)): `oceanarray report <array.yaml> --array` generates a multi-mooring HTML summary with smart rebuild (only re-renders sections whose NC files are newer than the existing report).
314
+ - **Wave / frequency diagnostics** ([#47](https://github.com/ocean-uhh/oceanarray/pull/47)): rotary power spectra, near-inertial band energy, and wave diagnostics added to ADCP instrument reports.
315
+ - **Release automation** ([#61](https://github.com/ocean-uhh/oceanarray/pull/61)): pushing a `v*` tag now auto-creates a draft GitHub release with PR-based release notes; publishing the draft triggers PyPI upload.
316
+
317
+ ### Bug fixes
318
+
319
+ - **QC flags unified to OceanSITES table** ([#54](https://github.com/ocean-uhh/oceanarray/pull/54)): all QC flag values now use the standard OceanSITES convention (0 no QC, 1 good, 2 probably good, 3 probably bad, 4 bad, 9 missing). Previously mixed conventions caused flag collisions on merge.
320
+ - **Plot regularisation** ([#50](https://github.com/ocean-uhh/oceanarray/pull/50)): fixed irregular time-axis sampling in instrument report figures.
321
+ - **Turbidity `units=MISSING`** ([#61](https://github.com/ocean-uhh/oceanarray/pull/61)): stage1 now strips placeholder `units` strings (`"MISSING"`, `""`) written by the RBR RSK reader when the instrument database has no units entry, and emits a `UserWarning` so the operator can verify the sensor spec.
322
+
323
+ ### Deprecations
324
+
325
+ - **`oceanarray stack`**: deprecated in favour of `oceanarray process MOORING --stage stack`. Emits `DeprecationWarning`. Will be removed in v0.3.0.
326
+ - **`oceanarray grid`**: deprecated in favour of `oceanarray process MOORING --stage grid`. Emits `DeprecationWarning`. Will be removed in v0.3.0.
327
+ - `file_type: rbr-hex-oa` remapped automatically to `rbr-hex` with a `DeprecationWarning`; update mooring YAMLs.
328
+ - `file_type: sbe-asc` remapped automatically to `sbe-ascii`.
329
+
330
+ ### Refactoring
331
+
332
+ - Single-source variable registries in `parameters.py`; `validation.py` derives from it ([#51](https://github.com/ocean-uhh/oceanarray/pull/51)).
333
+ - Figure-returning shape for `report/_plots.py` ([#56](https://github.com/ocean-uhh/oceanarray/pull/56)); `draw_*` helpers relocated to `plotters/` ([#57](https://github.com/ocean-uhh/oceanarray/pull/57)).
334
+ - Type annotations backfilled on `hydrographic.py` and `temporal.py`; two ANN per-file-ignores removed from `pyproject.toml`.
335
+
336
+ ### Tests
337
+
338
+ - Integration chain tests (stage1 → stage2 → stage3 → stack → grid) over committed `dune2_1_2026` fixtures ([#60](https://github.com/ocean-uhh/oceanarray/pull/60)).
339
+ - CI: integration job now installs seasenselib from PyPI; Windows and macOS unit jobs run seasenselib-free.
340
+
341
+ ---
342
+
343
+ ## [0.1.0] — 2026-07-27
344
+
345
+ First public release.
346
+
347
+ ### Processing pipeline
348
+
349
+ - **Stage 1** — raw instrument files → CF-NetCDF: Sea-Bird SBE37 MicroCAT (`sbe-cnv`, `sbe-ascii`), Nortek Aquadopp (`nortek-raw`, `nortek-ascii`, `nortek-csv`), RBR Solo/Duet (`rbr-rsk`, `rbr-dat`), RDI WorkHorse ADCP (`rdi-raw`). Nortek BEAM→XYZ transformation matrix parsed from `.hdr` file and applied at stage 1; matrix stored in output for reproducibility.
350
+ - **Stage 2** — deployment trimming (YAML `deployment_time`/`recovery_time`) and linear clock-drift correction from recovery timestamps.
351
+ - **Stage 3** — QARTOD gross-range and spike QC on T/C/S/P; pressure interpolation (QC flag 8) for instruments without a pressure sensor; Aquadopp XYZ→ENU rotation using heading/pitch/roll + IGRF magnetic declination (`ppigrf`); tilt QC on velocity; potential density via `gsw`.
352
+
353
+ ### Mooring-level commands
354
+
355
+ - `oceanarray stack` — resample all instruments to a common time axis, stack into a single `(time, N_LEVELS)` dataset ordered deep-first.
356
+ - `oceanarray grid` — linearly interpolate the stacked dataset onto a regular pressure grid (`--pmin`, `--pmax`, `--dp`).
357
+
358
+ ### Reporting
359
+
360
+ - `oceanarray report` — self-contained HTML reports (all figures base64-embedded, offline-readable):
361
+ - Mooring summary: deployment metadata, instrument pipeline status, QC flag breakdown, clock corrections, knockdown figures, clock alignment check.
362
+ - Per-instrument pages (`--instruments`): full time series with QC markers, T-S diagram, current roses, data histograms, QC table, scalar metadata.
363
+ - Stack report (`--stack`): pressure/T/S/velocity time series, T-S diagram, current roses, spacing histogram.
364
+ - Grid report (`--grid`): T/S/density pcolormesh, N², velocity sections, T-S diagram, power spectra.
365
+ - Array report (`--array`): position map, summary table with clickable links to mooring reports.
366
+
367
+ ### CLI
368
+
369
+ - `oceanarray process` — run stage 1, 2, and/or 3 for a mooring or a single instrument (`--serial`).
370
+ - `oceanarray run` — complete pipeline in one command (process + stack + grid + report).
371
+ - `oceanarray validate` — check mooring YAML for missing fields and unknown instrument types.
372
+ - `oceanarray list` — print accepted `instrument:` names and `file_type:` values.
373
+ - `oceanarray logsheet` — generate PDF logsheets from YAML instrument inventory.
374
+
375
+ ### Logsheets
376
+
377
+ - `oceanarray logsheet` subcommand generates LaTeX-rendered PDF deployment logsheets from a cruise configuration YAML.
378
+
379
+ ### Notable design choices
380
+
381
+ - Data provenance: all processing parameters (QC thresholds, declination value, transformation matrix) stored as NetCDF attributes so any file can be reprocessed exactly from itself.
382
+ - Discrete colorbars throughout (≤ 20 levels, `BoundaryNorm`).
383
+ - CF-convention variable names and standard names throughout; OceanSITES QC flag values.
384
+ - `seasenselib` is used for raw file reading but is a separate install (`pip install seasenselib --no-deps` — see installation docs).
@@ -39,7 +39,7 @@ Three separate things.
39
39
 
40
40
  **Citation authorship** is the author list in `CITATION.cff`, which propagates into the Zenodo DOI for every release and therefore into other people's bibliographies. It reflects *substantial* contribution to the software — its design, a significant body of its implementation, its test suite, or its documentation architecture — and is decided by the maintainer at release time. Funding or supervision alone does not qualify. There is no line count that guarantees it or excludes it. If you believe your contribution crosses that line and it has not been reflected, please say so in an issue — being asked is better than being resented.
41
41
 
42
- Where a contribution is adapted from someone else's work rather than written from scratch, we credit it **in the docstring of the code itself**, so the attribution travels with the code rather than living in a file nobody reads (see the existing examples in `utilities.py` and `plotters/current.py`).
42
+ Where a contribution is adapted from someone else's work rather than written from scratch, we credit it **in the docstring of the code itself**, so the attribution travels with the code rather than living in a file nobody reads (see the existing examples in `pipeline/gridders/rapid_interp.py` and `plotters/current.py`).
43
43
 
44
44
  ---
45
45
 
@@ -81,17 +81,17 @@ For all other bugs:
81
81
 
82
82
  ### Scope
83
83
 
84
- oceanarray **processes moored-array observations**: raw instrument files from a mooring (MicroCATs, RBRs, Nortek and RDI current meters and ADCPs, SBE 16/56, Seapoint, …) → CF-NetCDF at each stage — stage 1 (raw → NetCDF), stage 2 (deployment window, clock), stage 3 (QC, velocity rotation, calibration-dip offsets applied) — then a stack on a common time axis and a grid on pressure levels, each step documented in an HTML report. The OceanSITES export of the stacked and gridded products is the next in-scope step.
84
+ oceanarray **processes moored-array observations**: raw instrument files from a mooring (MicroCATs, RBRs, Nortek and RDI current meters and ADCPs, SBE 16/56, Seapoint, …) → CF-NetCDF at each stage — stage 1 (raw → NetCDF), stage 2 (deployment window, clock), stage 3 (QC, velocity rotation; calibration-dip offsets once the apply step lands — the interface is in place) — then a stack on a common time axis and a grid on pressure levels, each step documented in an HTML report, and an OceanSITES 1.4 export of the stage-3 files and the grid. Exporting the stack is the next in-scope step.
85
85
 
86
86
  **Fixed — not open to variation:** the output contract. Variable names, CF standard names and the canonical unit spellings come from one registry (`config/parameters.py`) and are the same in every file the package writes; QC flags follow the QARTOD/OceanSITES vocabulary; every processing parameter is recorded in the output's attributes so a file can be reprocessed from itself. Contributions that change these change every user's files, and are discussed first, as an issue.
87
87
 
88
88
  **Open — alternative methods welcome, as selectable options with the default unchanged:**
89
89
 
90
- - **Gridding.** The grid step is where the method choices are made — today linear interpolation in pressure onto a fixed `dp` grid, with σ₀ targets for isopycnal products. Alternatives: a **PCHIP spline**; the **RAPID climatological-gradient interpolation** (`tools/rapid_interp.py`, written but **not yet integrated** into `grid.py`); and bounds handling above the shallowest instrument — **extrapolate to the surface**, clip, or mask. All welcome as named methods the user picks in the config, each recording its name and parameters in the output.
90
+ - **Gridding.** The grid step is where the method choices are made — today linear interpolation in pressure onto a fixed `dp` grid, with σ₀ targets for isopycnal products. Alternatives: a **PCHIP spline**; the **RAPID climatological-gradient interpolation** (`pipeline/gridders/rapid_interp.py`, written but **not yet integrated** into `grid.py`); and bounds handling above the shallowest instrument — **extrapolate to the surface**, clip, or mask. All welcome as named methods the user picks in the config, each recording its name and parameters in the output.
91
91
  - **Corrections to individual instruments.** How calibration-dip offsets and other per-instrument corrections (drift, pressure-sensor offset) are applied in stage 3 — constant, linear in time, pre/post weighted — is a method choice; the *derivation* of caldip offsets stays in `caldip`, oceanarray applies its output.
92
92
  - **QC tests.** New QARTOD-style tests or thresholds, as long as the flags land in the existing `_qc` companions with their thresholds recorded.
93
93
  - **Diagnostic figures and report panels.** New figures are welcome, and the report is meant to let a user choose their own selection of panels per page (a config-driven profile); contributions that make that selection easier are in scope.
94
- - **Readers.** Instrument readers live in `seasenselib`; oceanarray's stage 1 dispatches on the file type (`config/parameters.INSTRUMENT_FILE_TYPES`) and keeps only a small set of its own legacy readers (`tools/readers.py`: RODB and the old Nortek CSV). A reader for an instrument `seasenselib` does not cover is welcome — but write it in `seasenselib` first and add the file type here; a reader that only oceanarray would ever use can live in `tools/readers.py`. (Where exactly that line is drawn is not written down yet — ask.)
94
+ - **Readers.** Instrument readers live in `seasenselib`; oceanarray's stage 1 dispatches on the file type (`config/parameters.INSTRUMENT_FILE_TYPES`) and keeps only a small set of its own readers and helpers (`readers/`: its own netCDF, OceanSITES, RODB, and the Nortek and Sea-Bird header parsers). A reader for an instrument `seasenselib` does not cover is welcome — but write it in `seasenselib` first and add the file type here; a reader that only oceanarray would ever use can live in `readers/`. (Where exactly that line is drawn is not written down yet — ask.)
95
95
 
96
96
  **Out of scope, because a sibling owns it:** shipboard CTD processing (`ctdcast`); deriving calibration-dip offsets (`caldip`); glider data (`glidertest`, `seagliderOG1`); transport and AMOC estimates from the gridded products (`AMOCatlas`); general-purpose plotting. Also out: features that need cruise-specific raw data in the repository, heavy new dependencies, or that break the CF-NetCDF contract. If you are unsure whether an idea fits, open an issue describing it rather than deciding alone.
97
97
 
@@ -103,11 +103,11 @@ oceanarray **processes moored-array observations**: raw instrument files from a
103
103
 
104
104
  | Layer | Modules | Role |
105
105
  |-------|---------|------|
106
- | Tier 1 | `tools/`, `writers/`, `utilities.py`, `inspect.py` | Low-level I/O and pure functions — raw-file readers, the single netCDF writer, dataset inspection |
107
- | Tier 2 | `processors/stage1.py` … `processors/grid.py` | Processing orchestrators — read, transform, write CF-NetCDF |
108
- | Tier 3 | `cli.py` | Entry point — argument parsing, subcommand dispatch |
106
+ | Tier 1 | `readers/`, `writers/`, `instruments.py`, `location.py`, `inspect.py` | Low-level I/O and pure functions — file readers, the single netCDF writer, description parsing, dataset inspection |
107
+ | Tier 2 | `pipeline/stage1.py` … `pipeline/grid.py` | Processing orchestrators — read, transform, write CF-NetCDF |
108
+ | Tier 3 | `cli/` | Entry point — argument parsing, subcommand dispatch |
109
109
  | — | `plotters/`, `reports/` | Visualisation and HTML report generation |
110
- | — | `analysis/` | Science utilities (filtering, isopycnals, QC) |
110
+ | — | `analysis/` | Science analysis (isopycnals, spectra) |
111
111
  | — | `config/` | Parameters, variable registry, YAML validation |
112
112
 
113
113
  Processing flows from raw files → Stage 1 (CF-NetCDF) → Stage 2 (trimming + clock) → Stage 3 (QC + ENU) → stack → grid.
@@ -150,7 +150,26 @@ Co-authored-by: Name <email@example.com>
150
150
  - **Type annotations**: all public function arguments and return values.
151
151
  - **Lint**: `ruff check .` must be clean. No bare `except:`. No suppressed warnings without a comment explaining why.
152
152
  - **Units**: every registered variable carries the registry's canonical spelling (`config/parameters.VARIABLES[var]["units"]`), and that spelling is identical in every file the package writes — except N², kept as `s-2` or `rad2 s-2` as it arrives (`config/unit_tables.UNIT_SPELLINGS_KEPT`). The pipeline rewrites known spellings through the shared units tables (`config/unit_tables.TABLES`) and refuses unknown ones. A new spelling is added **with evidence** — a reader that emits it — never from memory: to `config/unit_tables.UNIT_ALIAS_EXTRAS` if only oceanarray's readers emit it, or upstream in ctdcast's vendored `units_tables.py` if it belongs to the family. A mass↔volume conversion is never a scalar alias. Use `gsw` for all seawater property calculations.
153
- - **Plot style**: discrete colorbars (`BoundaryNorm`, ≤ 20 levels). Report figures are styled at one choke point — `reports/_encode.render_b64` applies the vendored `report.mplstyle` and `reports/_slots.render` draws each figure at its slot width — so a report plotter does not call `plt.style.use` itself.
153
+ - **Plot style**: discrete colorbars (`BoundaryNorm`, ≤ 20 levels). Report figures are styled at one choke point — `reports/_vendored/figure_png.render_b64` applies the vendored `report.mplstyle` and `reports/_slots.render` draws each figure at its slot width — so a report plotter does not call `plt.style.use` itself.
154
+ - **Private helpers**: a leading underscore keeps a helper out of the public API; it may be shared inside its own subpackage (`reports/`, `cli/`, `pipeline/`). Its docstring is **one line** plus a typed signature; a reason the code cannot show (a units or flag-table detail, a precedence order, an edge case) goes in a `#` comment at the line it explains. The name says what comes back, with one verb per job:
155
+
156
+ | verb | returns |
157
+ |---|---|
158
+ | `_read_<what>(path)` | an object read from a file |
159
+ | `_parse_<what>(text)` | a typed value from a string in hand, no I/O |
160
+ | `_resolve_<what>(…)` | the one value that applies, from several sources by precedence |
161
+ | `_format_<what>(value)` | a display string |
162
+ | `_build_<what>(…)` | rows, a dict or a dataset |
163
+ | `_render_<what>(…)` | an HTML fragment |
164
+ | `_draw_<what>(…)` | a matplotlib Figure (public: `draw_<what>`; no `_fig` suffix) |
165
+ | `_make_<what>_b64(…)` | a base64 PNG for a report slot (`_b64s` for a list) |
166
+ | `_has_<what>` / `_is_<what>` | a bool |
167
+ | `_apply_<what>(ds, …)` | the dataset after one processing step |
168
+ | `_add_<what>(…)` | the target with variables, attributes or flags added |
169
+ | `_rename_<what>(ds)` / `_to_canonical_<form>(ds)` | renamed variables / a foreign layout in ours |
170
+ | noun (`_time_axis_bounds`) | a computed result |
171
+
172
+ Words with a British/American variant are avoided where a neutral word exists (`_rename_`, not `_normalize_`); `color` is the exception. `tests/unit/test_private_names.py` fails on a retired prefix.
154
173
  - **Data provenance**: store all processing parameters (thresholds, coefficients) in NC output attributes so any file can be reprocessed exactly from itself.
155
174
  - **No silent defaults**: never substitute a default, guess, or approximation when the correct value cannot be determined. Raise, or warn loudly and record what was assumed in the output's metadata. A plausible wrong number is worse than an error, because nothing downstream can detect it.
156
175