doppy 0.5.2__tar.gz → 0.5.4__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.
Potentially problematic release.
This version of doppy might be problematic. Click here for more details.
- {doppy-0.5.2 → doppy-0.5.4}/Cargo.lock +55 -29
- {doppy-0.5.2 → doppy-0.5.4}/Cargo.toml +6 -1
- {doppy-0.5.2 → doppy-0.5.4}/PKG-INFO +2 -1
- {doppy-0.5.2 → doppy-0.5.4}/crates/doppy_rs/Cargo.toml +2 -1
- doppy-0.5.4/crates/doppy_rs/src/raw/wls77.rs +90 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doppy_rs/src/raw.rs +2 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doprs/Cargo.toml +1 -0
- doppy-0.5.4/crates/doprs/src/bin/parse_wls70.rs +8 -0
- doppy-0.5.4/crates/doprs/src/bin/parse_wls77.rs +7 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doprs/src/raw/halo_hpl.rs +30 -4
- doppy-0.5.4/crates/doprs/src/raw/wls77.rs +290 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doprs/src/raw.rs +1 -0
- {doppy-0.5.2 → doppy-0.5.4}/pyproject.toml +1 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/raw/__init__.py +10 -1
- doppy-0.5.4/src/doppy/raw/wls77.py +163 -0
- {doppy-0.5.2 → doppy-0.5.4}/LICENSE +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/README.md +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doppy_rs/src/lib.rs +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doppy_rs/src/raw/halo_hpl.rs +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doppy_rs/src/raw/wls70.rs +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doprs/.gitignore +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doprs/src/lib.rs +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doprs/src/raw/error.rs +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/crates/doprs/src/raw/wls70.rs +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/__init__.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/__main__.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/bench.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/data/__init__.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/data/api.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/data/cache.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/data/exceptions.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/defaults.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/exceptions.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/netcdf.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/options.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/product/__init__.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/product/noise_utils.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/product/stare.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/product/stare_depol.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/product/turbulence.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/product/wind.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/py.typed +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/raw/halo_bg.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/raw/halo_hpl.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/raw/halo_sys_params.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/raw/utils.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/raw/windcube.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/raw/wls70.py +0 -0
- {doppy-0.5.2 → doppy-0.5.4}/src/doppy/utils.py +0 -0
|
@@ -34,9 +34,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
|
|
34
34
|
|
|
35
35
|
[[package]]
|
|
36
36
|
name = "bitflags"
|
|
37
|
-
version = "2.
|
|
37
|
+
version = "2.9.0"
|
|
38
38
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
39
|
-
checksum = "
|
|
39
|
+
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
|
40
40
|
|
|
41
41
|
[[package]]
|
|
42
42
|
name = "bumpalo"
|
|
@@ -46,9 +46,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
|
|
46
46
|
|
|
47
47
|
[[package]]
|
|
48
48
|
name = "cc"
|
|
49
|
-
version = "1.2.
|
|
49
|
+
version = "1.2.16"
|
|
50
50
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
51
|
-
checksum = "
|
|
51
|
+
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
|
52
52
|
dependencies = [
|
|
53
53
|
"shlex",
|
|
54
54
|
]
|
|
@@ -106,27 +106,29 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|
|
106
106
|
|
|
107
107
|
[[package]]
|
|
108
108
|
name = "doppy_rs"
|
|
109
|
-
version = "0.5.
|
|
109
|
+
version = "0.5.4"
|
|
110
110
|
dependencies = [
|
|
111
111
|
"doprs",
|
|
112
|
+
"ndarray 0.16.1",
|
|
112
113
|
"numpy",
|
|
113
114
|
"pyo3",
|
|
114
115
|
]
|
|
115
116
|
|
|
116
117
|
[[package]]
|
|
117
118
|
name = "doprs"
|
|
118
|
-
version = "0.5.
|
|
119
|
+
version = "0.5.4"
|
|
119
120
|
dependencies = [
|
|
120
121
|
"chrono",
|
|
122
|
+
"ndarray 0.16.1",
|
|
121
123
|
"rayon",
|
|
122
124
|
"regex",
|
|
123
125
|
]
|
|
124
126
|
|
|
125
127
|
[[package]]
|
|
126
128
|
name = "either"
|
|
127
|
-
version = "1.
|
|
129
|
+
version = "1.15.0"
|
|
128
130
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
129
|
-
checksum = "
|
|
131
|
+
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
130
132
|
|
|
131
133
|
[[package]]
|
|
132
134
|
name = "heck"
|
|
@@ -159,9 +161,9 @@ dependencies = [
|
|
|
159
161
|
|
|
160
162
|
[[package]]
|
|
161
163
|
name = "indoc"
|
|
162
|
-
version = "2.0.
|
|
164
|
+
version = "2.0.6"
|
|
163
165
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
164
|
-
checksum = "
|
|
166
|
+
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
|
165
167
|
|
|
166
168
|
[[package]]
|
|
167
169
|
name = "js-sys"
|
|
@@ -175,9 +177,9 @@ dependencies = [
|
|
|
175
177
|
|
|
176
178
|
[[package]]
|
|
177
179
|
name = "libc"
|
|
178
|
-
version = "0.2.
|
|
180
|
+
version = "0.2.171"
|
|
179
181
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
180
|
-
checksum = "
|
|
182
|
+
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
|
181
183
|
|
|
182
184
|
[[package]]
|
|
183
185
|
name = "lock_api"
|
|
@@ -233,6 +235,21 @@ dependencies = [
|
|
|
233
235
|
"rawpointer",
|
|
234
236
|
]
|
|
235
237
|
|
|
238
|
+
[[package]]
|
|
239
|
+
name = "ndarray"
|
|
240
|
+
version = "0.16.1"
|
|
241
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
242
|
+
checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
|
|
243
|
+
dependencies = [
|
|
244
|
+
"matrixmultiply",
|
|
245
|
+
"num-complex",
|
|
246
|
+
"num-integer",
|
|
247
|
+
"num-traits",
|
|
248
|
+
"portable-atomic",
|
|
249
|
+
"portable-atomic-util",
|
|
250
|
+
"rawpointer",
|
|
251
|
+
]
|
|
252
|
+
|
|
236
253
|
[[package]]
|
|
237
254
|
name = "num-complex"
|
|
238
255
|
version = "0.4.6"
|
|
@@ -267,7 +284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
267
284
|
checksum = "bef41cbb417ea83b30525259e30ccef6af39b31c240bda578889494c5392d331"
|
|
268
285
|
dependencies = [
|
|
269
286
|
"libc",
|
|
270
|
-
"ndarray",
|
|
287
|
+
"ndarray 0.15.6",
|
|
271
288
|
"num-complex",
|
|
272
289
|
"num-integer",
|
|
273
290
|
"num-traits",
|
|
@@ -277,9 +294,9 @@ dependencies = [
|
|
|
277
294
|
|
|
278
295
|
[[package]]
|
|
279
296
|
name = "once_cell"
|
|
280
|
-
version = "1.
|
|
297
|
+
version = "1.21.0"
|
|
281
298
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
282
|
-
checksum = "
|
|
299
|
+
checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad"
|
|
283
300
|
|
|
284
301
|
[[package]]
|
|
285
302
|
name = "parking_lot"
|
|
@@ -310,11 +327,20 @@ version = "1.11.0"
|
|
|
310
327
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
311
328
|
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
|
312
329
|
|
|
330
|
+
[[package]]
|
|
331
|
+
name = "portable-atomic-util"
|
|
332
|
+
version = "0.2.4"
|
|
333
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
334
|
+
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
|
335
|
+
dependencies = [
|
|
336
|
+
"portable-atomic",
|
|
337
|
+
]
|
|
338
|
+
|
|
313
339
|
[[package]]
|
|
314
340
|
name = "proc-macro2"
|
|
315
|
-
version = "1.0.
|
|
341
|
+
version = "1.0.94"
|
|
316
342
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
317
|
-
checksum = "
|
|
343
|
+
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
|
318
344
|
dependencies = [
|
|
319
345
|
"unicode-ident",
|
|
320
346
|
]
|
|
@@ -384,9 +410,9 @@ dependencies = [
|
|
|
384
410
|
|
|
385
411
|
[[package]]
|
|
386
412
|
name = "quote"
|
|
387
|
-
version = "1.0.
|
|
413
|
+
version = "1.0.40"
|
|
388
414
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
389
|
-
checksum = "
|
|
415
|
+
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
|
390
416
|
dependencies = [
|
|
391
417
|
"proc-macro2",
|
|
392
418
|
]
|
|
@@ -419,9 +445,9 @@ dependencies = [
|
|
|
419
445
|
|
|
420
446
|
[[package]]
|
|
421
447
|
name = "redox_syscall"
|
|
422
|
-
version = "0.5.
|
|
448
|
+
version = "0.5.10"
|
|
423
449
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
424
|
-
checksum = "
|
|
450
|
+
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
|
425
451
|
dependencies = [
|
|
426
452
|
"bitflags",
|
|
427
453
|
]
|
|
@@ -463,9 +489,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|
|
463
489
|
|
|
464
490
|
[[package]]
|
|
465
491
|
name = "rustversion"
|
|
466
|
-
version = "1.0.
|
|
492
|
+
version = "1.0.20"
|
|
467
493
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
468
|
-
checksum = "
|
|
494
|
+
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
|
469
495
|
|
|
470
496
|
[[package]]
|
|
471
497
|
name = "scopeguard"
|
|
@@ -487,9 +513,9 @@ checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
|
|
487
513
|
|
|
488
514
|
[[package]]
|
|
489
515
|
name = "syn"
|
|
490
|
-
version = "2.0.
|
|
516
|
+
version = "2.0.100"
|
|
491
517
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
492
|
-
checksum = "
|
|
518
|
+
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
|
493
519
|
dependencies = [
|
|
494
520
|
"proc-macro2",
|
|
495
521
|
"quote",
|
|
@@ -504,15 +530,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|
|
504
530
|
|
|
505
531
|
[[package]]
|
|
506
532
|
name = "unicode-ident"
|
|
507
|
-
version = "1.0.
|
|
533
|
+
version = "1.0.18"
|
|
508
534
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
509
|
-
checksum = "
|
|
535
|
+
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
|
510
536
|
|
|
511
537
|
[[package]]
|
|
512
538
|
name = "unindent"
|
|
513
|
-
version = "0.2.
|
|
539
|
+
version = "0.2.4"
|
|
514
540
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
515
|
-
checksum = "
|
|
541
|
+
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
|
516
542
|
|
|
517
543
|
[[package]]
|
|
518
544
|
name = "wasm-bindgen"
|
|
@@ -4,6 +4,11 @@ resolver = "2"
|
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
6
|
edition = "2021"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.4"
|
|
8
8
|
authors = ["Niko Leskinen <niko.leskinen@fmi.fi>"]
|
|
9
9
|
license-file = "LICENSE"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
[workspace.dependencies]
|
|
13
|
+
ndarray = "0.16"
|
|
14
|
+
numpy = {version = "0.20", fatures = ["ndarray"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: doppy
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -28,6 +28,7 @@ Requires-Dist: maturin==1.8 ; extra == 'dev'
|
|
|
28
28
|
Requires-Dist: release-version ; extra == 'dev'
|
|
29
29
|
Requires-Dist: pre-commit ; extra == 'dev'
|
|
30
30
|
Requires-Dist: xarray[io] ; extra == 'dev'
|
|
31
|
+
Requires-Dist: seaborn ; extra == 'dev'
|
|
31
32
|
Provides-Extra: dev
|
|
32
33
|
License-File: LICENSE
|
|
33
34
|
License-File: LICENSE
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
use numpy::PyArray1;
|
|
2
|
+
use pyo3::exceptions::PyRuntimeError;
|
|
3
|
+
use pyo3::prelude::*;
|
|
4
|
+
use pyo3::types::PyDict;
|
|
5
|
+
|
|
6
|
+
#[pymodule]
|
|
7
|
+
pub fn wls77(_py: Python, m: &PyModule) -> PyResult<()> {
|
|
8
|
+
m.add_function(wrap_pyfunction!(from_bytes_src, m)?)?;
|
|
9
|
+
Ok(())
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#[pyfunction]
|
|
13
|
+
pub fn from_bytes_srcs<'a>(py: Python<'a>, contents: Vec<&'a [u8]>) -> PyResult<Vec<&'a PyDict>> {
|
|
14
|
+
let raws = doprs::raw::wls77::from_bytes_srcs(contents);
|
|
15
|
+
let mut result = Vec::new();
|
|
16
|
+
for raw in raws {
|
|
17
|
+
result.push(convert_to_python(py, raw)?);
|
|
18
|
+
}
|
|
19
|
+
Ok(result)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#[pyfunction]
|
|
23
|
+
pub fn from_bytes_src<'a>(py: Python<'a>, content: &'a [u8]) -> PyResult<&'a PyDict> {
|
|
24
|
+
let raw = match doprs::raw::wls77::from_bytes_src(content) {
|
|
25
|
+
Ok(raw) => raw,
|
|
26
|
+
Err(e) => {
|
|
27
|
+
return Err(PyRuntimeError::new_err(format!(
|
|
28
|
+
"Failed to read files: {}",
|
|
29
|
+
e
|
|
30
|
+
)))
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
convert_to_python(py, raw)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[pyfunction]
|
|
37
|
+
pub fn from_filename_srcs(py: Python, filenames: Vec<String>) -> PyResult<Vec<&PyDict>> {
|
|
38
|
+
let raws = doprs::raw::wls77::from_filename_srcs(filenames);
|
|
39
|
+
let mut result = Vec::new();
|
|
40
|
+
for raw in raws {
|
|
41
|
+
result.push(convert_to_python(py, raw)?);
|
|
42
|
+
}
|
|
43
|
+
Ok(result)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#[pyfunction]
|
|
47
|
+
pub fn from_filename_src(py: Python, filename: String) -> PyResult<&PyDict> {
|
|
48
|
+
let raw = match doprs::raw::wls77::from_filename_src(filename) {
|
|
49
|
+
Ok(raw) => raw,
|
|
50
|
+
Err(e) => {
|
|
51
|
+
return Err(PyRuntimeError::new_err(format!(
|
|
52
|
+
"Failed to read files: {}",
|
|
53
|
+
e
|
|
54
|
+
)))
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
convert_to_python(py, raw)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fn convert_to_python(py: Python, raw: doprs::raw::wls77::Wls77) -> PyResult<&PyDict> {
|
|
61
|
+
let d = PyDict::new(py);
|
|
62
|
+
|
|
63
|
+
let fields = [
|
|
64
|
+
("time", raw.time.as_slice()),
|
|
65
|
+
("altitude", raw.altitude.as_slice()),
|
|
66
|
+
("position", raw.position.as_slice()),
|
|
67
|
+
("temperature", raw.temperature.as_slice()),
|
|
68
|
+
("wiper_count", raw.wiper_count.as_slice()),
|
|
69
|
+
("cnr", raw.cnr.as_slice()),
|
|
70
|
+
("radial_velocity", raw.radial_velocity.as_slice()),
|
|
71
|
+
(
|
|
72
|
+
"radial_velocity_deviation",
|
|
73
|
+
raw.radial_velocity_deviation.as_slice(),
|
|
74
|
+
),
|
|
75
|
+
("wind_speed", raw.wind_speed.as_slice()),
|
|
76
|
+
("wind_direction", raw.wind_direction.as_slice()),
|
|
77
|
+
("zonal_wind", raw.zonal_wind.as_slice()),
|
|
78
|
+
("meridional_wind", raw.meridional_wind.as_slice()),
|
|
79
|
+
("vertical_wind", raw.vertical_wind.as_slice()),
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
for (key, value) in fields {
|
|
83
|
+
d.set_item(key, PyArray1::from_slice(py, value.unwrap()))?;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
d.set_item("cnr_threshold", raw.cnr_threshold)?;
|
|
87
|
+
d.set_item("system_id", raw.system_id)?;
|
|
88
|
+
|
|
89
|
+
Ok(d)
|
|
90
|
+
}
|
|
@@ -3,10 +3,12 @@ use pyo3::wrap_pymodule;
|
|
|
3
3
|
|
|
4
4
|
pub mod halo_hpl;
|
|
5
5
|
pub mod wls70;
|
|
6
|
+
pub mod wls77;
|
|
6
7
|
|
|
7
8
|
#[pymodule]
|
|
8
9
|
pub fn raw(_py: Python, m: &PyModule) -> PyResult<()> {
|
|
9
10
|
m.add_wrapped(wrap_pymodule!(halo_hpl::halo_hpl))?;
|
|
10
11
|
m.add_wrapped(wrap_pymodule!(wls70::wls70))?;
|
|
12
|
+
m.add_wrapped(wrap_pymodule!(wls77::wls77))?;
|
|
11
13
|
Ok(())
|
|
12
14
|
}
|
|
@@ -29,6 +29,22 @@ pub struct Info {
|
|
|
29
29
|
pub start_time: i64, // Unix-timestamp
|
|
30
30
|
pub system_id: String,
|
|
31
31
|
pub instrument_spectral_width: Option<f64>,
|
|
32
|
+
range_formula: Option<RangeFormula>,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[derive(Debug, Clone)]
|
|
36
|
+
enum RangeFormula {
|
|
37
|
+
Common, //(range gate + 0.5) * Gate length
|
|
38
|
+
Overlapping, //Gate length / 2 + (range gate x 3)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
impl RangeFormula {
|
|
42
|
+
fn compute_distance(&self, gate_index: f64, range_gate_length: f64) -> f64 {
|
|
43
|
+
match self {
|
|
44
|
+
RangeFormula::Common => (gate_index + 0.5) * range_gate_length,
|
|
45
|
+
RangeFormula::Overlapping => range_gate_length / 2.0 + gate_index * 3.0,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
32
48
|
}
|
|
33
49
|
|
|
34
50
|
#[derive(Debug, Default, Clone)]
|
|
@@ -97,7 +113,11 @@ pub fn from_bytes_src(content: &[u8]) -> Result<HaloHpl, RawParseError> {
|
|
|
97
113
|
}
|
|
98
114
|
}
|
|
99
115
|
let info = parse_header(&buf_header)?;
|
|
100
|
-
let
|
|
116
|
+
let range_formula = info
|
|
117
|
+
.range_formula
|
|
118
|
+
.as_ref()
|
|
119
|
+
.ok_or("Cannot find range formula")?;
|
|
120
|
+
let data = parse_data(&mut cur, info.ngates, info.range_gate_length, range_formula)?;
|
|
101
121
|
Ok(HaloHpl { info, data })
|
|
102
122
|
}
|
|
103
123
|
|
|
@@ -105,6 +125,7 @@ fn parse_data(
|
|
|
105
125
|
cur: &mut Cursor<&[u8]>,
|
|
106
126
|
ngates: u64,
|
|
107
127
|
range_gate_length: f64,
|
|
128
|
+
range_formula: &RangeFormula,
|
|
108
129
|
) -> Result<Data, RawParseError> {
|
|
109
130
|
let (n1d, n2d) = infer_data_shape(cur)?;
|
|
110
131
|
if ngates < 1 || n1d < 3 || n2d < 4 {
|
|
@@ -161,7 +182,7 @@ fn parse_data(
|
|
|
161
182
|
time: data_1d[0].clone(),
|
|
162
183
|
radial_distance: gate
|
|
163
184
|
.iter()
|
|
164
|
-
.map(|&x| (x
|
|
185
|
+
.map(|&x| range_formula.compute_distance(x, range_gate_length))
|
|
165
186
|
.collect(),
|
|
166
187
|
azimuth: data_1d[1].clone(),
|
|
167
188
|
elevation: data_1d[2].clone(),
|
|
@@ -249,8 +270,13 @@ fn parse_header(header_bytes: &[u8]) -> Result<Info, RawParseError> {
|
|
|
249
270
|
info.instrument_spectral_width = Some(captures[1].parse()?);
|
|
250
271
|
} else {
|
|
251
272
|
match line.as_str() {
|
|
252
|
-
"Altitude of measurement (center of gate) = (range gate + 0.5) * Gate length"
|
|
253
|
-
"Range of measurement (center of gate) = (range gate + 0.5) * Gate length" =>
|
|
273
|
+
"Altitude of measurement (center of gate) = (range gate + 0.5) * Gate length" |
|
|
274
|
+
"Range of measurement (center of gate) = (range gate + 0.5) * Gate length" => {
|
|
275
|
+
info.range_formula = Some(RangeFormula::Common)
|
|
276
|
+
},
|
|
277
|
+
"Range of measurement (center of gate) = Gate length / 2 + (range gate x 3)" => {
|
|
278
|
+
info.range_formula = Some(RangeFormula::Overlapping)
|
|
279
|
+
},
|
|
254
280
|
"Data line 1: Decimal time (hours) Azimuth (degrees) Elevation (degrees) Pitch (degrees) Roll (degrees)" => (),
|
|
255
281
|
"Data line 1: Decimal time (hours) Azimuth (degrees) Elevation (degrees)" => (),
|
|
256
282
|
"f9.6,1x,f6.2,1x,f6.2" => (),
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
use crate::raw::error::RawParseError;
|
|
2
|
+
use chrono::{DateTime, NaiveDateTime, ParseError, Utc};
|
|
3
|
+
use ndarray::{s, Array, Array1, Array2};
|
|
4
|
+
use rayon::prelude::*;
|
|
5
|
+
use std::fs::File;
|
|
6
|
+
use std::io::{BufRead, Cursor, Read};
|
|
7
|
+
|
|
8
|
+
#[derive(Debug, Default, Clone)]
|
|
9
|
+
pub struct Wls77Old {
|
|
10
|
+
pub info: Info,
|
|
11
|
+
pub data_columns: Vec<String>,
|
|
12
|
+
pub data: Vec<f64>,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#[derive(Debug, Default, Clone)]
|
|
16
|
+
pub struct Wls77 {
|
|
17
|
+
pub time: Array1<f64>,
|
|
18
|
+
pub altitude: Array1<f64>,
|
|
19
|
+
pub position: Array1<f64>,
|
|
20
|
+
pub temperature: Array1<f64>,
|
|
21
|
+
pub wiper_count: Array1<f64>,
|
|
22
|
+
pub cnr: Array2<f64>,
|
|
23
|
+
pub radial_velocity: Array2<f64>,
|
|
24
|
+
pub radial_velocity_deviation: Array2<f64>,
|
|
25
|
+
pub wind_speed: Array2<f64>,
|
|
26
|
+
pub wind_direction: Array2<f64>,
|
|
27
|
+
pub zonal_wind: Array2<f64>,
|
|
28
|
+
pub meridional_wind: Array2<f64>,
|
|
29
|
+
pub vertical_wind: Array2<f64>,
|
|
30
|
+
pub cnr_threshold: f64,
|
|
31
|
+
pub system_id: String,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#[derive(Debug, Default, Clone)]
|
|
35
|
+
pub struct Info {
|
|
36
|
+
pub altitude: Vec<f64>,
|
|
37
|
+
pub system_id: String,
|
|
38
|
+
pub cnr_threshold: f64,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pub fn from_file_src(mut file: &File) -> Result<Wls77, RawParseError> {
|
|
42
|
+
let mut content = vec![];
|
|
43
|
+
file.read_to_end(&mut content)?;
|
|
44
|
+
from_bytes_src(&content)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn from_filename_src(filename: String) -> Result<Wls77, RawParseError> {
|
|
48
|
+
let file = File::open(filename)?;
|
|
49
|
+
from_file_src(&file)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pub fn from_filename_srcs(filenames: Vec<String>) -> Vec<Wls77> {
|
|
53
|
+
let results = filenames
|
|
54
|
+
.par_iter()
|
|
55
|
+
.filter_map(|filename| from_filename_src(filename.to_string()).ok())
|
|
56
|
+
.collect();
|
|
57
|
+
results
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pub fn from_file_srcs(files: Vec<&File>) -> Vec<Wls77> {
|
|
61
|
+
let results = files
|
|
62
|
+
.par_iter()
|
|
63
|
+
.filter_map(|file| from_file_src(file).ok())
|
|
64
|
+
.collect();
|
|
65
|
+
results
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
pub fn from_bytes_srcs(contents: Vec<&[u8]>) -> Vec<Wls77> {
|
|
69
|
+
let results = contents
|
|
70
|
+
.par_iter()
|
|
71
|
+
.filter_map(|content| from_bytes_src(content).ok())
|
|
72
|
+
.collect();
|
|
73
|
+
results
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
enum Phase {
|
|
77
|
+
Info,
|
|
78
|
+
Data,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
pub fn from_bytes_src(content: &[u8]) -> Result<Wls77, RawParseError> {
|
|
82
|
+
let cur = Cursor::new(content);
|
|
83
|
+
let mut info_str = Vec::new();
|
|
84
|
+
let mut header = Vec::new();
|
|
85
|
+
let mut data_str = Vec::new();
|
|
86
|
+
|
|
87
|
+
let mut phase = Phase::Info;
|
|
88
|
+
|
|
89
|
+
for line in cur.split(b'\n') {
|
|
90
|
+
let line = line.unwrap();
|
|
91
|
+
match phase {
|
|
92
|
+
Phase::Info => {
|
|
93
|
+
if line.starts_with(b"Timestamp\tPosition\tTemperature")
|
|
94
|
+
|| line.starts_with(b"Date\tPosition\tTemperature")
|
|
95
|
+
{
|
|
96
|
+
header.extend_from_slice(&line);
|
|
97
|
+
header.push(b'\n');
|
|
98
|
+
phase = Phase::Data;
|
|
99
|
+
} else {
|
|
100
|
+
info_str.extend_from_slice(&line);
|
|
101
|
+
info_str.push(b'\n');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
Phase::Data => {
|
|
105
|
+
data_str.extend_from_slice(&line);
|
|
106
|
+
data_str.push(b'\n');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
let info = parse_info(&info_str)?;
|
|
111
|
+
|
|
112
|
+
match parse_data(&data_str) {
|
|
113
|
+
Ok((data, ncols)) => {
|
|
114
|
+
let header_str: String = header.iter().map(|&c| c as char).collect();
|
|
115
|
+
let cols: Vec<_> = header_str
|
|
116
|
+
.split('\t')
|
|
117
|
+
.map(|s| s.trim().to_string())
|
|
118
|
+
.filter(|s| !s.is_empty())
|
|
119
|
+
.collect();
|
|
120
|
+
if ncols != (cols.len() as i64) {
|
|
121
|
+
return Err(RawParseError {
|
|
122
|
+
message: "Number of columns on header and number of columns in data mismatch"
|
|
123
|
+
.to_string(),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let data: Array1<_> = Array::from_vec(data.clone());
|
|
128
|
+
let n = (data.len() as i64 / ncols)
|
|
129
|
+
.try_into()
|
|
130
|
+
.map_err(|e| RawParseError {
|
|
131
|
+
message: format!("Failed to convert rows count: {}", e),
|
|
132
|
+
})?;
|
|
133
|
+
let m = ncols.try_into().map_err(|e| RawParseError {
|
|
134
|
+
message: format!("Failed to convert columns count: {}", e),
|
|
135
|
+
})?;
|
|
136
|
+
let shape: [usize; 2] = [n, m];
|
|
137
|
+
|
|
138
|
+
let data = data
|
|
139
|
+
.into_shape_with_order(shape)
|
|
140
|
+
.map_err(|e| RawParseError {
|
|
141
|
+
message: format!("Cannot reshape data array: {}", e),
|
|
142
|
+
})?;
|
|
143
|
+
let altitude = Array::from_vec(info.altitude);
|
|
144
|
+
|
|
145
|
+
let time = data.slice(s![.., 0]).to_owned();
|
|
146
|
+
let position = data.slice(s![.., 1]).to_owned();
|
|
147
|
+
let temperature = data.slice(s![.., 2]).to_owned();
|
|
148
|
+
let wiper_count = data.slice(s![.., 2]).to_owned();
|
|
149
|
+
let cnr = data.slice(s![..,4..;8]).to_owned();
|
|
150
|
+
let radial_velocity = data.slice(s![..,5..;8]).to_owned();
|
|
151
|
+
let radial_velocity_deviation = data.slice(s![..,6..;8]).to_owned();
|
|
152
|
+
let wind_speed = data.slice(s![..,7..;8]).to_owned();
|
|
153
|
+
let wind_direction = data.slice(s![..,8..;8]).to_owned();
|
|
154
|
+
let zonal_wind = data.slice(s![..,9..;8]).to_owned();
|
|
155
|
+
let meridional_wind = data.slice(s![..,10..;8]).to_owned();
|
|
156
|
+
let vertical_wind = data.slice(s![..,11..;8]).to_owned();
|
|
157
|
+
|
|
158
|
+
Ok(Wls77 {
|
|
159
|
+
time,
|
|
160
|
+
altitude,
|
|
161
|
+
position,
|
|
162
|
+
temperature,
|
|
163
|
+
wiper_count,
|
|
164
|
+
cnr,
|
|
165
|
+
radial_velocity,
|
|
166
|
+
radial_velocity_deviation,
|
|
167
|
+
wind_speed,
|
|
168
|
+
wind_direction,
|
|
169
|
+
zonal_wind,
|
|
170
|
+
meridional_wind,
|
|
171
|
+
vertical_wind,
|
|
172
|
+
system_id: info.system_id,
|
|
173
|
+
cnr_threshold: info.cnr_threshold,
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
Err(e) => Err(e),
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fn parse_info(info_str: &[u8]) -> Result<Info, RawParseError> {
|
|
181
|
+
let mut info = Info::default();
|
|
182
|
+
for line in info_str.split(|&b| b == b'\n') {
|
|
183
|
+
match line {
|
|
184
|
+
b if b.starts_with(b"Altitudes AGL (m)=") => {
|
|
185
|
+
info.altitude = line
|
|
186
|
+
.split(|&b| b == b'\t')
|
|
187
|
+
.skip(1)
|
|
188
|
+
.map(|part| {
|
|
189
|
+
String::from_utf8(part.to_vec())
|
|
190
|
+
.map_err(|_| RawParseError {
|
|
191
|
+
message: "UTF-8 conversion error".into(),
|
|
192
|
+
})
|
|
193
|
+
.and_then(|s| {
|
|
194
|
+
s.trim().parse::<f64>().map_err(|_| RawParseError {
|
|
195
|
+
message: "Parse float error".into(),
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
.collect::<Result<Vec<f64>, _>>()?;
|
|
200
|
+
}
|
|
201
|
+
b if b.starts_with(b"ID System=") => {
|
|
202
|
+
info.system_id = std::str::from_utf8(&line[10..])
|
|
203
|
+
.map(|s| s.trim())
|
|
204
|
+
.map_err(|_| RawParseError {
|
|
205
|
+
message: "UTF-8 conversion error".into(),
|
|
206
|
+
})?
|
|
207
|
+
.to_string();
|
|
208
|
+
}
|
|
209
|
+
b if b.starts_with(b"CNRThreshold=") => {
|
|
210
|
+
info.cnr_threshold = std::str::from_utf8(&line[13..])
|
|
211
|
+
.map_err(|_| RawParseError {
|
|
212
|
+
message: "UTF-8 conversion error".into(),
|
|
213
|
+
})?
|
|
214
|
+
.trim()
|
|
215
|
+
.parse::<f64>()
|
|
216
|
+
.map_err(|_| RawParseError {
|
|
217
|
+
message: "Parse float error".into(),
|
|
218
|
+
})?;
|
|
219
|
+
}
|
|
220
|
+
_ => (),
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
Ok(info)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
pub fn parse_data(data: &[u8]) -> Result<(Vec<f64>, i64), RawParseError> {
|
|
228
|
+
let mut ncols: i64 = -1;
|
|
229
|
+
let mut data_flat = vec![];
|
|
230
|
+
for line in data.split(|&b| b == b'\n') {
|
|
231
|
+
let parts: Vec<_> = line
|
|
232
|
+
.split(|&b| b == b'\t')
|
|
233
|
+
.filter(|part| !(part.is_empty() || part == b"\r"))
|
|
234
|
+
.collect();
|
|
235
|
+
if parts.is_empty() {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if ncols < 0 {
|
|
239
|
+
ncols = parts.len() as i64;
|
|
240
|
+
}
|
|
241
|
+
if ncols != parts.len() as i64 {
|
|
242
|
+
return Err(RawParseError {
|
|
243
|
+
message: "Unexpected number of columns".to_string(),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
for (i, part) in parts.iter().enumerate() {
|
|
247
|
+
match i {
|
|
248
|
+
0 => {
|
|
249
|
+
let date = String::from_utf8_lossy(part).trim().to_string();
|
|
250
|
+
match datetime_to_timestamp(&date) {
|
|
251
|
+
Ok(d) => {
|
|
252
|
+
data_flat.push(d);
|
|
253
|
+
}
|
|
254
|
+
Err(_) => println!("Error with datetime"),
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
1 => {
|
|
258
|
+
let s = String::from_utf8_lossy(part).trim().to_string();
|
|
259
|
+
if let Ok(val) = s.parse::<f64>() {
|
|
260
|
+
data_flat.push(val);
|
|
261
|
+
} else {
|
|
262
|
+
match s.as_ref() {
|
|
263
|
+
"V" => data_flat.push(-1.0),
|
|
264
|
+
_ => data_flat.push(-2.0),
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
_ => match String::from_utf8_lossy(part).trim().parse::<f64>() {
|
|
270
|
+
Ok(x) => {
|
|
271
|
+
data_flat.push(x);
|
|
272
|
+
}
|
|
273
|
+
Err(_) => println!("Cannot parse float"),
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if ncols < 1 || (data_flat.len() as i64) % ncols != 0 {
|
|
279
|
+
return Err(RawParseError {
|
|
280
|
+
message: "Unexpected number of columns".to_string(),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
Ok((data_flat, ncols))
|
|
284
|
+
}
|
|
285
|
+
fn datetime_to_timestamp(s: &str) -> Result<f64, ParseError> {
|
|
286
|
+
let format = "%Y/%m/%d %H:%M:%S%.f";
|
|
287
|
+
let ndt = NaiveDateTime::parse_from_str(s, format)?;
|
|
288
|
+
let dt = DateTime::<Utc>::from_naive_utc_and_offset(ndt, Utc);
|
|
289
|
+
Ok(dt.timestamp() as f64 + dt.timestamp_subsec_millis() as f64 / 1000.0)
|
|
290
|
+
}
|
|
@@ -3,5 +3,14 @@ from .halo_hpl import HaloHpl
|
|
|
3
3
|
from .halo_sys_params import HaloSysParams
|
|
4
4
|
from .windcube import WindCube, WindCubeFixed
|
|
5
5
|
from .wls70 import Wls70
|
|
6
|
+
from .wls77 import Wls77
|
|
6
7
|
|
|
7
|
-
__all__ = [
|
|
8
|
+
__all__ = [
|
|
9
|
+
"HaloHpl",
|
|
10
|
+
"HaloBg",
|
|
11
|
+
"HaloSysParams",
|
|
12
|
+
"WindCube",
|
|
13
|
+
"WindCubeFixed",
|
|
14
|
+
"Wls70",
|
|
15
|
+
"Wls77",
|
|
16
|
+
]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from io import BufferedIOBase
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Sequence
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import numpy.typing as npt
|
|
11
|
+
from numpy import datetime64
|
|
12
|
+
|
|
13
|
+
import doppy
|
|
14
|
+
from doppy import exceptions
|
|
15
|
+
from doppy.raw.utils import bytes_from_src
|
|
16
|
+
from doppy.utils import merge_all_equal
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class Wls77:
|
|
21
|
+
time: npt.NDArray[datetime64] # dim: (time, )
|
|
22
|
+
altitude: npt.NDArray[np.float64] # dim: (altitude, )
|
|
23
|
+
position: npt.NDArray[np.float64] # dim: (time, )
|
|
24
|
+
temperature: npt.NDArray[np.float64] # dim: (time, )
|
|
25
|
+
wiper_count: npt.NDArray[np.float64] # dim: (time, )
|
|
26
|
+
cnr: npt.NDArray[np.float64] # dim: (time, altitude)
|
|
27
|
+
radial_velocity: npt.NDArray[np.float64] # dim: (time, altitude)
|
|
28
|
+
radial_velocity_deviation: npt.NDArray[np.float64] # dim: (time, altitude)
|
|
29
|
+
wind_speed: npt.NDArray[np.float64] # dim: (time, altitude)
|
|
30
|
+
wind_direction: npt.NDArray[np.float64] # dim: (time, altitude)
|
|
31
|
+
zonal_wind: npt.NDArray[np.float64] # u := zonal wind?, dim: (time, altitude)
|
|
32
|
+
meridional_wind: npt.NDArray[
|
|
33
|
+
np.float64
|
|
34
|
+
] # v := meridional wind?, dim: (time, altitude)
|
|
35
|
+
vertical_wind: npt.NDArray[np.float64] # w := vertical wind?, dim: (time, altitude)
|
|
36
|
+
cnr_threshold: float
|
|
37
|
+
system_id: str
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_srcs(
|
|
41
|
+
cls, data: Sequence[str | bytes | Path | BufferedIOBase]
|
|
42
|
+
) -> list[Wls77]:
|
|
43
|
+
data_bytes = [bytes_from_src(src) for src in data]
|
|
44
|
+
raws = doppy.rs.raw.wls77.from_bytes_srcs(data_bytes)
|
|
45
|
+
try:
|
|
46
|
+
return [_raw_rs_to_wls77(r) for r in raws]
|
|
47
|
+
except RuntimeError as err:
|
|
48
|
+
raise exceptions.RawParsingError(err) from err
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_src(cls, data: str | Path | bytes | BufferedIOBase) -> Wls77:
|
|
52
|
+
data_bytes = bytes_from_src(data)
|
|
53
|
+
try:
|
|
54
|
+
return _raw_rs_to_wls77(doppy.rs.raw.wls77.from_bytes_src(data_bytes))
|
|
55
|
+
except RuntimeError as err:
|
|
56
|
+
raise exceptions.RawParsingError(err) from err
|
|
57
|
+
|
|
58
|
+
def __getitem__(
|
|
59
|
+
self,
|
|
60
|
+
index: int
|
|
61
|
+
| slice
|
|
62
|
+
| list[int]
|
|
63
|
+
| npt.NDArray[np.int64]
|
|
64
|
+
| npt.NDArray[np.bool_]
|
|
65
|
+
| tuple[slice, slice],
|
|
66
|
+
) -> Wls77:
|
|
67
|
+
if isinstance(index, (int, slice, list, np.ndarray)):
|
|
68
|
+
return Wls77(
|
|
69
|
+
time=self.time[index],
|
|
70
|
+
altitude=self.altitude,
|
|
71
|
+
position=self.position[index],
|
|
72
|
+
temperature=self.temperature[index],
|
|
73
|
+
wiper_count=self.wiper_count[index],
|
|
74
|
+
cnr=self.cnr[index],
|
|
75
|
+
radial_velocity=self.radial_velocity[index],
|
|
76
|
+
radial_velocity_deviation=self.radial_velocity_deviation[index],
|
|
77
|
+
wind_speed=self.wind_speed[index],
|
|
78
|
+
wind_direction=self.wind_direction[index],
|
|
79
|
+
zonal_wind=self.zonal_wind[index],
|
|
80
|
+
meridional_wind=self.meridional_wind[index],
|
|
81
|
+
vertical_wind=self.vertical_wind[index],
|
|
82
|
+
system_id=self.system_id,
|
|
83
|
+
cnr_threshold=self.cnr_threshold,
|
|
84
|
+
)
|
|
85
|
+
raise TypeError
|
|
86
|
+
|
|
87
|
+
def sorted_by_time(self) -> Wls77:
|
|
88
|
+
sort_indices = np.argsort(self.time)
|
|
89
|
+
return self[sort_indices]
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def merge(cls, raws: Sequence[Wls77]) -> Wls77:
|
|
93
|
+
return cls(
|
|
94
|
+
time=np.concatenate(tuple(r.time for r in raws)),
|
|
95
|
+
altitude=raws[0].altitude,
|
|
96
|
+
position=np.concatenate(tuple(r.position for r in raws)),
|
|
97
|
+
temperature=np.concatenate(tuple(r.temperature for r in raws)),
|
|
98
|
+
wiper_count=np.concatenate(tuple(r.wiper_count for r in raws)),
|
|
99
|
+
cnr=np.concatenate(tuple(r.cnr for r in raws)),
|
|
100
|
+
radial_velocity=np.concatenate(tuple(r.radial_velocity for r in raws)),
|
|
101
|
+
radial_velocity_deviation=np.concatenate(
|
|
102
|
+
tuple(r.radial_velocity_deviation for r in raws)
|
|
103
|
+
),
|
|
104
|
+
wind_speed=np.concatenate(tuple(r.wind_speed for r in raws)),
|
|
105
|
+
wind_direction=np.concatenate(tuple(r.wind_direction for r in raws)),
|
|
106
|
+
zonal_wind=np.concatenate(tuple(r.zonal_wind for r in raws)),
|
|
107
|
+
meridional_wind=np.concatenate(tuple(r.meridional_wind for r in raws)),
|
|
108
|
+
vertical_wind=np.concatenate(tuple(r.vertical_wind for r in raws)),
|
|
109
|
+
system_id=merge_all_equal("system_id", [r.system_id for r in raws]),
|
|
110
|
+
cnr_threshold=merge_all_equal(
|
|
111
|
+
"cnr_threshold", [r.cnr_threshold for r in raws]
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def non_strictly_increasing_timesteps_removed(self) -> Wls77:
|
|
116
|
+
if len(self.time) == 0:
|
|
117
|
+
return self
|
|
118
|
+
mask = np.ones_like(self.time, dtype=np.bool_)
|
|
119
|
+
latest_time = self.time[0]
|
|
120
|
+
for i, t in enumerate(self.time[1:], start=1):
|
|
121
|
+
if t <= latest_time:
|
|
122
|
+
mask[i] = False
|
|
123
|
+
else:
|
|
124
|
+
latest_time = t
|
|
125
|
+
return self[mask]
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _raw_rs_to_wls77(
|
|
129
|
+
raw: dict[str, Any],
|
|
130
|
+
) -> Wls77:
|
|
131
|
+
time_ts = raw["time"]
|
|
132
|
+
time = np.array(
|
|
133
|
+
[
|
|
134
|
+
datetime64(datetime.fromtimestamp(ts, timezone.utc).replace(tzinfo=None))
|
|
135
|
+
for ts in time_ts
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
n = time.size
|
|
140
|
+
|
|
141
|
+
return Wls77(
|
|
142
|
+
time=time,
|
|
143
|
+
altitude=np.array(raw["altitude"], dtype=np.float64),
|
|
144
|
+
position=np.array(raw["position"], dtype=np.float64),
|
|
145
|
+
temperature=np.array(raw["temperature"], dtype=np.float64),
|
|
146
|
+
wiper_count=np.array(raw["wiper_count"], dtype=np.float64),
|
|
147
|
+
cnr=np.array(raw["cnr"], dtype=np.float64).reshape(n, -1),
|
|
148
|
+
radial_velocity=np.array(raw["radial_velocity"], dtype=np.float64).reshape(
|
|
149
|
+
n, -1
|
|
150
|
+
),
|
|
151
|
+
radial_velocity_deviation=np.array(
|
|
152
|
+
raw["radial_velocity_deviation"], dtype=np.float64
|
|
153
|
+
).reshape(n, -1),
|
|
154
|
+
wind_speed=np.array(raw["wind_speed"], dtype=np.float64).reshape(n, -1),
|
|
155
|
+
wind_direction=np.array(raw["wind_direction"], dtype=np.float64).reshape(n, -1),
|
|
156
|
+
zonal_wind=np.array(raw["zonal_wind"], dtype=np.float64).reshape(n, -1),
|
|
157
|
+
meridional_wind=np.array(raw["meridional_wind"], dtype=np.float64).reshape(
|
|
158
|
+
n, -1
|
|
159
|
+
),
|
|
160
|
+
vertical_wind=np.array(raw["vertical_wind"], dtype=np.float64).reshape(n, -1),
|
|
161
|
+
cnr_threshold=raw["cnr_threshold"],
|
|
162
|
+
system_id=raw["system_id"],
|
|
163
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|