Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
eab13f3
wip
surgura Aug 19, 2024
1e48185
wip
surgura Aug 21, 2024
86bc46a
wip
surgura Aug 21, 2024
f8eeebe
wip
surgura Aug 22, 2024
37780f1
wip
surgura Aug 22, 2024
e5a5768
clean
surgura Aug 22, 2024
9528cd8
costs
surgura Aug 22, 2024
2232a63
cleanup
surgura Aug 22, 2024
9445382
cleanup
surgura Aug 22, 2024
8896b87
add cli
surgura Aug 23, 2024
7c260e0
all done but _progress_time_traveling_towards
surgura Aug 23, 2024
ce2b7c8
it workss
surgura Aug 23, 2024
3b576b0
codetools
surgura Aug 23, 2024
8c6c2b2
done
surgura Aug 23, 2024
9a7c8d6
cleanup
surgura Aug 23, 2024
0e3da78
add missing test files
surgura Aug 24, 2024
c81e083
recreate results dir
surgura Aug 24, 2024
e81df71
fix checkpoint
surgura Aug 24, 2024
e28b2e1
codetools
surgura Aug 24, 2024
7237a1d
missing newline
surgura Aug 24, 2024
ed25a0b
change download dir name to input_data
surgura Aug 25, 2024
bd78130
add units to config
surgura Aug 25, 2024
9b7afc7
cli tool dont use relative import
surgura Aug 25, 2024
3c30311
sfdgsfdgiu
surgura Aug 26, 2024
5bca508
imrpoved error msg
surgura Aug 26, 2024
af1be5b
fix typo
surgura Aug 26, 2024
78dab99
codetools fixes and made pydantic imports clearer 🌊
surgura Aug 26, 2024
a0bf982
Update virtual_ship/expedition/simulate_measurements.py
surgura Aug 26, 2024
d03916d
Update virtual_ship/expedition/simulate_measurements.py
surgura Aug 26, 2024
0f0eeb7
fixed pydantic errors
surgura Aug 26, 2024
4799bfc
more reliable verify not on land sampling
surgura Aug 26, 2024
29b5b0f
load in fieldsets preemtively and better error mesgs
surgura Aug 26, 2024
473653f
codetools
surgura Aug 26, 2024
b1b31d9
Update virtual_ship/expedition/input_data.py
VeckoTheGecko Sep 25, 2024
00df77a
patch test
VeckoTheGecko Sep 25, 2024
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
4 changes: 4 additions & 0 deletions meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ package:
source:
path: virtual_ship

build:
entry_points:
- do_expedition = virtual_ship.cli.do_expedition:main

requirements:
run:
- python >=3.8
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies = [
"sortedcontainers == 2.4.0",
"opensimplex == 0.4.5",
"numpy >=1, < 2",
"pydantic >=2, <3",
]

[project.urls]
Expand Down Expand Up @@ -61,6 +62,9 @@ dev = [
"sortedcontainers-stubs == 2.4.2",
]

[project.scripts]
do_expedition = "virtual_ship.cli.do_expedition:main"

[tool.isort]
profile = "black"
skip_gitignore = true
Expand Down
136 changes: 136 additions & 0 deletions scripts/download_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
"""
Download data required to run expeditions.

This is a very crude script, here just as long as we do not properly incorporate it into the library.
"""

import copernicusmarine
import datetime

if __name__ == "__main__":
datadir = "input_data"
username = input("username: ")
password = input("password: ")

copernicusmarine.subset(
dataset_id="cmems_mod_glo_phy_my_0.083deg_static",
force_dataset_part="bathy",
variables=["deptho"],
minimum_longitude=-0.01,
maximum_longitude=0.01,
minimum_latitude=-0.01,
maximum_latitude=0.01,
minimum_depth=0.49402499198913574,
maximum_depth=5727.9169921875,
output_filename="bathymetry.nc",
output_directory=datadir,
username=username,
password=password,
force_download=True,
)

download_dict = {
"UVdata": {
"dataset_id": "cmems_mod_glo_phy-cur_anfc_0.083deg_PT6H-i",
"variables": ["uo", "vo"],
"output_filename": "default_uv.nc",
},
"Sdata": {
"dataset_id": "cmems_mod_glo_phy-so_anfc_0.083deg_PT6H-i",
"variables": ["so"],
"output_filename": "default_s.nc",
},
"Tdata": {
"dataset_id": "cmems_mod_glo_phy-thetao_anfc_0.083deg_PT6H-i",
"variables": ["thetao"],
"output_filename": "default_t.nc",
},
}

