canvodpy 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- canvodpy/.DS_Store +0 -0
- canvodpy/__init__.py +276 -0
- canvodpy/api.py +707 -0
- canvodpy/cli/__init__.py +0 -0
- canvodpy/cli/run.py +366 -0
- canvodpy/diagnostics/.DS_Store +0 -0
- canvodpy/diagnostics/__init__.py +9 -0
- canvodpy/diagnostics/sbf_timing_diagnostics_new_api.py +239 -0
- canvodpy/diagnostics/timing_diagnostics_new_api.py +242 -0
- canvodpy/diagnostics/timing_diagnostics_script.py +246 -0
- canvodpy/factories.py +376 -0
- canvodpy/fluent.py +477 -0
- canvodpy/functional.py +585 -0
- canvodpy/globals.py +50 -0
- canvodpy/logging/.DS_Store +0 -0
- canvodpy/logging/__init__.py +50 -0
- canvodpy/logging/context.py +37 -0
- canvodpy/logging/logging_config.py +437 -0
- canvodpy/orchestrator/.DS_Store +0 -0
- canvodpy/orchestrator/__init__.py +46 -0
- canvodpy/orchestrator/interpolator.py +369 -0
- canvodpy/orchestrator/matcher.py +158 -0
- canvodpy/orchestrator/pipeline.py +1344 -0
- canvodpy/orchestrator/processor.py +3404 -0
- canvodpy/orchestrator/resources.py +302 -0
- canvodpy/utils/.DS_Store +0 -0
- canvodpy/utils/__init__.py +37 -0
- canvodpy/utils/perf.py +41 -0
- canvodpy/utils/telemetry.py +367 -0
- canvodpy/vod_computer.py +349 -0
- canvodpy/workflow.py +471 -0
- canvodpy/workflows/__init__.py +27 -0
- canvodpy/workflows/tasks.py +1394 -0
- canvodpy-0.2.0.dist-info/METADATA +151 -0
- canvodpy-0.2.0.dist-info/RECORD +36 -0
- canvodpy-0.2.0.dist-info/WHEEL +4 -0
canvodpy/.DS_Store
ADDED
|
Binary file
|
canvodpy/__init__.py
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"""canvodpy: GNSS Vegetation Optical Depth Analysis.
|
|
2
|
+
|
|
3
|
+
A modern Python package for processing GNSS data and calculating
|
|
4
|
+
vegetation optical depth (VOD) using the tau-omega model.
|
|
5
|
+
|
|
6
|
+
Quick Start
|
|
7
|
+
-----------
|
|
8
|
+
Three levels of API to match your needs:
|
|
9
|
+
|
|
10
|
+
**Level 1: Simple (one-liners)**
|
|
11
|
+
>>> from canvodpy import process_date, calculate_vod
|
|
12
|
+
>>> data = process_date("Rosalia", "2025001")
|
|
13
|
+
>>> vod = calculate_vod("Rosalia", "canopy_01", "reference_01", "2025001")
|
|
14
|
+
|
|
15
|
+
**Level 2: Object-oriented (more control)**
|
|
16
|
+
>>> from canvodpy import Site, Pipeline
|
|
17
|
+
>>> site = Site("Rosalia")
|
|
18
|
+
>>> pipeline = site.pipeline()
|
|
19
|
+
>>> data = pipeline.process_date("2025001")
|
|
20
|
+
>>> vod = pipeline.calculate_vod("canopy_01", "reference_01", "2025001")
|
|
21
|
+
|
|
22
|
+
**Level 3: Low-level (full control)**
|
|
23
|
+
>>> from canvod.store import GnssResearchSite
|
|
24
|
+
>>> from canvod.vod import VODCalculator
|
|
25
|
+
>>> # Direct access to all internals
|
|
26
|
+
|
|
27
|
+
Community Extensions
|
|
28
|
+
--------------------
|
|
29
|
+
Extend canvodpy with custom components using factories:
|
|
30
|
+
|
|
31
|
+
>>> from canvodpy import VODFactory
|
|
32
|
+
>>> from my_package import CustomCalculator
|
|
33
|
+
>>> VODFactory.register("custom", CustomCalculator)
|
|
34
|
+
>>> calc = VODFactory.create("custom", **params)
|
|
35
|
+
|
|
36
|
+
Package Structure
|
|
37
|
+
-----------------
|
|
38
|
+
- canvod.readers - RINEX file parsing
|
|
39
|
+
- canvod.auxiliary - Auxiliary data (ephemeris, clocks)
|
|
40
|
+
- canvod.grids - Hemisphere grid structures
|
|
41
|
+
- canvod.vod - VOD calculation algorithms
|
|
42
|
+
- canvod.viz - 2D/3D visualization
|
|
43
|
+
- canvod.store - Icechunk data storage
|
|
44
|
+
|
|
45
|
+
Configuration
|
|
46
|
+
-------------
|
|
47
|
+
Site configurations are stored in ``config/sites.yaml``.
|
|
48
|
+
Default variables and settings are in `globals.py`.
|
|
49
|
+
|
|
50
|
+
Examples
|
|
51
|
+
--------
|
|
52
|
+
Process one day of data:
|
|
53
|
+
>>> from canvodpy import process_date
|
|
54
|
+
>>> data = process_date("Rosalia", "2025001")
|
|
55
|
+
|
|
56
|
+
Process a week:
|
|
57
|
+
>>> from canvodpy import Pipeline
|
|
58
|
+
>>> pipeline = Pipeline("Rosalia")
|
|
59
|
+
>>> for date, datasets in pipeline.process_range("2025001", "2025007"):
|
|
60
|
+
... print(f"Processed {date}")
|
|
61
|
+
|
|
62
|
+
Calculate and visualize VOD:
|
|
63
|
+
>>> from canvodpy import calculate_vod
|
|
64
|
+
>>> from canvod.viz import HemisphereVisualizer
|
|
65
|
+
>>> vod = calculate_vod("Rosalia", "canopy_01", "reference_01", "2025001")
|
|
66
|
+
>>> viz = HemisphereVisualizer()
|
|
67
|
+
>>> fig = viz.plot_2d(vod)
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
from canvodpy.api import (
|
|
72
|
+
Pipeline,
|
|
73
|
+
Site,
|
|
74
|
+
calculate_vod,
|
|
75
|
+
preview_processing,
|
|
76
|
+
process_date,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Factories (for community extensions)
|
|
80
|
+
from canvodpy.factories import (
|
|
81
|
+
AugmentationFactory,
|
|
82
|
+
GridFactory,
|
|
83
|
+
ReaderFactory,
|
|
84
|
+
VODFactory,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Fluent workflow API (deferred execution)
|
|
88
|
+
from canvodpy.fluent import FluentWorkflow
|
|
89
|
+
|
|
90
|
+
# Functional API (Airflow-compatible)
|
|
91
|
+
from canvodpy.functional import (
|
|
92
|
+
assign_grid_cells,
|
|
93
|
+
assign_grid_cells_to_file,
|
|
94
|
+
augment_with_ephemeris,
|
|
95
|
+
calculate_vod_to_file,
|
|
96
|
+
create_grid,
|
|
97
|
+
create_grid_to_file,
|
|
98
|
+
read_rinex,
|
|
99
|
+
read_rinex_to_file,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Logging (for all users)
|
|
103
|
+
from canvodpy.logging import get_logger, setup_logging
|
|
104
|
+
|
|
105
|
+
# VOD computation helper
|
|
106
|
+
from canvodpy.vod_computer import VodComputer
|
|
107
|
+
|
|
108
|
+
# New workflow API
|
|
109
|
+
from canvodpy.workflow import VODWorkflow
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def workflow(site: str, **kwargs) -> FluentWorkflow:
|
|
113
|
+
"""Create a fluent workflow with deferred execution.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
site : str
|
|
118
|
+
Site name (e.g. ``"Rosalia"``).
|
|
119
|
+
**kwargs
|
|
120
|
+
Forwarded to :class:`FluentWorkflow`.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
FluentWorkflow
|
|
125
|
+
|
|
126
|
+
Examples
|
|
127
|
+
--------
|
|
128
|
+
>>> import canvodpy
|
|
129
|
+
>>> result = (canvodpy.workflow("Rosalia")
|
|
130
|
+
... .read("2025001")
|
|
131
|
+
... .preprocess()
|
|
132
|
+
... .grid()
|
|
133
|
+
... .vod("canopy_01", "reference_01")
|
|
134
|
+
... .result())
|
|
135
|
+
"""
|
|
136
|
+
return FluentWorkflow(site, **kwargs)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# ============================================================================
|
|
140
|
+
# Level 3 API: Re-export subpackages for advanced users
|
|
141
|
+
# ============================================================================
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# Lazy import subpackages on access to avoid circular dependencies
|
|
145
|
+
def __getattr__(name: str):
|
|
146
|
+
"""Lazy import subpackages when accessed."""
|
|
147
|
+
_subpackages = {
|
|
148
|
+
"auxiliary": "canvod.auxiliary",
|
|
149
|
+
"grids": "canvod.grids",
|
|
150
|
+
"readers": "canvod.readers",
|
|
151
|
+
"store": "canvod.store",
|
|
152
|
+
"viz": "canvod.viz",
|
|
153
|
+
"vod": "canvod.vod",
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if name in _subpackages:
|
|
157
|
+
import importlib
|
|
158
|
+
import sys
|
|
159
|
+
|
|
160
|
+
module = importlib.import_module(_subpackages[name])
|
|
161
|
+
# Cache the imported module (can't use globals() as it's shadowed by canvodpy.globals)
|
|
162
|
+
setattr(sys.modules[__name__], name, module)
|
|
163
|
+
return module
|
|
164
|
+
|
|
165
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ============================================================================
|
|
169
|
+
# Version
|
|
170
|
+
# ============================================================================
|
|
171
|
+
|
|
172
|
+
__version__ = "0.1.0"
|
|
173
|
+
|
|
174
|
+
# ============================================================================
|
|
175
|
+
# Public API
|
|
176
|
+
# ============================================================================
|
|
177
|
+
|
|
178
|
+
__all__ = [ # noqa: RUF022
|
|
179
|
+
# Version
|
|
180
|
+
"__version__",
|
|
181
|
+
# High-level API (most users)
|
|
182
|
+
"Site",
|
|
183
|
+
"Pipeline",
|
|
184
|
+
"process_date",
|
|
185
|
+
"calculate_vod",
|
|
186
|
+
"preview_processing",
|
|
187
|
+
# New workflow API
|
|
188
|
+
"VODWorkflow",
|
|
189
|
+
# Fluent workflow API
|
|
190
|
+
"FluentWorkflow",
|
|
191
|
+
"workflow",
|
|
192
|
+
# Functional API (notebooks & Airflow)
|
|
193
|
+
"read_rinex",
|
|
194
|
+
"read_rinex_to_file",
|
|
195
|
+
"create_grid",
|
|
196
|
+
"create_grid_to_file",
|
|
197
|
+
"assign_grid_cells",
|
|
198
|
+
"assign_grid_cells_to_file",
|
|
199
|
+
"calculate_vod_to_file",
|
|
200
|
+
# Logging
|
|
201
|
+
"setup_logging",
|
|
202
|
+
"get_logger",
|
|
203
|
+
# Factories (community extensions)
|
|
204
|
+
"ReaderFactory",
|
|
205
|
+
"GridFactory",
|
|
206
|
+
"VODFactory",
|
|
207
|
+
"AugmentationFactory",
|
|
208
|
+
# Subpackages (advanced users)
|
|
209
|
+
"readers",
|
|
210
|
+
"aux",
|
|
211
|
+
"grids",
|
|
212
|
+
"vod",
|
|
213
|
+
"viz",
|
|
214
|
+
"store",
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# ============================================================================
|
|
219
|
+
# Auto-register built-in components
|
|
220
|
+
# ============================================================================
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _register_builtin_components() -> None:
|
|
224
|
+
"""
|
|
225
|
+
Register built-in component implementations.
|
|
226
|
+
|
|
227
|
+
Called automatically on package import. Registers:
|
|
228
|
+
- Rnxv3Obs reader (rinex3)
|
|
229
|
+
- EqualAreaGridBuilder (equal_area)
|
|
230
|
+
- TauOmegaZerothOrder calculator (tau_omega)
|
|
231
|
+
|
|
232
|
+
Notes
|
|
233
|
+
-----
|
|
234
|
+
Uses lazy imports to avoid loading heavy dependencies unless needed.
|
|
235
|
+
"""
|
|
236
|
+
log = get_logger(__name__)
|
|
237
|
+
|
|
238
|
+
# Set ABC classes for validation
|
|
239
|
+
ReaderFactory._set_abc_class()
|
|
240
|
+
GridFactory._set_abc_class()
|
|
241
|
+
VODFactory._set_abc_class()
|
|
242
|
+
AugmentationFactory._set_abc_class()
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
from canvod.readers import Rnxv3Obs
|
|
246
|
+
|
|
247
|
+
ReaderFactory.register("rinex3", Rnxv3Obs)
|
|
248
|
+
except ImportError:
|
|
249
|
+
log.debug("canvod-readers not available, skipping reader registration")
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
from canvod.readers.sbf import SbfReader
|
|
253
|
+
|
|
254
|
+
ReaderFactory.register("sbf", SbfReader)
|
|
255
|
+
except ImportError:
|
|
256
|
+
log.debug("SbfReader not available, skipping sbf reader registration")
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
from canvod.grids import EqualAreaBuilder
|
|
260
|
+
|
|
261
|
+
GridFactory.register("equal_area", EqualAreaBuilder)
|
|
262
|
+
except ImportError:
|
|
263
|
+
log.debug("canvod-grids not available, skipping grid registration")
|
|
264
|
+
|
|
265
|
+
try:
|
|
266
|
+
from canvod.vod.calculator import TauOmegaZerothOrder
|
|
267
|
+
|
|
268
|
+
VODFactory.register("tau_omega", TauOmegaZerothOrder)
|
|
269
|
+
except ImportError:
|
|
270
|
+
log.debug("canvod-vod not available, skipping VOD registration")
|
|
271
|
+
|
|
272
|
+
log.info("builtin_components_registered")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# Auto-register on import
|
|
276
|
+
_register_builtin_components()
|