diff --git a/src/virtualship/cli/_fetch.py b/src/virtualship/cli/_fetch.py index df66cd66..ac039d76 100644 --- a/src/virtualship/cli/_fetch.py +++ b/src/virtualship/cli/_fetch.py @@ -248,7 +248,37 @@ def _fetch(path: str | Path, username: str | None, password: str | None) -> None "chlorodata": { "dataset_id": "cmems_mod_glo_bgc-pft_anfc_0.25deg_P1D-m", "variables": ["chl"], - "output_filename": "ctd_bgc_chloro.nc", + "output_filename": "ctd_bgc_chl.nc", + }, + "nitratedata": { + "dataset_id": "cmems_mod_glo_bgc-nut_anfc_0.25deg_P1D-m", + "variables": ["no3"], + "output_filename": "ctd_bgc_no3.nc", + }, + "phosphatedata": { + "dataset_id": "cmems_mod_glo_bgc-nut_anfc_0.25deg_P1D-m", + "variables": ["po4"], + "output_filename": "ctd_bgc_po4.nc", + }, + "phdata": { + "dataset_id": "cmems_mod_glo_bgc-car_anfc_0.25deg_P1D-m", + "variables": ["ph"], + "output_filename": "ctd_bgc_ph.nc", + }, + "phytoplanktondata": { + "dataset_id": "cmems_mod_glo_bgc-pft_anfc_0.25deg_P1D-m", + "variables": ["phyc"], + "output_filename": "ctd_bgc_phyc.nc", + }, + "zooplanktondata": { + "dataset_id": "cmems_mod_glo_bgc-plankton_anfc_0.25deg_P1D-m", + "variables": ["zooc"], + "output_filename": "ctd_bgc_zooc.nc", + }, + "primaryproductiondata": { + "dataset_id": "cmems_mod_glo_bgc-bio_anfc_0.25deg_P1D-m", + "variables": ["nppv"], + "output_filename": "ctd_bgc_nppv.nc", }, } diff --git a/src/virtualship/expedition/input_data.py b/src/virtualship/expedition/input_data.py index 0cf34d28..921daeda 100644 --- a/src/virtualship/expedition/input_data.py +++ b/src/virtualship/expedition/input_data.py @@ -137,9 +137,26 @@ def _load_ctd_bgc_fieldset(cls, directory: Path) -> FieldSet: "U": directory.joinpath("ship_uv.nc"), "V": directory.joinpath("ship_uv.nc"), "o2": directory.joinpath("ctd_bgc_o2.nc"), - "chl": directory.joinpath("ctd_bgc_chloro.nc"), + "chl": directory.joinpath("ctd_bgc_chl.nc"), + "no3": directory.joinpath("ctd_bgc_no3.nc"), + "po4": directory.joinpath("ctd_bgc_po4.nc"), + "ph": directory.joinpath("ctd_bgc_ph.nc"), + "phyc": directory.joinpath("ctd_bgc_phyc.nc"), + "zooc": directory.joinpath("ctd_bgc_zooc.nc"), + "nppv": directory.joinpath("ctd_bgc_nppv.nc"), + } + variables = { + "U": "uo", + "V": "vo", + "o2": "o2", + "chl": "chl", + "no3": "no3", + "po4": "po4", + "ph": "ph", + "phyc": "phyc", + "zooc": "zooc", + "nppv": "nppv", } - variables = {"U": "uo", "V": "vo", "o2": "o2", "chl": "chl"} dimensions = { "lon": "longitude", "lat": "latitude", @@ -152,6 +169,12 @@ def _load_ctd_bgc_fieldset(cls, directory: Path) -> FieldSet: ) fieldset.o2.interp_method = "linear_invdist_land_tracer" fieldset.chl.interp_method = "linear_invdist_land_tracer" + fieldset.no3.interp_method = "linear_invdist_land_tracer" + fieldset.po4.interp_method = "linear_invdist_land_tracer" + fieldset.ph.interp_method = "linear_invdist_land_tracer" + fieldset.phyc.interp_method = "linear_invdist_land_tracer" + fieldset.zooc.interp_method = "linear_invdist_land_tracer" + fieldset.nppv.interp_method = "linear_invdist_land_tracer" # make depth negative for g in fieldset.gridset.grids: diff --git a/src/virtualship/instruments/ctd_bgc.py b/src/virtualship/instruments/ctd_bgc.py index acd4df61..fde92ca1 100644 --- a/src/virtualship/instruments/ctd_bgc.py +++ b/src/virtualship/instruments/ctd_bgc.py @@ -23,6 +23,12 @@ class CTD_BGC: [ Variable("o2", dtype=np.float32, initial=np.nan), Variable("chl", dtype=np.float32, initial=np.nan), + Variable("no3", dtype=np.float32, initial=np.nan), + Variable("po4", dtype=np.float32, initial=np.nan), + Variable("ph", dtype=np.float32, initial=np.nan), + Variable("phyc", dtype=np.float32, initial=np.nan), + Variable("zooc", dtype=np.float32, initial=np.nan), + Variable("nppv", dtype=np.float32, initial=np.nan), Variable("raising", dtype=np.int8, initial=0.0), # bool. 0 is False, 1 is True. Variable("max_depth", dtype=np.float32), Variable("min_depth", dtype=np.float32), @@ -39,6 +45,30 @@ def _sample_chlorophyll(particle, fieldset, time): particle.chl = fieldset.chl[time, particle.depth, particle.lat, particle.lon] +def _sample_nitrate(particle, fieldset, time): + particle.no3 = fieldset.no3[time, particle.depth, particle.lat, particle.lon] + + +def _sample_phosphate(particle, fieldset, time): + particle.po4 = fieldset.po4[time, particle.depth, particle.lat, particle.lon] + + +def _sample_ph(particle, fieldset, time): + particle.ph = fieldset.ph[time, particle.depth, particle.lat, particle.lon] + + +def _sample_phytoplankton(particle, fieldset, time): + particle.phyc = fieldset.phyc[time, particle.depth, particle.lat, particle.lon] + + +def _sample_zooplankton(particle, fieldset, time): + particle.zooc = fieldset.zooc[time, particle.depth, particle.lat, particle.lon] + + +def _sample_primary_production(particle, fieldset, time): + particle.nppv = fieldset.nppv[time, particle.depth, particle.lat, particle.lon] + + def _ctd_bgc_cast(particle, fieldset, time): # lowering if particle.raising == 0: @@ -129,7 +159,17 @@ def simulate_ctd_bgc( # execute simulation ctd_bgc_particleset.execute( - [_sample_o2, _sample_chlorophyll, _ctd_bgc_cast], + [ + _sample_o2, + _sample_chlorophyll, + _sample_nitrate, + _sample_phosphate, + _sample_ph, + _sample_phytoplankton, + _sample_zooplankton, + _sample_primary_production, + _ctd_bgc_cast, + ], endtime=fieldset_endtime, dt=DT, verbose_progress=False, diff --git a/tests/expedition/expedition_dir/input_data/.gitignore b/tests/expedition/expedition_dir/input_data/.gitignore index 2235154f..b323da5b 100644 --- a/tests/expedition/expedition_dir/input_data/.gitignore +++ b/tests/expedition/expedition_dir/input_data/.gitignore @@ -7,3 +7,4 @@ !ship_uv.nc !drifter_t.nc !drifter_uv.nc +!ctd_bgc_*.nc diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_chloro.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_chl.nc similarity index 56% rename from tests/expedition/expedition_dir/input_data/ctd_bgc_chloro.nc rename to tests/expedition/expedition_dir/input_data/ctd_bgc_chl.nc index efdc51d3..16bc9d58 100644 Binary files a/tests/expedition/expedition_dir/input_data/ctd_bgc_chloro.nc and b/tests/expedition/expedition_dir/input_data/ctd_bgc_chl.nc differ diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_no3.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_no3.nc new file mode 100644 index 00000000..58be88bf Binary files /dev/null and b/tests/expedition/expedition_dir/input_data/ctd_bgc_no3.nc differ diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_nppv.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_nppv.nc new file mode 100644 index 00000000..87eb77c5 Binary files /dev/null and b/tests/expedition/expedition_dir/input_data/ctd_bgc_nppv.nc differ diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_o2.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_o2.nc index d552f8bb..2a889d2e 100644 Binary files a/tests/expedition/expedition_dir/input_data/ctd_bgc_o2.nc and b/tests/expedition/expedition_dir/input_data/ctd_bgc_o2.nc differ diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_ph.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_ph.nc new file mode 100644 index 00000000..06711dfd Binary files /dev/null and b/tests/expedition/expedition_dir/input_data/ctd_bgc_ph.nc differ diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_phyc.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_phyc.nc new file mode 100644 index 00000000..a3cdad36 Binary files /dev/null and b/tests/expedition/expedition_dir/input_data/ctd_bgc_phyc.nc differ diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_po4.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_po4.nc new file mode 100644 index 00000000..e1e1336a Binary files /dev/null and b/tests/expedition/expedition_dir/input_data/ctd_bgc_po4.nc differ diff --git a/tests/expedition/expedition_dir/input_data/ctd_bgc_zooc.nc b/tests/expedition/expedition_dir/input_data/ctd_bgc_zooc.nc new file mode 100644 index 00000000..93a9468e Binary files /dev/null and b/tests/expedition/expedition_dir/input_data/ctd_bgc_zooc.nc differ diff --git a/tests/instruments/test_ctd_bgc.py b/tests/instruments/test_ctd_bgc.py index f26e34b1..5347a2ce 100644 --- a/tests/instruments/test_ctd_bgc.py +++ b/tests/instruments/test_ctd_bgc.py @@ -45,12 +45,24 @@ def test_simulate_ctd_bgcs(tmpdir) -> None: "surface": { "o2": 9, "chl": 10, + "no3": 13, + "po4": 14, + "ph": 8.1, + "phyc": 15, + "zooc": 16, + "nppv": 17, "lat": ctd_bgcs[0].spacetime.location.lat, "lon": ctd_bgcs[0].spacetime.location.lon, }, "maxdepth": { "o2": 11, "chl": 12, + "no3": 18, + "po4": 19, + "ph": 8.0, + "phyc": 20, + "zooc": 21, + "nppv": 22, "lat": ctd_bgcs[0].spacetime.location.lat, "lon": ctd_bgcs[0].spacetime.location.lon, }, @@ -59,12 +71,24 @@ def test_simulate_ctd_bgcs(tmpdir) -> None: "surface": { "o2": 9, "chl": 10, + "no3": 13, + "po4": 14, + "ph": 8.1, + "phyc": 15, + "zooc": 16, + "nppv": 17, "lat": ctd_bgcs[1].spacetime.location.lat, "lon": ctd_bgcs[1].spacetime.location.lon, }, "maxdepth": { "o2": 11, "chl": 12, + "no3": 18, + "po4": 19, + "ph": 8.0, + "phyc": 20, + "zooc": 21, + "nppv": 22, "lat": ctd_bgcs[1].spacetime.location.lat, "lon": ctd_bgcs[1].spacetime.location.lon, }, @@ -75,9 +99,16 @@ def test_simulate_ctd_bgcs(tmpdir) -> None: # indices are time, depth, latitude, longitude u = np.zeros((2, 2, 2, 2)) v = np.zeros((2, 2, 2, 2)) - o2 = np.zeros((2, 2, 2, 2)) # o2 field - chl = np.zeros((2, 2, 2, 2)) # chl field - + o2 = np.zeros((2, 2, 2, 2)) + chl = np.zeros((2, 2, 2, 2)) + no3 = np.zeros((2, 2, 2, 2)) + po4 = np.zeros((2, 2, 2, 2)) + ph = np.zeros((2, 2, 2, 2)) + phyc = np.zeros((2, 2, 2, 2)) + zooc = np.zeros((2, 2, 2, 2)) + nppv = np.zeros((2, 2, 2, 2)) + + # Fill fields for both CTDs at surface and maxdepth o2[:, 1, 0, 1] = ctd_bgc_exp[0]["surface"]["o2"] o2[:, 0, 0, 1] = ctd_bgc_exp[0]["maxdepth"]["o2"] o2[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["o2"] @@ -88,8 +119,49 @@ def test_simulate_ctd_bgcs(tmpdir) -> None: chl[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["chl"] chl[:, 0, 1, 0] = ctd_bgc_exp[1]["maxdepth"]["chl"] + no3[:, 1, 0, 1] = ctd_bgc_exp[0]["surface"]["no3"] + no3[:, 0, 0, 1] = ctd_bgc_exp[0]["maxdepth"]["no3"] + no3[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["no3"] + no3[:, 0, 1, 0] = ctd_bgc_exp[1]["maxdepth"]["no3"] + + po4[:, 1, 0, 1] = ctd_bgc_exp[0]["surface"]["po4"] + po4[:, 0, 0, 1] = ctd_bgc_exp[0]["maxdepth"]["po4"] + po4[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["po4"] + po4[:, 0, 1, 0] = ctd_bgc_exp[1]["maxdepth"]["po4"] + + ph[:, 1, 0, 1] = ctd_bgc_exp[0]["surface"]["ph"] + ph[:, 0, 0, 1] = ctd_bgc_exp[0]["maxdepth"]["ph"] + ph[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["ph"] + ph[:, 0, 1, 0] = ctd_bgc_exp[1]["maxdepth"]["ph"] + + phyc[:, 1, 0, 1] = ctd_bgc_exp[0]["surface"]["phyc"] + phyc[:, 0, 0, 1] = ctd_bgc_exp[0]["maxdepth"]["phyc"] + phyc[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["phyc"] + phyc[:, 0, 1, 0] = ctd_bgc_exp[1]["maxdepth"]["phyc"] + + zooc[:, 1, 0, 1] = ctd_bgc_exp[0]["surface"]["zooc"] + zooc[:, 0, 0, 1] = ctd_bgc_exp[0]["maxdepth"]["zooc"] + zooc[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["zooc"] + zooc[:, 0, 1, 0] = ctd_bgc_exp[1]["maxdepth"]["zooc"] + + nppv[:, 1, 0, 1] = ctd_bgc_exp[0]["surface"]["nppv"] + nppv[:, 0, 0, 1] = ctd_bgc_exp[0]["maxdepth"]["nppv"] + nppv[:, 1, 1, 0] = ctd_bgc_exp[1]["surface"]["nppv"] + nppv[:, 0, 1, 0] = ctd_bgc_exp[1]["maxdepth"]["nppv"] + fieldset = FieldSet.from_data( - {"V": v, "U": u, "o2": o2, "chl": chl}, + { + "V": v, + "U": u, + "o2": o2, + "chl": chl, + "no3": no3, + "po4": po4, + "ph": ph, + "phyc": phyc, + "zooc": zooc, + "nppv": nppv, + }, { "time": [ np.datetime64(base_time + datetime.timedelta(hours=0)), @@ -129,7 +201,18 @@ def test_simulate_ctd_bgcs(tmpdir) -> None: (obs_maxdepth, "maxdepth"), ]: exp = exp_bothloc[loc] - for var in ["o2", "chl", "lat", "lon"]: + for var in [ + "o2", + "chl", + "no3", + "po4", + "ph", + "phyc", + "zooc", + "nppv", + "lat", + "lon", + ]: obs_value = obs[var].values.item() exp_value = exp[var] assert np.isclose(obs_value, exp_value), (