Skip to content

Commit 6ef4dfb

Browse files
authored
Merge branch 'main' into strongly_typed
2 parents dfd7111 + d75fecc commit 6ef4dfb

File tree

11 files changed

+133
-50
lines changed

11 files changed

+133
-50
lines changed

.github/workflows/full_test.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ jobs:
1515
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
18-
os: [ubuntu-latest, windows-latest]
1918
python-version: ["3.10", "3.13"]
2019

2120
steps:

.github/workflows/python-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
strategy:
1616
matrix:
1717
os: [ubuntu-latest, windows-latest]
18-
python-version: [3.9, "3.13"]
18+
python-version: ["3.10", "3.13"]
1919

2020
steps:
2121
- uses: actions/checkout@v4

mikeio/_track.py

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from .dataset import Dataset
1010
from .dfs import Dfs0
11-
from .eum import ItemInfo
11+
from .eum import ItemInfo, EUMUnit, EUMType
1212
from .spatial import GeometryFM2D
1313

1414

@@ -33,33 +33,17 @@ def _extract_track(
3333

3434
n_items = len(item_numbers)
3535

36-
if isinstance(track, str):
37-
filename = track
38-
path = Path(filename)
39-
if not path.exists():
40-
raise ValueError(f"{filename} does not exist")
41-
42-
ext = path.suffix.lower()
43-
if ext == ".dfs0":
44-
df = Dfs0(filename).to_dataframe()
45-
elif ext == ".csv":
46-
df = pd.read_csv(filename, index_col=0, parse_dates=True)
47-
df.index = pd.DatetimeIndex(df.index)
48-
else:
49-
raise ValueError(f"{ext} files not supported (dfs0, csv)")
50-
51-
times = df.index
52-
coords = df.iloc[:, 0:2].to_numpy(copy=True)
53-
54-
elif isinstance(track, Dataset):
55-
times = track.time
56-
coords = np.zeros(shape=(len(times), 2))
57-
coords[:, 0] = track[0].to_numpy().copy()
58-
coords[:, 1] = track[1].to_numpy().copy()
59-
else:
60-
assert isinstance(track, pd.DataFrame)
61-
times = track.index
62-
coords = track.iloc[:, 0:2].to_numpy(copy=True)
36+
match track:
37+
case str():
38+
times, coords = _get_track_data_from_file(track)
39+
case Dataset():
40+
times, coords = _get_track_data_from_dataset(track)
41+
case pd.DataFrame():
42+
times, coords = _get_track_data_from_dataframe(track)
43+
case _:
44+
raise ValueError(
45+
"track must be a file name, a Dataset or a pandas DataFrame"
46+
)
6347

6448
assert isinstance(
6549
times, pd.DatetimeIndex
@@ -157,11 +141,72 @@ def is_EOF(step: int) -> bool:
157141
data_list[item + 2][t] = dati[item]
158142

159143
if geometry.is_geo:
160-
items_out = [ItemInfo("Longitude"), ItemInfo("Latitude")]
144+
items_out = [
145+
ItemInfo("Longitude", EUMType.Latitude_longitude, EUMUnit.degree),
146+
ItemInfo("Latitude", EUMType.Latitude_longitude, EUMUnit.degree),
147+
]
161148
else:
162-
items_out = [ItemInfo("x"), ItemInfo("y")]
149+
items_out = [
150+
ItemInfo("x", EUMType.Geographical_coordinate, EUMUnit.meter),
151+
ItemInfo("y", EUMType.Geographical_coordinate, EUMUnit.meter),
152+
]
163153

164154
for item_info in items:
165155
items_out.append(item_info)
166156

167157
return Dataset(data_list, times, items_out)
158+
159+
160+
def _get_track_data_from_dataset(track: Dataset) -> tuple[pd.DatetimeIndex, np.ndarray]:
161+
times = track.time
162+
coords = np.zeros(shape=(len(times), 2))
163+
coords[:, 0] = track[0].to_numpy().copy()
164+
coords[:, 1] = track[1].to_numpy().copy()
165+
return times, coords
166+
167+
168+
def _get_track_data_from_dataframe(
169+
track: pd.DataFrame,
170+
) -> tuple[pd.DatetimeIndex, np.ndarray]:
171+
times = track.index
172+
coords = track.iloc[:, 0:2].to_numpy(copy=True)
173+
return times, coords
174+
175+
176+
def _get_track_data_from_file(track: str) -> tuple[pd.DatetimeIndex, np.ndarray]:
177+
filename = track
178+
path = Path(filename)
179+
if not path.exists():
180+
raise FileNotFoundError(f"{filename} does not exist")
181+
182+
ext = path.suffix.lower()
183+
match ext:
184+
case ".dfs0":
185+
df = Dfs0(filename).to_dataframe()
186+
case ".csv":
187+
df = pd.read_csv(filename, index_col=0, parse_dates=True)
188+
df.index = pd.DatetimeIndex(df.index)
189+
case _:
190+
raise ValueError(f"{ext} files not supported (dfs0, csv)")
191+
192+
times = df.index
193+
coords = df.iloc[:, 0:2].to_numpy(copy=True)
194+
195+
return times, coords
196+
197+
198+
def _find_end_index(t_rel: pd.Index, end_time: pd.Timestamp) -> int:
199+
# largest idx for which (times - self.end_time)<=0
200+
tmp = np.where(t_rel <= 0)[0]
201+
if len(tmp) == 0:
202+
raise ValueError("No time overlap!")
203+
i_end = tmp[-1]
204+
return i_end
205+
206+
207+
def _find_start_index(t_rel: pd.Index, start_time: pd.Timestamp) -> int:
208+
tmp = np.where(t_rel >= 0)[0]
209+
if len(tmp) == 0:
210+
raise ValueError("No time overlap!")
211+
i_start = tmp[0] # smallest idx for which t_rel>=0
212+
return i_start

mikeio/dataset/_dataarray.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,7 @@ def extract_track(
10641064
geometry=self.geometry,
10651065
n_elements=self.shape[1], # TODO is there a better way to find out this?
10661066
track=track,
1067-
items=[self.item],
1067+
items=deepcopy([self.item]),
10681068
time_steps=list(range(self.n_timesteps)),
10691069
item_numbers=[0],
10701070
method=method,

mikeio/dataset/_dataset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ def extract_track(
10511051
geometry=self.geometry,
10521052
n_elements=self.shape[1], # TODO is there a better way to find out this?
10531053
track=track,
1054-
items=self.items,
1054+
items=deepcopy(self.items),
10551055
time_steps=time_steps,
10561056
item_numbers=item_numbers,
10571057
method=method,

mikeio/dfsu/_dfsu.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
from copy import deepcopy
23
from dataclasses import dataclass
34
from datetime import datetime
45
from pathlib import Path
@@ -686,18 +687,15 @@ def extract_track(
686687
687688
Examples
688689
--------
689-
>>> dfsu = mikeio.open("tests/testdata/NorthSea_HD_and_windspeed.dfsu")
690-
>>> ds = dfsu.extract_track("tests/testdata/altimetry_NorthSea_20171027.csv")
691-
>>> ds
692-
<mikeio.Dataset>
693-
dims: (time:1115)
694-
time: 2017-10-26 04:37:37 - 2017-10-30 20:54:47 (1115 non-equidistant records)
695-
geometry: GeometryUndefined()
696-
items:
697-
0: Longitude <Undefined> (undefined)
698-
1: Latitude <Undefined> (undefined)
699-
2: Surface elevation <Surface Elevation> (meter)
700-
3: Wind speed <Wind speed> (meter per sec)
690+
```{python}
691+
import mikeio
692+
693+
ds = (
694+
mikeio.open("../data/NorthSea_HD_and_windspeed.dfsu")
695+
.extract_track("../data/altimetry_NorthSea_20171027.csv")
696+
)
697+
ds
698+
```
701699
702700
"""
703701
dfs = DfsuFile.Open(self._filename)
@@ -714,7 +712,7 @@ def extract_track(
714712
geometry=self.geometry,
715713
n_elements=self.geometry.n_elements,
716714
track=track,
717-
items=items,
715+
items=deepcopy(items),
718716
time_steps=time_steps,
719717
item_numbers=item_numbers,
720718
method=method,

mikeio/spatial/_grid_geometry.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,10 @@ def y(self) -> np.ndarray:
700700

701701
y1 = y0 + self.dy * (self.ny - 1)
702702
y_local = np.linspace(y0, y1, self.ny)
703-
return y_local if self._is_rotated else y_local + self._origin[1]
703+
if self._is_rotated or self.is_spectral:
704+
return y_local
705+
else:
706+
return y_local + self._origin[1]
704707

705708
@property
706709
def nx(self) -> int:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ exclude = [
2020

2121
[project]
2222
name = "mikeio"
23-
version = "2.2.dev3"
23+
version = "2.2.0"
2424
dependencies = [
2525
"mikecore>=0.2.1",
2626
"numpy>=1.22.0",

tests/test_dfs2.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ def dfs2_random_2items():
2525
return mikeio.open(filepath)
2626

2727

28+
@pytest.fixture
29+
def dfs2_pt_spectrum_geographical():
30+
filepath = Path("tests/testdata/spectra/pt_spectra_geographical.dfs2")
31+
return mikeio.open(filepath, type="spectral")
32+
33+
2834
@pytest.fixture
2935
def dfs2_pt_spectrum():
3036
filepath = Path("tests/testdata/spectra/pt_spectra.dfs2")
@@ -312,6 +318,31 @@ def test_properties_pt_spectrum(dfs2_pt_spectrum):
312318
assert g.orientation == 0
313319

314320

321+
def test_properties_pt_spectrum_geographical(dfs2_pt_spectrum_geographical):
322+
dfs = dfs2_pt_spectrum_geographical
323+
assert dfs.x0 == pytest.approx(0.055)
324+
assert dfs.y0 == 0
325+
assert dfs.dx == pytest.approx(1.1)
326+
assert dfs.dy == 22.5
327+
assert dfs.nx == 25
328+
assert dfs.ny == 16
329+
assert dfs.longitude == pytest.approx(0, abs=1e-6)
330+
assert dfs.latitude == 0
331+
assert dfs.orientation == 0
332+
assert dfs.n_items == 1
333+
assert dfs.n_timesteps == 31
334+
335+
g = dfs.geometry
336+
assert g.is_spectral
337+
assert g.x[0] == pytest.approx(0.055)
338+
# assert g.x[-1] > 25 # if considered linear
339+
assert g.x[-1] < 0.6 # logarithmic
340+
assert g.y[0] == 0
341+
assert g.dx == pytest.approx(1.1)
342+
assert g.dy == 22.5
343+
assert g.orientation == 0
344+
345+
315346
def test_properties_pt_spectrum_linearf(dfs2_pt_spectrum_linearf):
316347
dfs = dfs2_pt_spectrum_linearf
317348
# This file doesn't have a valid projection string

tests/test_dfsu.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,9 +788,16 @@ def test_extract_track_from_dataset():
788788
parse_dates=True,
789789
)
790790
df.index = pd.DatetimeIndex(df.index)
791+
assert ds[0].name == "Sign. Wave Height"
791792
track = ds.extract_track(df)
792793

793-
assert track[2].values[23] == approx(3.6284972794399653)
794+
# This should not change the original dataset
795+
track.rename({"Sign. Wave Height": "Hm0"}, inplace=True)
796+
assert track["Hm0"].name == "Hm0"
797+
798+
assert ds[0].name == "Sign. Wave Height"
799+
800+
assert track["Hm0"].values[23] == approx(3.6284972794399653)
794801
assert sum(np.isnan(track[2].to_numpy())) == 26
795802
assert np.all(track[1].to_numpy() == df.latitude.values)
796803

0 commit comments

Comments
 (0)