Skip to content

Commit 10e68b3

Browse files
committed
add buffers to drifters and argos, plus depth limits for drifters
1 parent 05686f2 commit 10e68b3

File tree

10 files changed

+68
-67
lines changed

10 files changed

+68
-67
lines changed

src/virtualship/instruments/adcp.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def __init__(self, expedition, directory):
6161
"V": f"{ADCP.name}_uv.nc",
6262
}
6363
variables = {"U": "uo", "V": "vo"}
64+
6465
super().__init__(
6566
ADCP.name,
6667
expedition,
@@ -70,6 +71,8 @@ def __init__(self, expedition, directory):
7071
add_bathymetry=False,
7172
allow_time_extrapolation=True,
7273
verbose_progress=False,
74+
buffer_spec=None,
75+
limit_spec=None,
7376
)
7477

7578
def simulate(self, measurements, out_path) -> None:

src/virtualship/instruments/argo_float.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ def __init__(self, expedition, directory):
146146
"T": f"{ArgoFloat.name}_t.nc",
147147
}
148148
variables = {"U": "uo", "V": "vo", "S": "so", "T": "thetao"}
149+
buffer_spec = {
150+
"latlon": 6.0, # [degrees]
151+
"time": 21.0, # [days]
152+
}
153+
149154
super().__init__(
150155
ArgoFloat.name,
151156
expedition,
@@ -155,6 +160,8 @@ def __init__(self, expedition, directory):
155160
add_bathymetry=False,
156161
allow_time_extrapolation=False,
157162
verbose_progress=True,
163+
buffer_spec=buffer_spec,
164+
limit_spec=None,
158165
)
159166

160167
def simulate(self, measurements, out_path) -> None:

src/virtualship/instruments/base.py

Lines changed: 28 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ class Instrument(abc.ABC):
2525
"""Base class for instruments and their simulation."""
2626

2727
#! TODO List:
28-
# TODO: update documentation/quickstart
29-
# TODO: update tests
30-
#! TODO: how is this handling credentials?! Seems to work already, are these set up from my previous instances of using copernicusmarine? Therefore users will only have to do it once too?
28+
# TODO: how is this handling credentials?! Seems to work already, are these set up from my previous instances of using copernicusmarine? Therefore users will only have to do it once too?
3129

