Skip to content

Commit 87de210

Browse files
committed
update _plan logic (+ more changes to expedition model) to handle lifetime in minutes
1 parent ff43127 commit 87de210

File tree

5 files changed

+45
-27
lines changed

5 files changed

+45
-27
lines changed

src/virtualship/cli/_plan.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@ def log_exception_to_file(
138138
{"name": "cycle_days"},
139139
{"name": "drift_days"},
140140
{"name": "stationkeeping_time", "minutes": True},
141-
{"name": "lifetime", "minutes": True},
141+
{"name": "lifetime", "days": True},
142142
],
143143
},
144144
"drifter_config": {
145145
"class": DrifterConfig,
146146
"title": "Drifter",
147147
"attributes": [
148148
{"name": "depth_meter"},
149-
{"name": "lifetime", "minutes": True},
149+
{"name": "lifetime", "days": True},
150150
{"name": "stationkeeping_time", "minutes": True},
151151
],
152152
},
@@ -264,7 +264,10 @@ def compose(self) -> ComposeResult:
264264
with Container(classes="instrument-config"):
265265
for attr_meta in attributes:
266266
attr = attr_meta["name"]
267-
is_minutes = attr_meta.get("minutes", False)
267+
is_minutes, is_days = (
268+
attr_meta.get("minutes", False),
269+
attr_meta.get("days", False),
270+
)
268271
validators = group_validators(config_class, attr)
269272
if config_instance:
270273
raw_value = getattr(config_instance, attr, "")
@@ -275,16 +278,23 @@ def compose(self) -> ComposeResult:
275278
)
276279
except AttributeError:
277280
value = str(raw_value)
281+
elif is_days and raw_value != "":
282+
try:
283+
value = str(
284+
raw_value.total_seconds() / 86400.0
285+
)
286+
except AttributeError:
287+
value = str(raw_value)
278288
else:
279289
value = str(raw_value)
280290
else:
281291
value = ""
282292
label = f"{attr.replace('_', ' ').title()}:"
283-
yield Label(
284-
label
285-
if not is_minutes
286-
else label.replace(":", " Minutes:")
287-
)
293+
if is_minutes:
294+
label = label.replace(":", " Minutes:")
295+
elif is_days:
296+
label = label.replace(":", " Days:")
297+
yield Label(label)
288298
yield Input(
289299
id=f"{instrument_name}_{attr}",
290300
type=type_to_textual(
@@ -392,11 +402,14 @@ def _update_instrument_configs(self):
392402
for attr_meta in attributes:
393403
attr = attr_meta["name"]
394404
is_minutes = attr_meta.get("minutes", False)
405+
is_days = attr_meta.get("days", False)
395406
input_id = f"{instrument_name}_{attr}"
396407
value = self.query_one(f"#{input_id}").value
397408
field_type = get_field_type(config_class, attr)
398409
if is_minutes and field_type is datetime.timedelta:
399410
value = datetime.timedelta(minutes=float(value))
411+
elif is_days and field_type is datetime.timedelta:
412+
value = datetime.timedelta(days=float(value))
400413
else:
401414
value = field_type(value)
402415
kwargs[attr] = value

src/virtualship/models/expedition.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from virtualship.utils import (
1515
_get_bathy_data,
1616
_get_waypoint_latlons,
17-
_validate_numeric_mins_to_timedelta,
17+
_validate_numeric_to_timedelta,
1818
)
1919

2020
from .location import Location
@@ -227,19 +227,19 @@ class ArgoFloatConfig(pydantic.BaseModel):
227227

228228
@pydantic.field_serializer("lifetime")
229229
def _serialize_lifetime(self, value: timedelta, _info):
230-
return value.total_seconds() / 60.0
230+
return value.total_seconds() / 86400.0 # [days]
231231

232232
@pydantic.field_validator("lifetime", mode="before")
233233
def _validate_lifetime(cls, value: int | float | timedelta) -> timedelta:
234-
return _validate_numeric_mins_to_timedelta(value)
234+
return _validate_numeric_to_timedelta(value, "days")
235235

236236
@pydantic.field_serializer("stationkeeping_time")
237237
def _serialize_stationkeeping_time(self, value: timedelta, _info):
238238
return value.total_seconds() / 60.0
239239

240240
@pydantic.field_validator("stationkeeping_time", mode="before")
241241
def _validate_stationkeeping_time(cls, value: int | float | timedelta) -> timedelta:
242-
return _validate_numeric_mins_to_timedelta(value)
242+
return _validate_numeric_to_timedelta(value, "minutes")
243243

244244
model_config = pydantic.ConfigDict(populate_by_name=True)
245245

@@ -263,7 +263,7 @@ def _serialize_period(self, value: timedelta, _info):
263263

264264
@pydantic.field_validator("period", mode="before")
265265
def _validate_period(cls, value: int | float | timedelta) -> timedelta:
266-
return _validate_numeric_mins_to_timedelta(value)
266+
return _validate_numeric_to_timedelta(value, "minutes")
267267

268268

269269
class CTDConfig(pydantic.BaseModel):
@@ -285,7 +285,7 @@ def _serialize_stationkeeping_time(self, value: timedelta, _info):
285285

286286
@pydantic.field_validator("stationkeeping_time", mode="before")
287287
def _validate_stationkeeping_time(cls, value: int | float | timedelta) -> timedelta:
288-
return _validate_numeric_mins_to_timedelta(value)
288+
return _validate_numeric_to_timedelta(value, "minutes")
289289

290290

291291
class CTD_BGCConfig(pydantic.BaseModel):
@@ -307,7 +307,7 @@ def _serialize_stationkeeping_time(self, value: timedelta, _info):
307307

308308
@pydantic.field_validator("stationkeeping_time", mode="before")
309309
def _validate_stationkeeping_time(cls, value: int | float | timedelta) -> timedelta:
310-
return _validate_numeric_mins_to_timedelta(value)
310+
return _validate_numeric_to_timedelta(value, "minutes")
311311

312312

313313
class ShipUnderwaterSTConfig(pydantic.BaseModel):
@@ -327,7 +327,7 @@ def _serialize_period(self, value: timedelta, _info):
327327

328328
@pydantic.field_validator("period", mode="before")
329329
def _validate_period(cls, value: int | float | timedelta) -> timedelta:
330-
return _validate_numeric_mins_to_timedelta(value)
330+
return _validate_numeric_to_timedelta(value, "minutes")
331331

332332

333333
class DrifterConfig(pydantic.BaseModel):
@@ -349,19 +349,19 @@ class DrifterConfig(pydantic.BaseModel):
349349

350350
@pydantic.field_serializer("lifetime")
351351
def _serialize_lifetime(self, value: timedelta, _info):
352-
return value.total_seconds() / 60.0
352+
return value.total_seconds() / 86400.0 # [days]
353353

354354
@pydantic.field_validator("lifetime", mode="before")
355355
def _validate_lifetime(cls, value: int | float | timedelta) -> timedelta:
356-
return _validate_numeric_mins_to_timedelta(value)
356+
return _validate_numeric_to_timedelta(value, "days")
357357

358358
@pydantic.field_serializer("stationkeeping_time")
359359
def _serialize_stationkeeping_time(self, value: timedelta, _info):
360360
return value.total_seconds() / 60.0
361361

362362
@pydantic.field_validator("stationkeeping_time", mode="before")
363363
def _validate_stationkeeping_time(cls, value: int | float | timedelta) -> timedelta:
364-
return _validate_numeric_mins_to_timedelta(value)
364+
return _validate_numeric_to_timedelta(value, "minutes")
365365

366366

367367
class XBTConfig(pydantic.BaseModel):

src/virtualship/static/expedition.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ instruments_config:
4343
min_depth_meter: 0.0
4444
vertical_speed_meter_per_second: -0.1
4545
stationkeeping_time_minutes: 20.0
46-
lifetime_days: 90720.0
46+
lifetime_days: 63.0
4747
ctd_config:
4848
max_depth_meter: -2000.0
4949
min_depth_meter: -11.0
@@ -54,7 +54,7 @@ instruments_config:
5454
stationkeeping_time_minutes: 50.0
5555
drifter_config:
5656
depth_meter: -1.0
57-
lifetime_days: 60480.0
57+
lifetime_days: 42.0
5858
stationkeeping_time_minutes: 20.0
5959
xbt_config:
6060
max_depth_meter: -285.0

src/virtualship/utils.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
import copernicusmarine
1414
import numpy as np
1515
import xarray as xr
16-
from parcels import FieldSet
1716

17+
from parcels import FieldSet
1818
from virtualship.errors import CopernicusCatalogueError
1919

2020
if TYPE_CHECKING:
@@ -186,11 +186,16 @@ def mfp_to_yaml(coordinates_file_path: str, yaml_output_path: str): # noqa: D41
186186
expedition.to_yaml(yaml_output_path)
187187

188188

189-
def _validate_numeric_mins_to_timedelta(value: int | float | timedelta) -> timedelta:
190-
"""Convert minutes to timedelta when reading."""
189+
def _validate_numeric_to_timedelta(
190+
value: int | float | timedelta, unit: str
191+
) -> timedelta:
192+
"""Convert to timedelta when reading."""
191193
if isinstance(value, timedelta):
192194
return value
193-
return timedelta(minutes=value)
195+
if unit == "minutes":
196+
return timedelta(minutes=float(value))
197+
elif unit == "days":
198+
return timedelta(days=float(value))
194199

195200

196201
def _get_expedition(expedition_dir: Path) -> Expedition:

tests/expedition/expedition_dir/expedition.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ instruments_config:
3030
min_depth_meter: 0.0
3131
vertical_speed_meter_per_second: -0.1
3232
stationkeeping_time_minutes: 20.0
33-
lifetime_days: 90720.0
33+
lifetime_days: 63.0
3434
ctd_config:
3535
max_depth_meter: -2000.0
3636
min_depth_meter: -11.0
@@ -41,7 +41,7 @@ instruments_config:
4141
stationkeeping_time_minutes: 50.0
4242
drifter_config:
4343
depth_meter: -1.0
44-
lifetime_days: 40320.0
44+
lifetime_days: 28.0
4545
stationkeeping_time_minutes: 20.0
4646
ship_underwater_st_config:
4747
period_minutes: 5.0

0 commit comments

Comments
 (0)