arlmet 0.1.0a1__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.
- arlmet-0.1.0a1/LICENSE +21 -0
- arlmet-0.1.0a1/PKG-INFO +193 -0
- arlmet-0.1.0a1/README.md +161 -0
- arlmet-0.1.0a1/pyproject.toml +125 -0
- arlmet-0.1.0a1/setup.cfg +4 -0
- arlmet-0.1.0a1/src/arlmet/__init__.py +63 -0
- arlmet-0.1.0a1/src/arlmet/_time.py +21 -0
- arlmet-0.1.0a1/src/arlmet/collection.py +171 -0
- arlmet-0.1.0a1/src/arlmet/file.py +552 -0
- arlmet-0.1.0a1/src/arlmet/grid.py +723 -0
- arlmet-0.1.0a1/src/arlmet/header.py +224 -0
- arlmet-0.1.0a1/src/arlmet/index.py +434 -0
- arlmet-0.1.0a1/src/arlmet/packing.py +243 -0
- arlmet-0.1.0a1/src/arlmet/py.typed +2 -0
- arlmet-0.1.0a1/src/arlmet/record.py +598 -0
- arlmet-0.1.0a1/src/arlmet/recordset.py +349 -0
- arlmet-0.1.0a1/src/arlmet/sampling.py +666 -0
- arlmet-0.1.0a1/src/arlmet/sources.py +564 -0
- arlmet-0.1.0a1/src/arlmet/subset.py +289 -0
- arlmet-0.1.0a1/src/arlmet/vertical.py +138 -0
- arlmet-0.1.0a1/src/arlmet/xarray/__init__.py +15 -0
- arlmet-0.1.0a1/src/arlmet/xarray/_accessor.py +52 -0
- arlmet-0.1.0a1/src/arlmet/xarray/_backend.py +74 -0
- arlmet-0.1.0a1/src/arlmet/xarray/_coords.py +192 -0
- arlmet-0.1.0a1/src/arlmet/xarray/_vertical.py +257 -0
- arlmet-0.1.0a1/src/arlmet/xarray/dataset.py +358 -0
- arlmet-0.1.0a1/src/arlmet.egg-info/PKG-INFO +193 -0
- arlmet-0.1.0a1/src/arlmet.egg-info/SOURCES.txt +40 -0
- arlmet-0.1.0a1/src/arlmet.egg-info/dependency_links.txt +1 -0
- arlmet-0.1.0a1/src/arlmet.egg-info/requires.txt +8 -0
- arlmet-0.1.0a1/src/arlmet.egg-info/top_level.txt +1 -0
- arlmet-0.1.0a1/tests/test_grid.py +329 -0
- arlmet-0.1.0a1/tests/test_low_level.py +960 -0
- arlmet-0.1.0a1/tests/test_metadata.py +119 -0
- arlmet-0.1.0a1/tests/test_packing.py +174 -0
- arlmet-0.1.0a1/tests/test_pkg.py +21 -0
- arlmet-0.1.0a1/tests/test_sampling.py +803 -0
- arlmet-0.1.0a1/tests/test_sources.py +821 -0
- arlmet-0.1.0a1/tests/test_subset.py +213 -0
- arlmet-0.1.0a1/tests/test_subset_slow.py +175 -0
- arlmet-0.1.0a1/tests/test_vertical.py +319 -0
- arlmet-0.1.0a1/tests/test_writer.py +349 -0
arlmet-0.1.0a1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 James Mineau
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
arlmet-0.1.0a1/PKG-INFO
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arlmet
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Read and write ARL meteorological files.
|
|
5
|
+
Author-email: James Mineau <jameskmineau@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jmineau/arl-met
|
|
8
|
+
Project-URL: Documentation, https://jmineau.github.io/arl-met/
|
|
9
|
+
Project-URL: Repository, https://github.com/jmineau/arl-met
|
|
10
|
+
Project-URL: Issues, https://github.com/jmineau/arl-met/issues
|
|
11
|
+
Keywords: arl,hysplit,meteorology,atmospheric-science,xarray
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: numpy>=1.24
|
|
25
|
+
Requires-Dist: pandas>=2.0
|
|
26
|
+
Requires-Dist: pyproj>=3.5
|
|
27
|
+
Requires-Dist: xarray>=2023.6
|
|
28
|
+
Provides-Extra: sources
|
|
29
|
+
Requires-Dist: fsspec>=2024.2; extra == "sources"
|
|
30
|
+
Requires-Dist: s3fs>=2024.2; extra == "sources"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# arl-met
|
|
34
|
+
|
|
35
|
+
[](https://github.com/jmineau/arl-met/actions/workflows/tests.yml)
|
|
36
|
+
[](https://github.com/jmineau/arl-met/actions/workflows/docs.yml)
|
|
37
|
+
[](https://github.com/jmineau/arl-met/actions/workflows/quality.yml)
|
|
38
|
+
[](https://codecov.io/gh/jmineau/arl-met)
|
|
39
|
+
[](https://badge.fury.io/py/arlmet)
|
|
40
|
+
[](https://pypi.org/project/arlmet/)
|
|
41
|
+
[](https://opensource.org/licenses/MIT)
|
|
42
|
+
[](https://github.com/astral-sh/ruff)
|
|
43
|
+
[](https://github.com/microsoft/pyright)
|
|
44
|
+
|
|
45
|
+
Read, write, subset, and sample NOAA ARL meteorological files.
|
|
46
|
+
|
|
47
|
+
`arl-met` provides a Python-first interface to the ARL packed meteorology
|
|
48
|
+
format used by HYSPLIT and related workflows. It supports:
|
|
49
|
+
|
|
50
|
+
- low-level record-preserving reads and writes through `File`, `RecordSet`, and `DataRecord`
|
|
51
|
+
- xarray Dataset reads and common-case writes through `open_dataset()` and `write_dataset()`
|
|
52
|
+
- crop-before-unpack subset extraction with `extract_subset()`
|
|
53
|
+
- NOAA source fetching helpers for common ARL archives
|
|
54
|
+
- vertical helper functions such as `pressure()`, `z_agl()`, and `z_msl()`
|
|
55
|
+
|
|
56
|
+
## Alpha status
|
|
57
|
+
|
|
58
|
+
This is an alpha release. The core read/write/subset APIs are usable, but the
|
|
59
|
+
package is still tightening its high-level contracts and release surface.
|
|
60
|
+
|
|
61
|
+
Current strengths:
|
|
62
|
+
|
|
63
|
+
- low-level ARL fidelity, including preservation of trailing `DIF*` records
|
|
64
|
+
- xarray-native analysis workflow for common ARL files
|
|
65
|
+
- direct subset extraction and point sampling
|
|
66
|
+
- tested support for Python 3.10 through 3.12
|
|
67
|
+
|
|
68
|
+
Current limitations:
|
|
69
|
+
|
|
70
|
+
- `write_dataset()` is intentionally conservative and targets the flat common-case Dataset contract
|
|
71
|
+
- complex multi-record DIFF chains are not tested
|
|
72
|
+
- WRF vertical flag 5 is not implemented
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
Install the core package:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install arlmet
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Install the optional source-fetching dependencies:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install "arlmet[sources]"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For development:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
git clone https://github.com/jmineau/arl-met.git
|
|
92
|
+
cd arl-met
|
|
93
|
+
uv sync --dev
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Quick examples
|
|
97
|
+
|
|
98
|
+
Open an ARL file as a Dataset:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import arlmet
|
|
102
|
+
|
|
103
|
+
ds = arlmet.open_dataset("met.arl")
|
|
104
|
+
print(ds)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Modify a Dataset and write it back:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
import arlmet
|
|
111
|
+
|
|
112
|
+
ds = arlmet.open_dataset("met.arl")
|
|
113
|
+
ds["TEMP"] = ds["TEMP"] - 273.15
|
|
114
|
+
ds["WWND"].attrs["diff"] = "DIFW"
|
|
115
|
+
arlmet.write_dataset(ds, "edited.arl")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Extract a subset without unpacking the full file first:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
import arlmet
|
|
122
|
+
|
|
123
|
+
arlmet.extract_subset(
|
|
124
|
+
"met.arl",
|
|
125
|
+
"subset.arl",
|
|
126
|
+
bbox=(-114.0, 39.0, -110.0, 42.0),
|
|
127
|
+
levels=[0, 1, 2],
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Use the low-level writer for irregular layouts:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
import numpy as np
|
|
135
|
+
import pandas as pd
|
|
136
|
+
import arlmet
|
|
137
|
+
|
|
138
|
+
grid = arlmet.Grid(
|
|
139
|
+
projection=arlmet.Projection(
|
|
140
|
+
pole_lat=90.0,
|
|
141
|
+
pole_lon=0.0,
|
|
142
|
+
tangent_lat=1.0,
|
|
143
|
+
tangent_lon=1.0,
|
|
144
|
+
grid_size=0.0,
|
|
145
|
+
orientation=0.0,
|
|
146
|
+
cone_angle=0.0,
|
|
147
|
+
sync_x=1.0,
|
|
148
|
+
sync_y=1.0,
|
|
149
|
+
sync_lat=-10.0,
|
|
150
|
+
sync_lon=20.0,
|
|
151
|
+
),
|
|
152
|
+
nx=20,
|
|
153
|
+
ny=20,
|
|
154
|
+
)
|
|
155
|
+
vertical_axis = arlmet.VerticalAxis(flag=2, levels=[0.0, 1000.0])
|
|
156
|
+
time = pd.Timestamp("2024-07-18 00:00")
|
|
157
|
+
|
|
158
|
+
prss = np.ones((grid.ny, grid.nx), dtype=np.float32)
|
|
159
|
+
wwnd = np.ones((grid.ny, grid.nx), dtype=np.float32)
|
|
160
|
+
|
|
161
|
+
with arlmet.File("custom.arl", mode="w", source="TEST", grid=grid, vertical_axis=vertical_axis) as arl:
|
|
162
|
+
rs = arl.create_recordset(time, forecast=0)
|
|
163
|
+
rs.create_datarecord("PRSS", level=0, forecast=0, data=prss)
|
|
164
|
+
rs.create_datarecord("WWND", level=1, forecast=0, data=wwnd, diff="DIFW")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Resources
|
|
168
|
+
|
|
169
|
+
Documentation is available at https://jmineau.github.io/arl-met/
|
|
170
|
+
|
|
171
|
+
Useful ARL/HYSPLIT references:
|
|
172
|
+
|
|
173
|
+
- [HYSPLIT User Guide](https://www.arl.noaa.gov/documents/reports/hysplit_user_guide.pdf) for the broader model and file-format context.
|
|
174
|
+
- [HYSPLIT meteorology page](https://www.ready.noaa.gov/hysplitusersguide/S141.htm) for the ARL meteorology format overview.
|
|
175
|
+
- [READY archive](https://www.ready.noaa.gov/archives.php) for the available meteorology archives.
|
|
176
|
+
- [GDAS1 packing notes](https://www.ready.noaa.gov/gdas1.php) for a concrete example of ARL packing behavior.
|
|
177
|
+
|
|
178
|
+
Related project:
|
|
179
|
+
|
|
180
|
+
- [ARLreader](https://github.com/martin-rdz/ARLreader), which focuses on GDAS1 files, while `arl-met` targets a broader ARL/xarray workflow.
|
|
181
|
+
|
|
182
|
+
## Release notes
|
|
183
|
+
|
|
184
|
+
See [CHANGELOG.md](CHANGELOG.md) for release history.
|
|
185
|
+
|
|
186
|
+
## Contributing
|
|
187
|
+
|
|
188
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for development
|
|
189
|
+
setup and contribution guidelines.
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE).
|
arlmet-0.1.0a1/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# arl-met
|
|
2
|
+
|
|
3
|
+
[](https://github.com/jmineau/arl-met/actions/workflows/tests.yml)
|
|
4
|
+
[](https://github.com/jmineau/arl-met/actions/workflows/docs.yml)
|
|
5
|
+
[](https://github.com/jmineau/arl-met/actions/workflows/quality.yml)
|
|
6
|
+
[](https://codecov.io/gh/jmineau/arl-met)
|
|
7
|
+
[](https://badge.fury.io/py/arlmet)
|
|
8
|
+
[](https://pypi.org/project/arlmet/)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://github.com/astral-sh/ruff)
|
|
11
|
+
[](https://github.com/microsoft/pyright)
|
|
12
|
+
|
|
13
|
+
Read, write, subset, and sample NOAA ARL meteorological files.
|
|
14
|
+
|
|
15
|
+
`arl-met` provides a Python-first interface to the ARL packed meteorology
|
|
16
|
+
format used by HYSPLIT and related workflows. It supports:
|
|
17
|
+
|
|
18
|
+
- low-level record-preserving reads and writes through `File`, `RecordSet`, and `DataRecord`
|
|
19
|
+
- xarray Dataset reads and common-case writes through `open_dataset()` and `write_dataset()`
|
|
20
|
+
- crop-before-unpack subset extraction with `extract_subset()`
|
|
21
|
+
- NOAA source fetching helpers for common ARL archives
|
|
22
|
+
- vertical helper functions such as `pressure()`, `z_agl()`, and `z_msl()`
|
|
23
|
+
|
|
24
|
+
## Alpha status
|
|
25
|
+
|
|
26
|
+
This is an alpha release. The core read/write/subset APIs are usable, but the
|
|
27
|
+
package is still tightening its high-level contracts and release surface.
|
|
28
|
+
|
|
29
|
+
Current strengths:
|
|
30
|
+
|
|
31
|
+
- low-level ARL fidelity, including preservation of trailing `DIF*` records
|
|
32
|
+
- xarray-native analysis workflow for common ARL files
|
|
33
|
+
- direct subset extraction and point sampling
|
|
34
|
+
- tested support for Python 3.10 through 3.12
|
|
35
|
+
|
|
36
|
+
Current limitations:
|
|
37
|
+
|
|
38
|
+
- `write_dataset()` is intentionally conservative and targets the flat common-case Dataset contract
|
|
39
|
+
- complex multi-record DIFF chains are not tested
|
|
40
|
+
- WRF vertical flag 5 is not implemented
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
Install the core package:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install arlmet
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Install the optional source-fetching dependencies:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install "arlmet[sources]"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For development:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/jmineau/arl-met.git
|
|
60
|
+
cd arl-met
|
|
61
|
+
uv sync --dev
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick examples
|
|
65
|
+
|
|
66
|
+
Open an ARL file as a Dataset:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import arlmet
|
|
70
|
+
|
|
71
|
+
ds = arlmet.open_dataset("met.arl")
|
|
72
|
+
print(ds)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Modify a Dataset and write it back:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import arlmet
|
|
79
|
+
|
|
80
|
+
ds = arlmet.open_dataset("met.arl")
|
|
81
|
+
ds["TEMP"] = ds["TEMP"] - 273.15
|
|
82
|
+
ds["WWND"].attrs["diff"] = "DIFW"
|
|
83
|
+
arlmet.write_dataset(ds, "edited.arl")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Extract a subset without unpacking the full file first:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import arlmet
|
|
90
|
+
|
|
91
|
+
arlmet.extract_subset(
|
|
92
|
+
"met.arl",
|
|
93
|
+
"subset.arl",
|
|
94
|
+
bbox=(-114.0, 39.0, -110.0, 42.0),
|
|
95
|
+
levels=[0, 1, 2],
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use the low-level writer for irregular layouts:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
import numpy as np
|
|
103
|
+
import pandas as pd
|
|
104
|
+
import arlmet
|
|
105
|
+
|
|
106
|
+
grid = arlmet.Grid(
|
|
107
|
+
projection=arlmet.Projection(
|
|
108
|
+
pole_lat=90.0,
|
|
109
|
+
pole_lon=0.0,
|
|
110
|
+
tangent_lat=1.0,
|
|
111
|
+
tangent_lon=1.0,
|
|
112
|
+
grid_size=0.0,
|
|
113
|
+
orientation=0.0,
|
|
114
|
+
cone_angle=0.0,
|
|
115
|
+
sync_x=1.0,
|
|
116
|
+
sync_y=1.0,
|
|
117
|
+
sync_lat=-10.0,
|
|
118
|
+
sync_lon=20.0,
|
|
119
|
+
),
|
|
120
|
+
nx=20,
|
|
121
|
+
ny=20,
|
|
122
|
+
)
|
|
123
|
+
vertical_axis = arlmet.VerticalAxis(flag=2, levels=[0.0, 1000.0])
|
|
124
|
+
time = pd.Timestamp("2024-07-18 00:00")
|
|
125
|
+
|
|
126
|
+
prss = np.ones((grid.ny, grid.nx), dtype=np.float32)
|
|
127
|
+
wwnd = np.ones((grid.ny, grid.nx), dtype=np.float32)
|
|
128
|
+
|
|
129
|
+
with arlmet.File("custom.arl", mode="w", source="TEST", grid=grid, vertical_axis=vertical_axis) as arl:
|
|
130
|
+
rs = arl.create_recordset(time, forecast=0)
|
|
131
|
+
rs.create_datarecord("PRSS", level=0, forecast=0, data=prss)
|
|
132
|
+
rs.create_datarecord("WWND", level=1, forecast=0, data=wwnd, diff="DIFW")
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Resources
|
|
136
|
+
|
|
137
|
+
Documentation is available at https://jmineau.github.io/arl-met/
|
|
138
|
+
|
|
139
|
+
Useful ARL/HYSPLIT references:
|
|
140
|
+
|
|
141
|
+
- [HYSPLIT User Guide](https://www.arl.noaa.gov/documents/reports/hysplit_user_guide.pdf) for the broader model and file-format context.
|
|
142
|
+
- [HYSPLIT meteorology page](https://www.ready.noaa.gov/hysplitusersguide/S141.htm) for the ARL meteorology format overview.
|
|
143
|
+
- [READY archive](https://www.ready.noaa.gov/archives.php) for the available meteorology archives.
|
|
144
|
+
- [GDAS1 packing notes](https://www.ready.noaa.gov/gdas1.php) for a concrete example of ARL packing behavior.
|
|
145
|
+
|
|
146
|
+
Related project:
|
|
147
|
+
|
|
148
|
+
- [ARLreader](https://github.com/martin-rdz/ARLreader), which focuses on GDAS1 files, while `arl-met` targets a broader ARL/xarray workflow.
|
|
149
|
+
|
|
150
|
+
## Release notes
|
|
151
|
+
|
|
152
|
+
See [CHANGELOG.md](CHANGELOG.md) for release history.
|
|
153
|
+
|
|
154
|
+
## Contributing
|
|
155
|
+
|
|
156
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for development
|
|
157
|
+
setup and contribution guidelines.
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "arlmet"
|
|
7
|
+
version = "0.1.0a1"
|
|
8
|
+
description = "Read and write ARL meteorological files."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "James Mineau", email = "jameskmineau@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["arl", "hysplit", "meteorology", "atmospheric-science", "xarray"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Atmospheric Science",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"numpy>=1.24",
|
|
29
|
+
"pandas>=2.0",
|
|
30
|
+
"pyproj>=3.5",
|
|
31
|
+
"xarray>=2023.6",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
sources = ["fsspec>=2024.2", "s3fs>=2024.2"]
|
|
36
|
+
|
|
37
|
+
[dependency-groups]
|
|
38
|
+
dev = [
|
|
39
|
+
"arlmet[sources]",
|
|
40
|
+
"build>=1.2",
|
|
41
|
+
"docstr-coverage>=2.0.0",
|
|
42
|
+
"pydata-sphinx-theme>=0.14.0",
|
|
43
|
+
"pre-commit>=3.0.0",
|
|
44
|
+
"pyright>=1.1.0",
|
|
45
|
+
"pytest>=7.0.0",
|
|
46
|
+
"pytest-cov>=4.0.0",
|
|
47
|
+
"ruff>=0.1.0",
|
|
48
|
+
"rust-just>=1.42.4",
|
|
49
|
+
"sphinx>=7.0.0",
|
|
50
|
+
"sphinx-autodoc-typehints>=1.24.0",
|
|
51
|
+
"twine>=5.0",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
[project.urls]
|
|
55
|
+
Homepage = "https://github.com/jmineau/arl-met"
|
|
56
|
+
Documentation = "https://jmineau.github.io/arl-met/"
|
|
57
|
+
Repository = "https://github.com/jmineau/arl-met"
|
|
58
|
+
Issues = "https://github.com/jmineau/arl-met/issues"
|
|
59
|
+
|
|
60
|
+
[tool.coverage.run]
|
|
61
|
+
source = ["src/arlmet"]
|
|
62
|
+
omit = ["*/tests/*", "*/test_*.py"]
|
|
63
|
+
|
|
64
|
+
[tool.uv]
|
|
65
|
+
required-version = ">=0.10.4"
|
|
66
|
+
|
|
67
|
+
[tool.coverage.report]
|
|
68
|
+
# Regexes for lines to exclude from consideration
|
|
69
|
+
exclude_also = [
|
|
70
|
+
# Don't complain about missing debug-only code:
|
|
71
|
+
"def __repr__",
|
|
72
|
+
"if self\\.debug",
|
|
73
|
+
|
|
74
|
+
# Don't complain if tests don't hit defensive assertion code:
|
|
75
|
+
"raise AssertionError",
|
|
76
|
+
"raise NotImplementedError",
|
|
77
|
+
|
|
78
|
+
# Don't complain if non-runnable code isn't run:
|
|
79
|
+
"if 0:",
|
|
80
|
+
"if __name__ == .__main__.:",
|
|
81
|
+
|
|
82
|
+
# Don't complain about abstract methods, they aren't run:
|
|
83
|
+
"@(abc\\.)?abstractmethod",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
[tool.pyright]
|
|
87
|
+
include = ["src"]
|
|
88
|
+
exclude = ["**/__pycache__", "**/.venv"]
|
|
89
|
+
|
|
90
|
+
[tool.pytest.ini_options]
|
|
91
|
+
testpaths = ["tests"]
|
|
92
|
+
markers = [
|
|
93
|
+
"network: requires live network access to external services such as NOAA S3",
|
|
94
|
+
"slow: expensive runtime, bandwidth, or disk usage; excluded from default test runs",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
[tool.ruff]
|
|
98
|
+
target-version = "py310"
|
|
99
|
+
|
|
100
|
+
[tool.ruff.format]
|
|
101
|
+
docstring-code-format = true
|
|
102
|
+
|
|
103
|
+
[tool.ruff.lint]
|
|
104
|
+
select = [
|
|
105
|
+
"E", # pycodestyle
|
|
106
|
+
"F", # Pyflakes
|
|
107
|
+
"UP", # pyupgrade
|
|
108
|
+
"B", # flake8-bugbear
|
|
109
|
+
"SIM", # flake8-simplify
|
|
110
|
+
"I", # isort
|
|
111
|
+
"D213", # multi-line summary should start at the second line
|
|
112
|
+
]
|
|
113
|
+
ignore = [
|
|
114
|
+
"D212", # incompatible with D213; keep summaries on the second line
|
|
115
|
+
"E501", # line too long, handled by formatter
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
[tool.ruff.lint.isort]
|
|
119
|
+
known-first-party = ["arlmet"]
|
|
120
|
+
|
|
121
|
+
[tool.setuptools.packages.find]
|
|
122
|
+
where = ["src"]
|
|
123
|
+
|
|
124
|
+
[tool.setuptools.package-data]
|
|
125
|
+
"arlmet" = ["py.typed", "resources/*"]
|
arlmet-0.1.0a1/setup.cfg
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
arlmet: Python package for reading and analyzing NOAA ARL meteorological files.
|
|
3
|
+
|
|
4
|
+
This package provides tools to read, parse, and work with ARL (Air Resources Laboratory)
|
|
5
|
+
packed meteorological data files used by HYSPLIT and other atmospheric transport models.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from importlib.metadata import PackageNotFoundError, version as package_version
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _detect_version() -> str:
|
|
14
|
+
try:
|
|
15
|
+
return package_version("arlmet")
|
|
16
|
+
except PackageNotFoundError:
|
|
17
|
+
pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
18
|
+
match = re.search(
|
|
19
|
+
r'^version\s*=\s*"([^"]+)"',
|
|
20
|
+
pyproject.read_text(encoding="utf-8"),
|
|
21
|
+
flags=re.MULTILINE,
|
|
22
|
+
)
|
|
23
|
+
if match is None:
|
|
24
|
+
return "0+unknown"
|
|
25
|
+
return match.group(1)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__version__ = _detect_version()
|
|
29
|
+
__author__ = "James Mineau"
|
|
30
|
+
__email__ = "jmineau@gmail.com"
|
|
31
|
+
|
|
32
|
+
from .file import File
|
|
33
|
+
from .grid import Grid, Projection
|
|
34
|
+
from .header import Header
|
|
35
|
+
from .index import IndexRecord
|
|
36
|
+
from .packing import calculate_checksum, pack, unpack
|
|
37
|
+
from .record import DataRecord
|
|
38
|
+
from .recordset import RecordSet
|
|
39
|
+
from .sampling import sample_points
|
|
40
|
+
from .subset import extract_subset
|
|
41
|
+
from .vertical import VerticalAxis
|
|
42
|
+
from .xarray import open_dataset, pressure, write_dataset, z_agl, z_msl
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
"File",
|
|
46
|
+
"RecordSet",
|
|
47
|
+
"DataRecord",
|
|
48
|
+
"open_dataset",
|
|
49
|
+
"write_dataset",
|
|
50
|
+
"pressure",
|
|
51
|
+
"z_agl",
|
|
52
|
+
"z_msl",
|
|
53
|
+
"Projection",
|
|
54
|
+
"Grid",
|
|
55
|
+
"VerticalAxis",
|
|
56
|
+
"Header",
|
|
57
|
+
"IndexRecord",
|
|
58
|
+
"calculate_checksum",
|
|
59
|
+
"pack",
|
|
60
|
+
"unpack",
|
|
61
|
+
"extract_subset",
|
|
62
|
+
"sample_points",
|
|
63
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Internal timestamp normalization helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, cast
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def ensure_timestamp(value: Any, *, floor: str | None = None) -> pd.Timestamp:
|
|
11
|
+
"""Return a concrete pandas.Timestamp, rejecting NaT values."""
|
|
12
|
+
ts = value if isinstance(value, pd.Timestamp) else pd.Timestamp(value)
|
|
13
|
+
if pd.isna(ts):
|
|
14
|
+
raise ValueError(f"Invalid timestamp value: {value!r}")
|
|
15
|
+
if floor is not None:
|
|
16
|
+
ts = ts.floor(floor)
|
|
17
|
+
if pd.isna(ts):
|
|
18
|
+
raise ValueError(
|
|
19
|
+
f"Invalid timestamp value after floor({floor!r}): {value!r}"
|
|
20
|
+
)
|
|
21
|
+
return cast(pd.Timestamp, ts)
|