for dataset in download_dict:
copernicusmarine.subset(
dataset_id=download_dict[dataset]["dataset_id"],
variables=download_dict[dataset]["variables"],
minimum_longitude=-0.01,
maximum_longitude=0.01,
minimum_latitude=-0.01,
maximum_latitude=0.01,
start_datetime=datetime.datetime.strptime("2023-01-01", "%Y-%m-%d"),
end_datetime=datetime.datetime.strptime("2023-01-02", "%Y-%m-%d"),
minimum_depth=0.49402499198913574,
maximum_depth=5727.9169921875,
output_filename=download_dict[dataset]["output_filename"],
output_directory=datadir,
username=username,
password=password,
force_download=True,
)

download_dict = {
"UVdata": {
"dataset_id": "cmems_mod_glo_phy-cur_anfc_0.083deg_PT6H-i",
"variables": ["uo", "vo"],
"output_filename": "drifter_uv.nc",
},
"Tdata": {
"dataset_id": "cmems_mod_glo_phy-thetao_anfc_0.083deg_PT6H-i",
"variables": ["thetao"],
"output_filename": "drifter_t.nc",
},
}

for dataset in download_dict:
copernicusmarine.subset(
dataset_id=download_dict[dataset]["dataset_id"],
variables=download_dict[dataset]["variables"],
minimum_longitude=-0.01,
maximum_longitude=0.01,
minimum_latitude=-0.01,
maximum_latitude=0.01,
start_datetime=datetime.datetime.strptime("2023-01-01", "%Y-%m-%d"),
end_datetime=datetime.datetime.strptime("2023-01-02", "%Y-%m-%d"),
minimum_depth=0.49402499198913574,
maximum_depth=0.49402499198913574,
output_filename=download_dict[dataset]["output_filename"],
output_directory=datadir,
username=username,
password=password,
force_download=True,
)

download_dict = {
"UVdata": {
"dataset_id": "cmems_mod_glo_phy-cur_anfc_0.083deg_PT6H-i",
"variables": ["uo", "vo"],
"output_filename": "argo_float_uv.nc",
},
"Sdata": {
"dataset_id": "cmems_mod_glo_phy-so_anfc_0.083deg_PT6H-i",
"variables": ["so"],
"output_filename": "argo_float_s.nc",
},
"Tdata": {
"dataset_id": "cmems_mod_glo_phy-thetao_anfc_0.083deg_PT6H-i",
"variables": ["thetao"],
"output_filename": "argo_float_t.nc",
},
}

for dataset in download_dict:
copernicusmarine.subset(
dataset_id=download_dict[dataset]["dataset_id"],
variables=download_dict[dataset]["variables"],
minimum_longitude=-0.01,
maximum_longitude=0.01,
minimum_latitude=-0.01,
maximum_latitude=0.01,
start_datetime=datetime.datetime.strptime("2023-01-01", "%Y-%m-%d"),
end_datetime=datetime.datetime.strptime("2023-01-02", "%Y-%m-%d"),
minimum_depth=0.49402499198913574,
maximum_depth=5727.9169921875,
output_filename=download_dict[dataset]["output_filename"],
output_directory=datadir,
username=username,
password=password,
force_download=True,
)
1 change: 1 addition & 0 deletions tests/expedition/expedition_dir/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
results/
9 changes: 9 additions & 0 deletions tests/expedition/expedition_dir/input_data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
!argo_float_s.nc
!argo_float_t.nc
!argo_float_uv.nc
!bathymetry.nc
!default_s.nc
!default_t.nc
!default_uv.nc
!drifter_t.nc
!drifter_uv.nc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16 changes: 16 additions & 0 deletions tests/expedition/expedition_dir/schedule.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
waypoints:
- instrument: CTD
location:
latitude: 0
longitude: 0
time: 2023-01-01 00:00:00
- instrument: DRIFTER
location:
latitude: 0.01
longitude: 0.01
time: 2023-01-01 01:00:00
- instrument: ARGO_FLOAT
location:
latitude: 0.02
longitude: 0.02
time: 2023-01-01 02:00:00
21 changes: 21 additions & 0 deletions tests/expedition/expedition_dir/ship_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
ship_speed_meter_per_second: 5.14
adcp_config:
num_bins: 40
max_depth_meter: -1000.0
period_minutes: 5.0
argo_float_config:
cycle_days: 10.0
drift_days: 9.0
drift_depth_meter: -1000.0
max_depth_meter: -2000.0
min_depth_meter: 0.0
vertical_speed_meter_per_second: -0.1
ctd_config:
max_depth_meter: -2000.0
min_depth_meter: -11.0
stationkeeping_time_minutes: 20.0
drifter_config:
depth_meter: 0.0
lifetime_minutes: 40320.0
ship_underwater_st_config:
period_minutes: 5.0
9 changes: 9 additions & 0 deletions tests/expedition/test_do_expedition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pytest import CaptureFixture

from virtual_ship.expedition import do_expedition


def test_do_expedition(capfd: CaptureFixture) -> None:
do_expedition("expedition_dir")
out, _ = capfd.readouterr()
assert "This expedition took" in out, "Expedition did not complete successfully."
26 changes: 26 additions & 0 deletions tests/expedition/test_schedule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from datetime import datetime, timedelta

