Skip to content

Use depth dependence and a per-waypoint model for stationkeeping time - #411

Merged
j-atkins merged 24 commits into
mainfrom
depth-dependent-stationkeeping
Oct 20, 2026
Merged

j-atkins merged 24 commits into
mainfrom
depth-dependent-stationkeeping

Conversation

@j-atkins

@j-atkins j-atkins commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Note

This PR is part of a stack of three related PRs (#410, #411, #412). Each one builds on the one before it. I will request reviews for each in turn.

This PR replaces the fixed, per-instrument stationkeeping time approach with a per-waypoint model. The time a waypoint adds to the schedule is now the sum of the ship's deceleration time (to come to a stop), the instrument deployment time, and the ship's acceleration time (to get back up to cruising speed). Waypoints with no instruments add no time, as the ship sails straight past without decelerating/accelerating.

Deceleration and acceleration time fields are added to the ShipConfig object in expedition.py (15 minutes each by default) and are intended as ballpark default estimates. Accordingly, they are added as configuration options in the virtualship plan tool.

All instruments must now also have a deployment_time classmethod, which determines how much time their deployment adds at the waypoint. This keeps the timing specific and configurable by developers to each instrument. At present, only CTDs add time beyond deceleration and acceleration. A CTD cast's duration depends on the water depth, using a new sea_depth_meter field on each waypoint and a new winch_speed_meter_per_second in the CTD config. When sea_depth_meter is left as null, the cast is assumed to reach the CTD's configured maximum depth rather than bathymetry (i.e. the slowest case). Incorporating the estimated sea depth from the MFP exports will be implemented in a subsequent PR (i.e. #412).

The total stationkeeping time calculation now lives in one place (Expedition.stationkeeping_time) and is used by both schedule verification and the simulation, which previously kept separate versions of the logic.

Overall, this PR instroduces a breaking change, in that the previous expedition.yaml files with per-instrument stationkeeping_time_minutes fields will be rejected.

Docs and tests have also been updated.


Other note(s)

  • The logic is such that waypoint-based deployments are considered as being made concurrently so only the slowest counts towards the total stationkeeping time (and this is what the docs explains). At present, this is not too relevant because it's only CTDs which add deployment time at a waypoint (depth dependence), but it means the docs will still accurate if new instruments are added which do also have added deployment times.
  • Concrete instrument subclass class checks, e.g. that it has sensor kernels class attribute and now, as of this PR, that it has a deployment_time abstract classmethod, have been moved to the @register_instrument decorator. This allows both class attributes (sensor kernels) and classmethods (deployment_time) to be checked at import (with messaging if something is wrong) before runtime/the instrument subclasses are instantiated.

Closes #249

@j-atkins j-atkins changed the title Use depth dependent stationkeeping at waypoints Use depth dependence and a per-waypoint model for stationkeeping time Oct 19, 2026
@j-atkins
j-atkins changed the base branch from main to expedition-verification October 19, 2026 13:24
instrument: InstrumentType | list[InstrumentType] | None = None
sea_depth_meter: float | None = pydantic.Field(
default=None, le=0.0
) # estimated depth from MFP, if available. If None, instrument deployment times costed against configured max depth, thus over-estimateing rather than under-estimating than under-estimating.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Estimated depths from MFP will follow in #412

) -> _InstrumentConfigMixin | None:
"""The configuration for an instrument type, or None if it is not configured."""
return getattr(self, self._CONFIG_FIELDS[instrument_type])

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neater way of accessing the configuration for a given instrument

@j-atkins
j-atkins marked this pull request as ready for review October 20, 2026 08:11

@erikvansebille erikvansebille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good - a few comments below

```

```{important}
Remember that MFP's default of 45 minutes per station may not be enough once your instruments are selected. Time at a station is made up of slowing the ship down, carrying out the deployments, and getting back up to speed again.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be more explicit about how the total time is made up of these three aspects. I.e. explicitly mention the default 15+15 minutes of time needed for slow-down and speed-up?

Comment thread docs/user-guide/assignments/sail_the_ship.md Outdated
Comment thread src/virtualship/cli/_plan.py Outdated
DEFAULT_TS_CONFIG = {"period_minutes": 5.0}

# ship config timings, edited in minutes in their own (collapsed by default) section
SHIP_TIME_ATTRS = ("deceleration_time", "acceleration_time")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's my physics-brain but when I see deceleration and acceleration, I think in terms of m s-2. Perhaps better to call it 'station_slowdown_time' and 'station_speedup_time'?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes good point, now changed throughout the code for consistency (in e7174b3). Note, I have used "waypoint" instead of "station" throughout, also just to keep it consistent with how we refer to them throughout the code.

Comment thread src/virtualship/cli/_plan.py Outdated

# advanced settings, which most users can leave as the defaults
with Collapsible(
title="Ship deceleration & acceleration times",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also make explicit that this is at stations?

# TODO: docs suggest that add individual instrument stationkeeping times are cumulative, which is at odds with measurements being done simultaneously onboard here
# TODO: update one or the other?
return max(time_costs)
return self._expedition.stationkeeping_time(waypoint)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my information, is this also relevant for ports?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ports do not currently get slow down and speed up times, which is perhaps less realistic because of course a ship must still speed up from departure and slow down to arrival... At the moment this means the code is simpler because the Ports can simply be treated as waypoints with no instruments (and therefore no need to slow down/speed up), which sometimes users may specify so that logic would exist anyway. Do you reckon it's worth adding another rule for the Ports?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I don't think it's worth the extra code complexity. Let's leave then as is for now

Comment thread src/virtualship/instruments/ctd.py
Comment thread src/virtualship/instruments/xbt.py
Comment thread src/virtualship/static/expedition.yaml
Comment thread src/virtualship/utils.py Outdated


def register_instrument(instrument_type):
"""Register a concrete instrument class, refusing if doesn't meet the full Instrument contract."""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These words 'contract' and 'concrete' are quite different lingo than we use elsewhere. Rephrase?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes good point, will change

Base automatically changed from expedition-verification to main October 20, 2026 08:56
@j-atkins

Copy link
Copy Markdown
Collaborator Author

I have now addressed the comments @erikvansebille.

Please note, I have also made a few changes to the docs (quickstart and sail_the_ship guide; in 801b4cf), which go into a bit more detail on the timings associated with each instrument, plus links to the Research_proposal_intro.ipynb doc which has more information on the timings.

@erikvansebille erikvansebille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good - only one comment left. Otherwise good to go!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does drifters now have the same new sentence twice? o is that a rendering mistake in my git diff?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops that's my mistake, good spot thanks!

@j-atkins
j-atkins merged commit dd3cd96 into main Oct 20, 2026
12 checks passed
@j-atkins
j-atkins deleted the depth-dependent-stationkeeping branch October 20, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Realistic time for instrument deployment

2 participants