3230
def __init__(
3331
self,
@@ -39,7 +37,8 @@ def __init__(
3937
add_bathymetry: bool,
4038
allow_time_extrapolation: bool,
4139
verbose_progress: bool,
42-
bathymetry_file: str = "bathymetry.nc",
40+
buffer_spec: dict | None = None,
41+
limit_spec: dict | None = None,
4342
):
4443
"""Initialise instrument."""
4544
self.name = name
@@ -53,31 +52,23 @@ def __init__(
5352
"time": "time",
5453
"depth": "depth",
5554
} # same dimensions for all instruments
56-
self.bathymetry_file = bathymetry_file
5755
self.add_bathymetry = add_bathymetry
5856
self.allow_time_extrapolation = allow_time_extrapolation
5957
self.verbose_progress = verbose_progress
58+
self.buffer_spec = buffer_spec
59+
self.limit_spec = limit_spec
6060

6161
def load_input_data(self) -> FieldSet:
6262
"""Load and return the input data as a FieldSet for the instrument."""
6363
try:
6464
datasets = []
6565
for var in self.variables.values():
6666
physical = True if var in COPERNICUSMARINE_PHYS_VARIABLES else False
67-
68-
# TODO: TEMPORARY BODGE FOR DRIFTER INSTRUMENT - REMOVE WHEN ABLE TO!
69-
if self.name == "Drifter":
70-
ds = self._get_copernicus_ds_DRIFTER(physical=physical, var=var)
71-
else:
72-
ds = self._get_copernicus_ds(physical=physical, var=var)
73-
datasets.append(ds)
67+
datasets.append(self._get_copernicus_ds(physical=physical, var=var))
7468

7569
# make sure time dims are matched if BGC variables are present (different monthly/daily resolutions can impact fieldset_endtime in simulate)
76-
if any(
77-
key in COPERNICUSMARINE_BGC_VARIABLES
78-
for key in ds.keys()
79-
for ds in datasets
80-
):
70+
all_keys = set().union(*(ds.keys() for ds in datasets))
71+
if all_keys & set(COPERNICUSMARINE_BGC_VARIABLES):
8172
datasets = self._align_temporal(datasets)
8273

8374
ds_concat = xr.merge(datasets) # TODO: deal with WARNINGS?
@@ -100,11 +91,15 @@ def load_input_data(self) -> FieldSet:
10091
g.negate_depth()
10192

10293
# bathymetry data
103-
bathymetry_field = _get_bathy_data(
104-
self.expedition.schedule.space_time_region
105-
).bathymetry
106-
bathymetry_field.data = -bathymetry_field.data
107-
fieldset.add_field(bathymetry_field)
94+
if self.add_bathymetry:
95+
bathymetry_field = _get_bathy_data(
96+
self.expedition.schedule.space_time_region,
97+
latlon_buffer=self.buffer_spec.get("latlon")
98+
if self.buffer_spec
99+
else None,
100+
).bathymetry
101+
bathymetry_field.data = -bathymetry_field.data
102+
fieldset.add_field(bathymetry_field)
108103

109104
return fieldset
110105

@@ -127,8 +122,6 @@ def execute(self, measurements: list, out_path: str | Path) -> None:
127122
self.simulate(measurements, out_path)
128123
print("\n")
129124

130-
# self.simulate(measurements, out_path)
131-
132125
def _get_copernicus_ds(
133126
self,
134127
physical: bool,
@@ -142,50 +135,28 @@ def _get_copernicus_ds(
142135
variable=var if not physical else None,
143136
)
144137

145-
return copernicusmarine.open_dataset(
146-
dataset_id=product_id,
147-
dataset_part="default",
148-
minimum_longitude=self.expedition.schedule.space_time_region.spatial_range.minimum_longitude,
149-
maximum_longitude=self.expedition.schedule.space_time_region.spatial_range.maximum_longitude,
150-
minimum_latitude=self.expedition.schedule.space_time_region.spatial_range.minimum_latitude,
151-
maximum_latitude=self.expedition.schedule.space_time_region.spatial_range.maximum_latitude,
152-
variables=[var],
153-
start_datetime=self.expedition.schedule.space_time_region.time_range.start_time,
154-
end_datetime=self.expedition.schedule.space_time_region.time_range.end_time,
155-
coordinates_selection_method="outside",
156-
)
138+
latlon_buffer = self.buffer_spec.get("latlon") if self.buffer_spec else 0.0
139+
time_buffer = self.buffer_spec.get("time") if self.buffer_spec else 0.0
157140

158-
# TODO: TEMPORARY BODGE FOR DRIFTER INSTRUMENT - REMOVE WHEN ABLE TO!
159-
def _get_copernicus_ds_DRIFTER(
160-
self,
161-
physical: bool,
162-
var: str,
163-
) -> xr.Dataset:
164-
"""Get Copernicus Marine dataset for direct ingestion."""
165-
product_id = _select_product_id(
166-
physical=physical,
167-
schedule_start=self.expedition.schedule.space_time_region.time_range.start_time,
168-
schedule_end=self.expedition.schedule.space_time_region.time_range.end_time,
169-
variable=var if not physical else None,
170-
)
141+
depth_min = self.limit_spec.get("depth_min") if self.limit_spec else None
142+
depth_max = self.limit_spec.get("depth_max") if self.limit_spec else None
171143

172144
return copernicusmarine.open_dataset(
173145
dataset_id=product_id,
174-
dataset_part="default",
175146
minimum_longitude=self.expedition.schedule.space_time_region.spatial_range.minimum_longitude
176-
- 3.0,
147+
- latlon_buffer,
177148
maximum_longitude=self.expedition.schedule.space_time_region.spatial_range.maximum_longitude
178-
+ 3.0,
149+
+ latlon_buffer,
179150
minimum_latitude=self.expedition.schedule.space_time_region.spatial_range.minimum_latitude
180-
- 3.0,
151+
- latlon_buffer,
181152
maximum_latitude=self.expedition.schedule.space_time_region.spatial_range.maximum_latitude
182-
+ 3.0,
183-
maximum_depth=1.0,
184-
minimum_depth=1.0,
153+
+ latlon_buffer,
185154
variables=[var],
186155
start_datetime=self.expedition.schedule.space_time_region.time_range.start_time,
187156
end_datetime=self.expedition.schedule.space_time_region.time_range.end_time
188-
+ timedelta(days=21.0),
157+
+ timedelta(days=time_buffer),
158+
minimum_depth=depth_min,
159+
maximum_depth=depth_max,
189160
coordinates_selection_method="outside",
190161
)
191162

src/virtualship/instruments/ctd.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ def __init__(self, expedition, directory):
9696
add_bathymetry=True,
9797
allow_time_extrapolation=True,
9898
verbose_progress=False,
99+
buffer_spec=None,
100+
limit_spec=None,
99101
)
100102

101103
def simulate(self, measurements, out_path) -> None:

src/virtualship/instruments/ctd_bgc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ def __init__(self, expedition, directory):
130130
add_bathymetry=True,
131131
allow_time_extrapolation=True,
132132
verbose_progress=False,
133+
buffer_spec=None,
134+
limit_spec=None,
133135
)
134136