import py

from virtual_ship import Location
from virtual_ship.expedition import Schedule, Waypoint


def test_schedule(tmpdir: py.path.LocalPath) -> None:
out_path = tmpdir.join("schedule.yaml")

# arbitrary time for testing
base_time = datetime.strptime("1950-01-01", "%Y-%m-%d")

schedule = Schedule(
waypoints=[
Waypoint(Location(0, 0), time=base_time, instrument=None),
Waypoint(
Location(1, 1), time=base_time + timedelta(hours=1), instrument=None
),
]
)
schedule.to_yaml(out_path)

schedule2 = Schedule.from_yaml(out_path)
assert schedule == schedule2
48 changes: 48 additions & 0 deletions tests/expedition/test_simulate_schedule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from datetime import datetime, timedelta

import pyproj

from virtual_ship import Location
from virtual_ship.expedition import Schedule, ShipConfig, Waypoint
from virtual_ship.expedition.simulate_schedule import (
ScheduleOk,
ScheduleProblem,
simulate_schedule,
)


def test_simulate_schedule_feasible() -> None:
"""Test schedule with two waypoints that can be reached within time is OK."""
base_time = datetime.strptime("2022-01-01T00:00:00", "%Y-%m-%dT%H:%M:%S")

projection = pyproj.Geod(ellps="WGS84")
ship_config = ShipConfig.from_yaml("expedition_dir/ship_config.yaml")
ship_config.ship_speed_meter_per_second = 5.14
schedule = Schedule(
waypoints=[
Waypoint(Location(0, 0), base_time),
Waypoint(Location(0.01, 0), base_time + timedelta(days=1)),
]
)

result = simulate_schedule(projection, ship_config, schedule)

assert isinstance(result, ScheduleOk)


def test_simulate_schedule_too_far() -> None:
"""Test schedule with two waypoints that are very far away and cannot be reached in time is not OK."""
base_time = datetime.strptime("2022-01-01T00:00:00", "%Y-%m-%dT%H:%M:%S")

projection = pyproj.Geod(ellps="WGS84")
ship_config = ShipConfig.from_yaml("expedition_dir/ship_config.yaml")
schedule = Schedule(
waypoints=[
Waypoint(Location(0, 0), base_time),
Waypoint(Location(1.0, 0), base_time + timedelta(minutes=1)),
]
)

result = simulate_schedule(projection, ship_config, schedule)

assert isinstance(result, ScheduleProblem)
22 changes: 11 additions & 11 deletions tests/instruments/test_ship_underwater_st.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ def test_simulate_ship_underwater_st(tmpdir: py.path.LocalPath) -> None:
# expected observations at sample points
expected_obs = [
{
"salinity": 5,
"temperature": 6,
"S": 5,
"T": 6,
"lat": sample_points[0].location.lat,
"lon": sample_points[0].location.lon,
"time": base_time + datetime.timedelta(seconds=0),
},
{
"salinity": 7,
"temperature": 8,
"S": 7,
"T": 8,
"lat": sample_points[1].location.lat,
"lon": sample_points[1].location.lon,
"time": base_time + datetime.timedelta(seconds=1),
Expand All @@ -45,19 +45,19 @@ def test_simulate_ship_underwater_st(tmpdir: py.path.LocalPath) -> None:
# create fieldset based on the expected observations
# indices are time, latitude, longitude
salinity = np.zeros((2, 2, 2))
salinity[0, 0, 0] = expected_obs[0]["salinity"]
salinity[1, 1, 1] = expected_obs[1]["salinity"]
salinity[0, 0, 0] = expected_obs[0]["S"]
salinity[1, 1, 1] = expected_obs[1]["S"]

temperature = np.zeros((2, 2, 2))
temperature[0, 0, 0] = expected_obs[0]["temperature"]
temperature[1, 1, 1] = expected_obs[1]["temperature"]
temperature[0, 0, 0] = expected_obs[0]["T"]
temperature[1, 1, 1] = expected_obs[1]["T"]

fieldset = FieldSet.from_data(
{
"V": np.zeros((2, 2, 2)),
"U": np.zeros((2, 2, 2)),
"salinity": salinity,
"temperature": temperature,
"S": salinity,
"T": temperature,
},
{
"lat": np.array([expected_obs[0]["lat"], expected_obs[1]["lat"]]),
Expand Down Expand Up @@ -95,7 +95,7 @@ def test_simulate_ship_underwater_st(tmpdir: py.path.LocalPath) -> None:
zip(results.sel(trajectory=traj).obs, expected_obs, strict=True)
):
obs = results.sel(trajectory=traj, obs=obs_i)
for var in ["salinity", "temperature", "lat", "lon"]:
for var in ["S", "T", "lat", "lon"]:
obs_value = obs[var].values.item()
exp_value = exp[var]
assert np.isclose(
Expand Down
Loading