Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions src/virtualship/cli/_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def _fetch(path: str | Path, username: str | None, password: str | None) -> None

if (
(
{"XBT", "CTD", "SHIP_UNDERWATER_ST"}
{"XBT", "CTD", "CDT_BGC", "SHIP_UNDERWATER_ST"}
& set(instrument.name for instrument in instruments_in_schedule)
)
or ship_config.ship_underwater_st_config is not None
Expand Down Expand Up @@ -144,7 +144,6 @@ def _fetch(path: str | Path, username: str | None, password: str | None) -> None
shutil.rmtree(download_folder)
raise e

complete_download(download_folder)
click.echo("Ship data download based on space-time region completed.")

if InstrumentType.DRIFTER in instruments_in_schedule:
Expand Down Expand Up @@ -187,7 +186,6 @@ def _fetch(path: str | Path, username: str | None, password: str | None) -> None
shutil.rmtree(download_folder)
raise e

complete_download(download_folder)
click.echo("Drifter data download based on space-time region completed.")

if InstrumentType.ARGO_FLOAT in instruments_in_schedule:
Expand Down Expand Up @@ -235,9 +233,53 @@ def _fetch(path: str | Path, username: str | None, password: str | None) -> None
shutil.rmtree(download_folder)
raise e

complete_download(download_folder)
click.echo("Argo_float data download based on space-time region completed.")

if InstrumentType.CTD_BGC in instruments_in_schedule:
print("CTD_BGC data will be downloaded. Please wait...")

ctd_bgc_download_dict = {
"o2data": {
"dataset_id": "cmems_mod_glo_bgc-bio_anfc_0.25deg_P1D-m",
"variables": ["o2"],
"output_filename": "ctd_bgc_o2.nc",
},
"chlorodata": {
"dataset_id": "cmems_mod_glo_bgc-pft_anfc_0.25deg_P1D-m",
"variables": ["chl"],
"output_filename": "ctd_bgc_chloro.nc",
},
}

# Iterate over all datasets and download each based on space_time_region
try:
for dataset in ctd_bgc_download_dict.values():
copernicusmarine.subset(
dataset_id=dataset["dataset_id"],
variables=dataset["variables"],
minimum_longitude=spatial_range.minimum_longitude - 3.0,
maximum_longitude=spatial_range.maximum_longitude + 3.0,
minimum_latitude=spatial_range.minimum_latitude - 3.0,
maximum_latitude=spatial_range.maximum_latitude + 3.0,
start_datetime=start_datetime,
end_datetime=end_datetime + timedelta(days=21),
minimum_depth=abs(1),
maximum_depth=abs(spatial_range.maximum_depth),
output_filename=dataset["output_filename"],
output_directory=download_folder,
username=username,
password=password,
overwrite=True,
coordinates_selection_method="outside",
)
except InvalidUsernameOrPassword as e:
shutil.rmtree(download_folder)
raise e

click.echo("CTD_BGC data download based on space-time region completed.")

complete_download(download_folder)


def _hash(s: str, *, length: int) -> str:
"""Create a hash of a string."""
Expand Down
40 changes: 39 additions & 1 deletion src/virtualship/expedition/ship_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@


class InstrumentType(Enum):
"""Types of instruments."""
"""Types of the instruments."""

CTD = "CTD"
CTD_BGC = "CTD_BGC"
DRIFTER = "DRIFTER"
ARGO_FLOAT = "ARGO_FLOAT"
XBT = "XBT"
Expand Down Expand Up @@ -80,6 +81,28 @@ def _validate_stationkeeping_time(cls, value: int | float | timedelta) -> timede
return _validate_numeric_mins_to_timedelta(value)


class CTD_BGCConfig(pydantic.BaseModel):
"""Configuration for CTD_BGC instrument."""

stationkeeping_time: timedelta = pydantic.Field(
serialization_alias="stationkeeping_time_minutes",
validation_alias="stationkeeping_time_minutes",
gt=timedelta(),
)
min_depth_meter: float = pydantic.Field(le=0.0)
max_depth_meter: float = pydantic.Field(le=0.0)

model_config = pydantic.ConfigDict(populate_by_name=True)

@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")
def _validate_stationkeeping_time(cls, value: int | float | timedelta) -> timedelta:
return _validate_numeric_mins_to_timedelta(value)


class ShipUnderwaterSTConfig(pydantic.BaseModel):
"""Configuration for underwater ST."""

Expand Down Expand Up @@ -159,6 +182,13 @@ class ShipConfig(pydantic.BaseModel):
If None, no CTDs can be cast.
"""

ctd_bgc_config: CTD_BGCConfig | None = None
"""
CTD_BGC configuration.

If None, no BGC CTDs can be cast.
"""

ship_underwater_st_config: ShipUnderwaterSTConfig | None = None
"""
Ship underwater salinity temperature measurementconfiguration.
Expand Down Expand Up @@ -239,6 +269,7 @@ def verify(self, schedule: Schedule) -> None:
"DRIFTER",
"XBT",
"CTD",
"CTD_BGC",
]: # TODO make instrument names consistent capitals or lowercase throughout codebase
if hasattr(self, instrument.lower() + "_config") and not any(
instrument == schedule_instrument.name
Expand All @@ -248,6 +279,7 @@ def verify(self, schedule: Schedule) -> None:
setattr(self, instrument.lower() + "_config", None)

# verify instruments in schedule have configuration
# TODO: the ConfigError message could be improved to explain that the **schedule** file has X instrument but the **ship_config** file does not
for instrument in instruments_in_schedule:
try:
InstrumentType(instrument)
Expand All @@ -266,6 +298,12 @@ def verify(self, schedule: Schedule) -> None:
raise ConfigError(
"Planning has a waypoint with CTD instrument, but configuration does not configure CTDs."
)
if instrument == InstrumentType.CTD_BGC and (
not hasattr(self, "ctd_bgc_config") or self.ctd_bgc_config is None
):
raise ConfigError(
"Planning has a waypoint with CTD_BGC instrument, but configuration does not configure CTD_BGCs."
)
if instrument == InstrumentType.DRIFTER and (
not hasattr(self, "drifter_config") or self.drifter_config is None
):
Expand Down
4 changes: 4 additions & 0 deletions src/virtualship/static/ship_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ ctd_config:
max_depth_meter: -2000.0
min_depth_meter: -11.0
stationkeeping_time_minutes: 20.0
ctd_bgc_config:
max_depth_meter: -2000.0
min_depth_meter: -11.0
stationkeeping_time_minutes: 20.0
drifter_config:
depth_meter: 0.0
lifetime_minutes: 60480.0
Expand Down
1 change: 1 addition & 0 deletions src/virtualship/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def mfp_to_yaml(coordinates_file_path: str, yaml_output_path: str): # noqa: D41
instrument_max_depths = {
"XBT": 2000,
"CTD": 5000,
"CTD_BGC": 5000,
"DRIFTER": 1,
"ARGO_FLOAT": 2000,
}
Expand Down