135137
def simulate(self, measurements, out_path) -> None:

src/virtualship/instruments/drifter.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ def __init__(self, expedition, directory):
7171
"T": f"{Drifter.name}_t.nc",
7272
}
7373
variables = {"U": "uo", "V": "vo", "T": "thetao"}
74+
buffer_spec = {
75+
"latlon": 6.0, # [degrees]
76+
"time": 21.0, # [days]
77+
}
78+
limit_spec = {
79+
"depth_min": 1.0, # [meters]
80+
"depth_max": 1.0, # [meters]
81+
}
82+
7483
super().__init__(
7584
Drifter.name,
7685
expedition,
@@ -80,6 +89,8 @@ def __init__(self, expedition, directory):
8089
add_bathymetry=False,
8190
allow_time_extrapolation=False,
8291
verbose_progress=True,
92+
buffer_spec=buffer_spec,
93+
limit_spec=limit_spec,
8394
)
8495

8596
def simulate(self, measurements, out_path) -> None:
@@ -121,7 +132,7 @@ def simulate(self, measurements, out_path) -> None:
121132
chunks=[len(drifter_particleset), 100],
122133
)
123134

124-
# get earliest between fieldset end time and provide end time
135+
# get earliest between fieldset end time and prescribed end time
125136
fieldset_endtime = fieldset.time_origin.fulltime(fieldset.U.grid.time_full[-1])
126137
if ENDTIME is None:
127138
actual_endtime = fieldset_endtime

src/virtualship/instruments/ship_underwater_st.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def __init__(self, expedition, directory):
7272
add_bathymetry=False,
7373
allow_time_extrapolation=True,
7474
verbose_progress=False,
75+
buffer_spec=None,
76+
limit_spec=None,
7577
)
7678

7779
def simulate(self, measurements, out_path) -> None:

src/virtualship/instruments/xbt.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ def __init__(self, expedition, directory):
9595
add_bathymetry=True,
9696
allow_time_extrapolation=True,
9797
verbose_progress=False,
98+
buffer_spec=None,
99+
limit_spec=None,
98100
)
99101

100102
def simulate(self, measurements, out_path) -> None:

src/virtualship/models/expedition.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def verify(
132132
if not ignore_missing_bathymetry:
133133
try:
134134
bathymetry_field = _get_bathy_data(
135-
self.space_time_region
135+
self.space_time_region, latlon_buffer=None
136136
).bathymetry # via copernicusmarine
137137
except Exception as e:
138138
raise ScheduleError(
@@ -406,9 +406,6 @@ def verify(self, expedition: Expedition) -> None:
406406
hasattr(self, config_attr)
407407
and inst_type not in instruments_in_expedition
408408
):
409-
print(
410-
f"{inst_type.value} configuration provided but not in schedule. Removing config."
411-
)
412409
setattr(self, config_attr, None)
413410
# Check all scheduled instruments are configured
414411
for inst_type in instruments_in_expedition:

src/virtualship/utils.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,14 +412,18 @@ def _start_end_in_product_timerange(
412412
)
413413

414414

415-
def _get_bathy_data(space_time_region) -> FieldSet:
415+
def _get_bathy_data(space_time_region, latlon_buffer: float | None = None) -> FieldSet:
416416
"""Bathymetry data 'streamed' directly from Copernicus Marine."""
417417
ds_bathymetry = copernicusmarine.open_dataset(
418418
dataset_id="cmems_mod_glo_phy_my_0.083deg_static",
419-
minimum_longitude=space_time_region.spatial_range.minimum_longitude,
420-
maximum_longitude=space_time_region.spatial_range.maximum_longitude,
421-
minimum_latitude=space_time_region.spatial_range.minimum_latitude,
422-
maximum_latitude=space_time_region.spatial_range.maximum_latitude,
419+
minimum_longitude=space_time_region.spatial_range.minimum_longitude
420+
- (latlon_buffer if latlon_buffer is not None else 0),
421+
maximum_longitude=space_time_region.spatial_range.maximum_longitude
422+
+ (latlon_buffer if latlon_buffer is not None else 0),
423+
minimum_latitude=space_time_region.spatial_range.minimum_latitude
424+
- (latlon_buffer if latlon_buffer is not None else 0),
425+
maximum_latitude=space_time_region.spatial_range.maximum_latitude
426+
+ (latlon_buffer if latlon_buffer is not None else 0),
423427
variables=["deptho"],
424428
start_datetime=space_time_region.time_range.start_time,
425429
end_datetime=space_time_region.time_range.end_time,

0 commit comments

Comments
 (0)