From ff0ef88b602207e981efb236da8a3f2db3e1c341 Mon Sep 17 00:00:00 2001 From: Emma Daniels Date: Fri, 14 Feb 2025 16:14:02 +0100 Subject: [PATCH 01/12] speed and other little things --- src/virtualship/expedition/ship_config.py | 2 +- src/virtualship/expedition/simulate_measurements.py | 2 +- src/virtualship/expedition/simulate_schedule.py | 9 +++++---- src/virtualship/expedition/verify_schedule.py | 2 +- src/virtualship/static/ship_config.yaml | 3 ++- tests/expedition/test_simulate_schedule.py | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/virtualship/expedition/ship_config.py b/src/virtualship/expedition/ship_config.py index 7bb41e84..db2c7a9a 100644 --- a/src/virtualship/expedition/ship_config.py +++ b/src/virtualship/expedition/ship_config.py @@ -101,7 +101,7 @@ class XBTConfig(pydantic.BaseModel): class ShipConfig(pydantic.BaseModel): """Configuration of the virtual ship.""" - ship_speed_meter_per_second: float = pydantic.Field(gt=0.0) + ship_speed_knots: float = pydantic.Field(gt=0.0) """ Velocity of the ship in meters per second. """ diff --git a/src/virtualship/expedition/simulate_measurements.py b/src/virtualship/expedition/simulate_measurements.py index bf28c989..e50a1a46 100644 --- a/src/virtualship/expedition/simulate_measurements.py +++ b/src/virtualship/expedition/simulate_measurements.py @@ -85,7 +85,7 @@ def simulate_measurements( out_path=expedition_dir.joinpath("results", "drifters.zarr"), fieldset=input_data.drifter_fieldset, drifters=measurements.drifters, - outputdt=timedelta(hours=5), + outputdt=timedelta(minutes=ship_config.drifter_config.period_minutes), dt=timedelta(minutes=5), endtime=None, ) diff --git a/src/virtualship/expedition/simulate_schedule.py b/src/virtualship/expedition/simulate_schedule.py index bec54468..6ec678ec 100644 --- a/src/virtualship/expedition/simulate_schedule.py +++ b/src/virtualship/expedition/simulate_schedule.py @@ -122,11 +122,12 @@ def _progress_time_traveling_towards(self, location: Location) -> None: lons2=location.lon, lats2=location.lat, ) + ship_speed_meter_per_second = self._ship_config.ship_speed_knots * 3600/1852 azimuth1 = geodinv[0] distance_to_next_waypoint = geodinv[2] time_to_reach = timedelta( seconds=distance_to_next_waypoint - / self._ship_config.ship_speed_meter_per_second + / ship_speed_meter_per_second ) end_time = self._time + time_to_reach @@ -137,7 +138,7 @@ def _progress_time_traveling_towards(self, location: Location) -> None: while self._next_adcp_time <= end_time: time_to_sail = self._next_adcp_time - time distance_to_move = ( - self._ship_config.ship_speed_meter_per_second + ship_speed_meter_per_second * time_to_sail.total_seconds() ) geodfwd: tuple[float, float, float] = self._projection.fwd( @@ -164,7 +165,7 @@ def _progress_time_traveling_towards(self, location: Location) -> None: while self._next_ship_underwater_st_time <= end_time: time_to_sail = self._next_ship_underwater_st_time - time distance_to_move = ( - self._ship_config.ship_speed_meter_per_second + ship_speed_meter_per_second * time_to_sail.total_seconds() ) geodfwd: tuple[float, float, float] = self._projection.fwd( @@ -250,7 +251,7 @@ def _make_measurements(self, waypoint: Waypoint) -> timedelta: max_depth=self._ship_config.ctd_config.max_depth_meter, ) ) - time_costs.append(timedelta(minutes=20)) + time_costs.append(timedelta(minutes=self._ship_config.ctd_config.stationkeeping_time_minutes)) elif instrument is InstrumentType.DRIFTER: self._measurements_to_simulate.drifters.append( Drifter( diff --git a/src/virtualship/expedition/verify_schedule.py b/src/virtualship/expedition/verify_schedule.py index fcc77217..7300d432 100644 --- a/src/virtualship/expedition/verify_schedule.py +++ b/src/virtualship/expedition/verify_schedule.py @@ -99,7 +99,7 @@ def verify_schedule( distance = geodinv[2] time_to_reach = timedelta( - seconds=distance / ship_config.ship_speed_meter_per_second + seconds=distance / ship_config.ship_speed_knots * 3600/1852 ) arrival_time = time + time_to_reach diff --git a/src/virtualship/static/ship_config.yaml b/src/virtualship/static/ship_config.yaml index 729e4d75..aaf14915 100644 --- a/src/virtualship/static/ship_config.yaml +++ b/src/virtualship/static/ship_config.yaml @@ -1,4 +1,4 @@ -ship_speed_meter_per_second: 5.14 +ship_speed_knots: 10.0 adcp_config: num_bins: 40 max_depth_meter: -1000.0 @@ -16,6 +16,7 @@ ctd_config: stationkeeping_time_minutes: 20.0 drifter_config: depth_meter: 0.0 + period_minutes: 60.0 lifetime_minutes: 40320.0 xbt_config: max_depth_meter: -285.0 diff --git a/tests/expedition/test_simulate_schedule.py b/tests/expedition/test_simulate_schedule.py index 01544c42..3c250aff 100644 --- a/tests/expedition/test_simulate_schedule.py +++ b/tests/expedition/test_simulate_schedule.py @@ -17,7 +17,7 @@ def test_simulate_schedule_feasible() -> None: projection = pyproj.Geod(ellps="WGS84") ship_config = ShipConfig.from_yaml("expedition_dir/ship_config.yaml") - ship_config.ship_speed_meter_per_second = 5.14 + ship_config.ship_speed_knots = 10.0 schedule = Schedule( waypoints=[ Waypoint(location=Location(0, 0), time=base_time), From a6f9423f731d2a133c9b237ef44106e119156304 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 14 Feb 2025 15:24:52 +0000 Subject: [PATCH 02/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/tutorials/ADCP_data_tutorial.ipynb | 2 +- docs/tutorials/CTD_data_tutorial.ipynb | 4 ++-- src/virtualship/expedition/simulate_schedule.py | 17 +++++++++-------- src/virtualship/expedition/verify_schedule.py | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/ADCP_data_tutorial.ipynb b/docs/tutorials/ADCP_data_tutorial.ipynb index 9df68b3d..a7fe063b 100644 --- a/docs/tutorials/ADCP_data_tutorial.ipynb +++ b/docs/tutorials/ADCP_data_tutorial.ipynb @@ -128,7 +128,7 @@ " {\"long_name\": \"distance to coast\", \"units\": \"m\", \"positive\": \"shoreward\"}\n", ")\n", "peru = peru.set_coords(\"s\").sortby(\"s\")\n", - "print(f\"max distance from coast: {abs(peru.s.min()).data/1000:.2f} km\")" + "print(f\"max distance from coast: {abs(peru.s.min()).data / 1000:.2f} km\")" ] }, { diff --git a/docs/tutorials/CTD_data_tutorial.ipynb b/docs/tutorials/CTD_data_tutorial.ipynb index c374a476..fcd5d181 100644 --- a/docs/tutorials/CTD_data_tutorial.ipynb +++ b/docs/tutorials/CTD_data_tutorial.ipynb @@ -263,12 +263,12 @@ "source": [ "# Fill the dataset with values from the csv files.\n", "for ob in range(5): # loop through files\n", - " header = pd.read_csv(f\"Japan/CTD_Japan_station_{ob+1}.csv\", nrows=7, header=None)\n", + " header = pd.read_csv(f\"Japan/CTD_Japan_station_{ob + 1}.csv\", nrows=7, header=None)\n", " ctd.lon[ob] = header.iloc[0, 1]\n", " ctd.lat[ob] = header.iloc[1, 1]\n", " ctd.start_time[ob] = header.iloc[2, 1]\n", " ctd.end_time[ob] = header.iloc[3, 1]\n", - " data = pd.read_csv(f\"Japan/CTD_Japan_station_{ob+1}.csv\", skiprows=4)\n", + " data = pd.read_csv(f\"Japan/CTD_Japan_station_{ob + 1}.csv\", skiprows=4)\n", " ctd.P[:, ob] = data[\"pressure [hPa]\"]\n", " ctd.T[:, ob] = data[\"temperature [degC]\"]\n", " ctd.S[:, ob] = data[\"salinity [g kg-1]\"]" diff --git a/src/virtualship/expedition/simulate_schedule.py b/src/virtualship/expedition/simulate_schedule.py index 6ec678ec..13504135 100644 --- a/src/virtualship/expedition/simulate_schedule.py +++ b/src/virtualship/expedition/simulate_schedule.py @@ -122,12 +122,11 @@ def _progress_time_traveling_towards(self, location: Location) -> None: lons2=location.lon, lats2=location.lat, ) - ship_speed_meter_per_second = self._ship_config.ship_speed_knots * 3600/1852 + ship_speed_meter_per_second = self._ship_config.ship_speed_knots * 3600 / 1852 azimuth1 = geodinv[0] distance_to_next_waypoint = geodinv[2] time_to_reach = timedelta( - seconds=distance_to_next_waypoint - / ship_speed_meter_per_second + seconds=distance_to_next_waypoint / ship_speed_meter_per_second ) end_time = self._time + time_to_reach @@ -138,8 +137,7 @@ def _progress_time_traveling_towards(self, location: Location) -> None: while self._next_adcp_time <= end_time: time_to_sail = self._next_adcp_time - time distance_to_move = ( - ship_speed_meter_per_second - * time_to_sail.total_seconds() + ship_speed_meter_per_second * time_to_sail.total_seconds() ) geodfwd: tuple[float, float, float] = self._projection.fwd( lons=location.lon, @@ -165,8 +163,7 @@ def _progress_time_traveling_towards(self, location: Location) -> None: while self._next_ship_underwater_st_time <= end_time: time_to_sail = self._next_ship_underwater_st_time - time distance_to_move = ( - ship_speed_meter_per_second - * time_to_sail.total_seconds() + ship_speed_meter_per_second * time_to_sail.total_seconds() ) geodfwd: tuple[float, float, float] = self._projection.fwd( lons=location.lon, @@ -251,7 +248,11 @@ def _make_measurements(self, waypoint: Waypoint) -> timedelta: max_depth=self._ship_config.ctd_config.max_depth_meter, ) ) - time_costs.append(timedelta(minutes=self._ship_config.ctd_config.stationkeeping_time_minutes)) + time_costs.append( + timedelta( + minutes=self._ship_config.ctd_config.stationkeeping_time_minutes + ) + ) elif instrument is InstrumentType.DRIFTER: self._measurements_to_simulate.drifters.append( Drifter( diff --git a/src/virtualship/expedition/verify_schedule.py b/src/virtualship/expedition/verify_schedule.py index 7300d432..d3b01011 100644 --- a/src/virtualship/expedition/verify_schedule.py +++ b/src/virtualship/expedition/verify_schedule.py @@ -99,7 +99,7 @@ def verify_schedule( distance = geodinv[2] time_to_reach = timedelta( - seconds=distance / ship_config.ship_speed_knots * 3600/1852 + seconds=distance / ship_config.ship_speed_knots * 3600 / 1852 ) arrival_time = time + time_to_reach From d32fff62a454af3e7eb757d1791e8a62c18cf6e3 Mon Sep 17 00:00:00 2001 From: Erik van Sebille Date: Wed, 19 Feb 2025 13:01:53 +0100 Subject: [PATCH 03/12] Some fixes to config renaming --- src/virtualship/expedition/ship_config.py | 8 ++++---- tests/expedition/expedition_dir/ship_config.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/virtualship/expedition/ship_config.py b/src/virtualship/expedition/ship_config.py index db2c7a9a..fcdc76f5 100644 --- a/src/virtualship/expedition/ship_config.py +++ b/src/virtualship/expedition/ship_config.py @@ -41,7 +41,7 @@ def _serialize_period(self, value: timedelta, _info): class CTDConfig(pydantic.BaseModel): """Configuration for CTD instrument.""" - stationkeeping_time: timedelta = pydantic.Field( + stationkeeping_time_minutes: timedelta = pydantic.Field( serialization_alias="stationkeeping_time_minutes", validation_alias="stationkeeping_time_minutes", gt=timedelta(), @@ -51,8 +51,8 @@ class CTDConfig(pydantic.BaseModel): model_config = pydantic.ConfigDict(populate_by_name=True) - @pydantic.field_serializer("stationkeeping_time") - def _serialize_stationkeeping_time(self, value: timedelta, _info): + @pydantic.field_serializer("stationkeeping_time_minutes") + def _serialize_stationkeeping_time_minutes(self, value: timedelta, _info): return value.total_seconds() / 60.0 @@ -103,7 +103,7 @@ class ShipConfig(pydantic.BaseModel): ship_speed_knots: float = pydantic.Field(gt=0.0) """ - Velocity of the ship in meters per second. + Velocity of the ship in knots. """ argo_float_config: ArgoFloatConfig | None = None diff --git a/tests/expedition/expedition_dir/ship_config.yaml b/tests/expedition/expedition_dir/ship_config.yaml index c057d6b5..dfdcbfec 100644 --- a/tests/expedition/expedition_dir/ship_config.yaml +++ b/tests/expedition/expedition_dir/ship_config.yaml @@ -1,4 +1,4 @@ -ship_speed_meter_per_second: 5.14 +ship_speed_knots: 5.14 adcp_config: num_bins: 40 max_depth_meter: -1000.0 From e9a4a3fcdc131e9a24f248f63e00ce14f724a64a Mon Sep 17 00:00:00 2001 From: Emma Daniels Date: Wed, 19 Feb 2025 14:37:15 +0100 Subject: [PATCH 04/12] remove double timedelta --- src/virtualship/expedition/simulate_schedule.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/virtualship/expedition/simulate_schedule.py b/src/virtualship/expedition/simulate_schedule.py index 13504135..90d56d5f 100644 --- a/src/virtualship/expedition/simulate_schedule.py +++ b/src/virtualship/expedition/simulate_schedule.py @@ -249,9 +249,8 @@ def _make_measurements(self, waypoint: Waypoint) -> timedelta: ) ) time_costs.append( - timedelta( - minutes=self._ship_config.ctd_config.stationkeeping_time_minutes - ) + minutes=self._ship_config.ctd_config.stationkeeping_time_minutes + ) elif instrument is InstrumentType.DRIFTER: self._measurements_to_simulate.drifters.append( From bc61773452d8d04b4a62ed9046298a06a6fad25a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:37:39 +0000 Subject: [PATCH 05/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/virtualship/expedition/simulate_schedule.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/virtualship/expedition/simulate_schedule.py b/src/virtualship/expedition/simulate_schedule.py index 90d56d5f..105c47cb 100644 --- a/src/virtualship/expedition/simulate_schedule.py +++ b/src/virtualship/expedition/simulate_schedule.py @@ -250,7 +250,6 @@ def _make_measurements(self, waypoint: Waypoint) -> timedelta: ) time_costs.append( minutes=self._ship_config.ctd_config.stationkeeping_time_minutes - ) elif instrument is InstrumentType.DRIFTER: self._measurements_to_simulate.drifters.append( From 974aa59b50a7b84c09f8e8921ffe4318f2cd9f78 Mon Sep 17 00:00:00 2001 From: Erik van Sebille Date: Wed, 19 Feb 2025 20:08:22 +0100 Subject: [PATCH 06/12] Fixing smalll bug in creating list of costs --- src/virtualship/expedition/simulate_schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtualship/expedition/simulate_schedule.py b/src/virtualship/expedition/simulate_schedule.py index 105c47cb..59250e43 100644 --- a/src/virtualship/expedition/simulate_schedule.py +++ b/src/virtualship/expedition/simulate_schedule.py @@ -249,7 +249,7 @@ def _make_measurements(self, waypoint: Waypoint) -> timedelta: ) ) time_costs.append( - minutes=self._ship_config.ctd_config.stationkeeping_time_minutes + self._ship_config.ctd_config.stationkeeping_time_minutes ) elif instrument is InstrumentType.DRIFTER: self._measurements_to_simulate.drifters.append( From e59bdf744464522b5e97fa024848fe994666d082 Mon Sep 17 00:00:00 2001 From: Erik van Sebille Date: Wed, 19 Feb 2025 20:08:45 +0100 Subject: [PATCH 07/12] FIxing drifter measuring interval --- src/virtualship/expedition/ship_config.py | 5 +++++ src/virtualship/expedition/simulate_measurements.py | 2 +- tests/expedition/expedition_dir/ship_config.yaml | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/virtualship/expedition/ship_config.py b/src/virtualship/expedition/ship_config.py index fcdc76f5..be75f045 100644 --- a/src/virtualship/expedition/ship_config.py +++ b/src/virtualship/expedition/ship_config.py @@ -81,6 +81,11 @@ class DrifterConfig(pydantic.BaseModel): validation_alias="lifetime_minutes", gt=timedelta(), ) + period: timedelta = pydantic.Field( + serialization_alias="period_minutes", + validation_alias="period_minutes", + gt=timedelta(), + ) model_config = pydantic.ConfigDict(populate_by_name=True) diff --git a/src/virtualship/expedition/simulate_measurements.py b/src/virtualship/expedition/simulate_measurements.py index e50a1a46..be382222 100644 --- a/src/virtualship/expedition/simulate_measurements.py +++ b/src/virtualship/expedition/simulate_measurements.py @@ -85,7 +85,7 @@ def simulate_measurements( out_path=expedition_dir.joinpath("results", "drifters.zarr"), fieldset=input_data.drifter_fieldset, drifters=measurements.drifters, - outputdt=timedelta(minutes=ship_config.drifter_config.period_minutes), + outputdt=ship_config.drifter_config.period, dt=timedelta(minutes=5), endtime=None, ) diff --git a/tests/expedition/expedition_dir/ship_config.yaml b/tests/expedition/expedition_dir/ship_config.yaml index dfdcbfec..a0d89d77 100644 --- a/tests/expedition/expedition_dir/ship_config.yaml +++ b/tests/expedition/expedition_dir/ship_config.yaml @@ -1,4 +1,4 @@ -ship_speed_knots: 5.14 +ship_speed_knots: 10.0 adcp_config: num_bins: 40 max_depth_meter: -1000.0 @@ -16,6 +16,7 @@ ctd_config: stationkeeping_time_minutes: 20.0 drifter_config: depth_meter: 0.0 + period_minutes: 60.0 lifetime_minutes: 40320.0 ship_underwater_st_config: period_minutes: 5.0 From 065bdb9154cf58078c49214a5fb1544c1672002c Mon Sep 17 00:00:00 2001 From: Erik van Sebille Date: Thu, 20 Feb 2025 07:37:41 +0100 Subject: [PATCH 08/12] Adding chunks to Drifter zarr output --- src/virtualship/instruments/drifter.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/virtualship/instruments/drifter.py b/src/virtualship/instruments/drifter.py index 378af42f..70bde79c 100644 --- a/src/virtualship/instruments/drifter.py +++ b/src/virtualship/instruments/drifter.py @@ -17,6 +17,7 @@ class Drifter: spacetime: Spacetime depth: float # depth at which it floats and samples lifetime: timedelta | None # if none, lifetime is infinite + period: timedelta # time between samples _DrifterParticle = JITParticle.add_variables( @@ -81,7 +82,9 @@ def simulate_drifters( ) # define output file for the simulation - out_file = drifter_particleset.ParticleFile(name=out_path, outputdt=outputdt) + out_file = drifter_particleset.ParticleFile( + name=out_path, outputdt=outputdt, chunks=[len(drifter_particleset), 100] + ) # get earliest between fieldset end time and provide end time fieldset_endtime = fieldset.time_origin.fulltime(fieldset.U.grid.time_full[-1]) From 99955d7d231b76ef7dee9b51b776b5812c9fb6e4 Mon Sep 17 00:00:00 2001 From: Erik van Sebille Date: Thu, 20 Feb 2025 07:53:56 +0100 Subject: [PATCH 09/12] Adding test for pydantic serialiser converstion from minutes to seconds --- src/virtualship/expedition/ship_config.py | 12 ++++++++---- tests/expedition/test_simulate_schedule.py | 9 +++++++++ tests/instruments/test_drifter.py | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/virtualship/expedition/ship_config.py b/src/virtualship/expedition/ship_config.py index be75f045..21bcdc14 100644 --- a/src/virtualship/expedition/ship_config.py +++ b/src/virtualship/expedition/ship_config.py @@ -35,7 +35,7 @@ class ADCPConfig(pydantic.BaseModel): @pydantic.field_serializer("period") def _serialize_period(self, value: timedelta, _info): - return value.total_seconds() / 60.0 + return value.total_seconds() * 60.0 class CTDConfig(pydantic.BaseModel): @@ -53,7 +53,7 @@ class CTDConfig(pydantic.BaseModel): @pydantic.field_serializer("stationkeeping_time_minutes") def _serialize_stationkeeping_time_minutes(self, value: timedelta, _info): - return value.total_seconds() / 60.0 + return value.total_seconds() * 60.0 class ShipUnderwaterSTConfig(pydantic.BaseModel): @@ -69,7 +69,7 @@ class ShipUnderwaterSTConfig(pydantic.BaseModel): @pydantic.field_serializer("period") def _serialize_period(self, value: timedelta, _info): - return value.total_seconds() / 60.0 + return value.total_seconds() * 60.0 class DrifterConfig(pydantic.BaseModel): @@ -91,7 +91,11 @@ class DrifterConfig(pydantic.BaseModel): @pydantic.field_serializer("lifetime") def _serialize_lifetime(self, value: timedelta, _info): - return value.total_seconds() / 60.0 + return value.total_seconds() * 60.0 + + @pydantic.field_serializer("period") + def _serialize_period(self, value: timedelta, _info): + return value.total_seconds() * 60.0 class XBTConfig(pydantic.BaseModel): diff --git a/tests/expedition/test_simulate_schedule.py b/tests/expedition/test_simulate_schedule.py index 3c250aff..ca6fd4bb 100644 --- a/tests/expedition/test_simulate_schedule.py +++ b/tests/expedition/test_simulate_schedule.py @@ -46,3 +46,12 @@ def test_simulate_schedule_too_far() -> None: result = simulate_schedule(projection, ship_config, schedule) assert isinstance(result, ScheduleProblem) + + +def test_time_in_minutes_in_ship_schedule() -> None: + """Test whether the pydantic serializer picks up the time *in minutes* in the ship schedule.""" + ship_config = ShipConfig.from_yaml("expedition_dir/ship_config.yaml") + assert ship_config.drifter_config.period == timedelta(minutes=60) + assert ship_config.adcp_config.period == timedelta(minutes=5) + assert ship_config.ctd_config.stationkeeping_time_minutes == timedelta(minutes=20) + assert ship_config.ship_underwater_st_config.period == timedelta(minutes=5) diff --git a/tests/instruments/test_drifter.py b/tests/instruments/test_drifter.py index c62b5d60..0e8b0354 100644 --- a/tests/instruments/test_drifter.py +++ b/tests/instruments/test_drifter.py @@ -41,6 +41,7 @@ def test_simulate_drifters(tmpdir) -> None: ), depth=0.0, lifetime=datetime.timedelta(hours=2), + period=60, ), Drifter( spacetime=Spacetime( @@ -49,6 +50,7 @@ def test_simulate_drifters(tmpdir) -> None: ), depth=0.0, lifetime=None, + period=60, ), ] From 77a822074e5c6c2a47b17b6eb12b90e5970a87f9 Mon Sep 17 00:00:00 2001 From: Vecko <36369090+VeckoTheGecko@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:35:09 +0100 Subject: [PATCH 10/12] Fix serialisation and add Drifter validator --- src/virtualship/expedition/ship_config.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/virtualship/expedition/ship_config.py b/src/virtualship/expedition/ship_config.py index 1653d75d..45bb5334 100644 --- a/src/virtualship/expedition/ship_config.py +++ b/src/virtualship/expedition/ship_config.py @@ -37,7 +37,7 @@ class ADCPConfig(pydantic.BaseModel): @pydantic.field_serializer("period") def _serialize_period(self, value: timedelta, _info): - return value.total_seconds() * 60.0 + return value.total_seconds() / 60.0 @pydantic.field_validator("period", mode="before") def _validate_period(cls, value: int | float | timedelta) -> timedelta: @@ -59,7 +59,7 @@ class CTDConfig(pydantic.BaseModel): @pydantic.field_serializer("stationkeeping_time_minutes") def _serialize_stationkeeping_time_minutes(self, value: timedelta, _info): - return value.total_seconds() * 60.0 + return value.total_seconds() / 60.0 @pydantic.field_validator("stationkeeping_time", mode="before") def _validate_stationkeeping_time(cls, value: int | float | timedelta) -> timedelta: @@ -79,7 +79,7 @@ class ShipUnderwaterSTConfig(pydantic.BaseModel): @pydantic.field_serializer("period") def _serialize_period(self, value: timedelta, _info): - return value.total_seconds() * 60.0 + return value.total_seconds() / 60.0 @pydantic.field_validator("period", mode="before") def _validate_period(cls, value: int | float | timedelta) -> timedelta: @@ -105,11 +105,15 @@ class DrifterConfig(pydantic.BaseModel): @pydantic.field_serializer("lifetime") def _serialize_lifetime(self, value: timedelta, _info): - return value.total_seconds() * 60.0 + return value.total_seconds() / 60.0 @pydantic.field_serializer("period") def _serialize_period(self, value: timedelta, _info): - return value.total_seconds() * 60.0 + return value.total_seconds() / 60.0 + + @pydantic.field_validator("period", mode="before") + def _validate_period(cls, value: int | float | timedelta) -> timedelta: + return _validate_numeric_mins_to_timedelta(value) @pydantic.field_validator("lifetime", mode="before") def _validate_lifetime(cls, value: int | float | timedelta) -> timedelta: From 2620c7e79e105d01ff6e26eed9973069d5a8f17f Mon Sep 17 00:00:00 2001 From: Vecko <36369090+VeckoTheGecko@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:35:42 +0100 Subject: [PATCH 11/12] Update var name to stationkeeping_time --- src/virtualship/expedition/ship_config.py | 6 +++--- src/virtualship/expedition/simulate_schedule.py | 4 +--- tests/expedition/test_simulate_schedule.py | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/virtualship/expedition/ship_config.py b/src/virtualship/expedition/ship_config.py index 45bb5334..66353c7c 100644 --- a/src/virtualship/expedition/ship_config.py +++ b/src/virtualship/expedition/ship_config.py @@ -47,7 +47,7 @@ def _validate_period(cls, value: int | float | timedelta) -> timedelta: class CTDConfig(pydantic.BaseModel): """Configuration for CTD instrument.""" - stationkeeping_time_minutes: timedelta = pydantic.Field( + stationkeeping_time: timedelta = pydantic.Field( serialization_alias="stationkeeping_time_minutes", validation_alias="stationkeeping_time_minutes", gt=timedelta(), @@ -57,8 +57,8 @@ class CTDConfig(pydantic.BaseModel): model_config = pydantic.ConfigDict(populate_by_name=True) - @pydantic.field_serializer("stationkeeping_time_minutes") - def _serialize_stationkeeping_time_minutes(self, value: timedelta, _info): + @pydantic.field_serializer("stationkeeping_time") + def _serialize_stationkeeping_time(self, value: timedelta, _info): return value.total_seconds() / 60.0 @pydantic.field_validator("stationkeeping_time", mode="before") diff --git a/src/virtualship/expedition/simulate_schedule.py b/src/virtualship/expedition/simulate_schedule.py index 59250e43..aee01509 100644 --- a/src/virtualship/expedition/simulate_schedule.py +++ b/src/virtualship/expedition/simulate_schedule.py @@ -248,9 +248,7 @@ def _make_measurements(self, waypoint: Waypoint) -> timedelta: max_depth=self._ship_config.ctd_config.max_depth_meter, ) ) - time_costs.append( - self._ship_config.ctd_config.stationkeeping_time_minutes - ) + time_costs.append(self._ship_config.ctd_config.stationkeeping_time) elif instrument is InstrumentType.DRIFTER: self._measurements_to_simulate.drifters.append( Drifter( diff --git a/tests/expedition/test_simulate_schedule.py b/tests/expedition/test_simulate_schedule.py index ca6fd4bb..951244eb 100644 --- a/tests/expedition/test_simulate_schedule.py +++ b/tests/expedition/test_simulate_schedule.py @@ -53,5 +53,5 @@ def test_time_in_minutes_in_ship_schedule() -> None: ship_config = ShipConfig.from_yaml("expedition_dir/ship_config.yaml") assert ship_config.drifter_config.period == timedelta(minutes=60) assert ship_config.adcp_config.period == timedelta(minutes=5) - assert ship_config.ctd_config.stationkeeping_time_minutes == timedelta(minutes=20) + assert ship_config.ctd_config.stationkeeping_time == timedelta(minutes=20) assert ship_config.ship_underwater_st_config.period == timedelta(minutes=5) From 35163e1a5bf29d969c1c581e7084dadd0a7108e4 Mon Sep 17 00:00:00 2001 From: Vecko <36369090+VeckoTheGecko@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:56:11 +0100 Subject: [PATCH 12/12] Remove drifter period changes --- src/virtualship/expedition/ship_config.py | 13 ------------- src/virtualship/expedition/simulate_measurements.py | 2 +- src/virtualship/instruments/drifter.py | 1 - src/virtualship/static/ship_config.yaml | 1 - tests/expedition/expedition_dir/ship_config.yaml | 1 - tests/expedition/test_simulate_schedule.py | 1 - tests/instruments/test_drifter.py | 2 -- 7 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/virtualship/expedition/ship_config.py b/src/virtualship/expedition/ship_config.py index 66353c7c..8969f1c4 100644 --- a/src/virtualship/expedition/ship_config.py +++ b/src/virtualship/expedition/ship_config.py @@ -95,11 +95,6 @@ class DrifterConfig(pydantic.BaseModel): validation_alias="lifetime_minutes", gt=timedelta(), ) - period: timedelta = pydantic.Field( - serialization_alias="period_minutes", - validation_alias="period_minutes", - gt=timedelta(), - ) model_config = pydantic.ConfigDict(populate_by_name=True) @@ -107,14 +102,6 @@ class DrifterConfig(pydantic.BaseModel): def _serialize_lifetime(self, value: timedelta, _info): return value.total_seconds() / 60.0 - @pydantic.field_serializer("period") - def _serialize_period(self, value: timedelta, _info): - return value.total_seconds() / 60.0 - - @pydantic.field_validator("period", mode="before") - def _validate_period(cls, value: int | float | timedelta) -> timedelta: - return _validate_numeric_mins_to_timedelta(value) - @pydantic.field_validator("lifetime", mode="before") def _validate_lifetime(cls, value: int | float | timedelta) -> timedelta: return _validate_numeric_mins_to_timedelta(value) diff --git a/src/virtualship/expedition/simulate_measurements.py b/src/virtualship/expedition/simulate_measurements.py index be382222..bf28c989 100644 --- a/src/virtualship/expedition/simulate_measurements.py +++ b/src/virtualship/expedition/simulate_measurements.py @@ -85,7 +85,7 @@ def simulate_measurements( out_path=expedition_dir.joinpath("results", "drifters.zarr"), fieldset=input_data.drifter_fieldset, drifters=measurements.drifters, - outputdt=ship_config.drifter_config.period, + outputdt=timedelta(hours=5), dt=timedelta(minutes=5), endtime=None, ) diff --git a/src/virtualship/instruments/drifter.py b/src/virtualship/instruments/drifter.py index 70bde79c..2fd4180b 100644 --- a/src/virtualship/instruments/drifter.py +++ b/src/virtualship/instruments/drifter.py @@ -17,7 +17,6 @@ class Drifter: spacetime: Spacetime depth: float # depth at which it floats and samples lifetime: timedelta | None # if none, lifetime is infinite - period: timedelta # time between samples _DrifterParticle = JITParticle.add_variables( diff --git a/src/virtualship/static/ship_config.yaml b/src/virtualship/static/ship_config.yaml index aaf14915..494656c1 100644 --- a/src/virtualship/static/ship_config.yaml +++ b/src/virtualship/static/ship_config.yaml @@ -16,7 +16,6 @@ ctd_config: stationkeeping_time_minutes: 20.0 drifter_config: depth_meter: 0.0 - period_minutes: 60.0 lifetime_minutes: 40320.0 xbt_config: max_depth_meter: -285.0 diff --git a/tests/expedition/expedition_dir/ship_config.yaml b/tests/expedition/expedition_dir/ship_config.yaml index a0d89d77..09f40c0a 100644 --- a/tests/expedition/expedition_dir/ship_config.yaml +++ b/tests/expedition/expedition_dir/ship_config.yaml @@ -16,7 +16,6 @@ ctd_config: stationkeeping_time_minutes: 20.0 drifter_config: depth_meter: 0.0 - period_minutes: 60.0 lifetime_minutes: 40320.0 ship_underwater_st_config: period_minutes: 5.0 diff --git a/tests/expedition/test_simulate_schedule.py b/tests/expedition/test_simulate_schedule.py index 951244eb..6381b805 100644 --- a/tests/expedition/test_simulate_schedule.py +++ b/tests/expedition/test_simulate_schedule.py @@ -51,7 +51,6 @@ def test_simulate_schedule_too_far() -> None: def test_time_in_minutes_in_ship_schedule() -> None: """Test whether the pydantic serializer picks up the time *in minutes* in the ship schedule.""" ship_config = ShipConfig.from_yaml("expedition_dir/ship_config.yaml") - assert ship_config.drifter_config.period == timedelta(minutes=60) assert ship_config.adcp_config.period == timedelta(minutes=5) assert ship_config.ctd_config.stationkeeping_time == timedelta(minutes=20) assert ship_config.ship_underwater_st_config.period == timedelta(minutes=5) diff --git a/tests/instruments/test_drifter.py b/tests/instruments/test_drifter.py index 0e8b0354..c62b5d60 100644 --- a/tests/instruments/test_drifter.py +++ b/tests/instruments/test_drifter.py @@ -41,7 +41,6 @@ def test_simulate_drifters(tmpdir) -> None: ), depth=0.0, lifetime=datetime.timedelta(hours=2), - period=60, ), Drifter( spacetime=Spacetime( @@ -50,7 +49,6 @@ def test_simulate_drifters(tmpdir) -> None: ), depth=0.0, lifetime=None, - period=60, ), ]