Repository: British-Oceanographic-Data-Centre/COAsT (language: python)

Issue:
Add functionality to contourT class
Create function to return a dataset that holds information about the flow _along_ an isobath


Discussion / hints:

Fix patch:
diff --git a/coast/contour.py b/coast/contour.py
index 1e021be3..48006743 100755
--- a/coast/contour.py
+++ b/coast/contour.py
@@ -411,8 +411,7 @@ def calc_cross_contour_flow(self, gridded_u: Coast, gridded_v: Coast):
             }
 
         self._update_cross_flow_vars("depth_0", u_ds.depth_0, v_ds.depth_0, dr_n, dr_s, dr_e, dr_w, 1)
-        self._update_cross_flow_vars("longitude", u_ds.longitude, v_ds.longitude, dr_n, dr_s, dr_e, dr_w, 0)
-        self._update_cross_flow_vars("latitude", u_ds.latitude, v_ds.latitude, dr_n, dr_s, dr_e, dr_w, 0)
+        self._update_cross_flow_latlon(u_ds, v_ds, dr_n, dr_s, dr_e, dr_w)
         self._update_cross_flow_vars("bathymetry", u_ds.bathymetry, v_ds.bathymetry, dr_n, dr_s, dr_e, dr_w, 0)
         self._update_cross_flow_vars("e1", u_ds.e1, v_ds.e1, dr_n, dr_s, dr_e, dr_w, 0)
         self._update_cross_flow_vars("e2", u_ds.e2, v_ds.e2, dr_n, dr_s, dr_e, dr_w, 0)
@@ -422,17 +421,12 @@ def calc_cross_contour_flow(self, gridded_u: Coast, gridded_v: Coast):
         self.data_cross_flow["depth_0"].attrs = {
             "standard_name": "Depth at time zero on the contour-normal velocity grid points"
         }
-        self.data_cross_flow["latitude"].attrs = {
-            "standard_name": "Latitude at the contour-normal velocity grid points"
-        }
-        self.data_cross_flow["longitude"].attrs = {
-            "standard_name": "Longitude at the contour-normal velocity grid points"
-        }
+
         self.data_cross_flow = self.data_cross_flow.squeeze()
 
     def _update_cross_flow_vars(self, var, u_var, v_var, dr_n, dr_s, dr_e, dr_w, pos):
         """This method will pull variable data at specific points along the contour
-        from the u and v grid datasets and put them into the data_cross_flow dataset"""
+        from the u and v grid datasets and put them into the self.data_cross_flow dataset"""
         tmp_var = xr.full_like(u_var, np.nan)
         if pos == 0:
             tmp_var[dr_n] = u_var.data[dr_n + 1]
@@ -453,6 +447,18 @@ def _update_cross_flow_vars(self, var, u_var, v_var, dr_n, dr_s, dr_e, dr_w, pos
             tmp_var[:, :, dr_w] = v_var.data[:, :, dr_w]
             self.data_cross_flow[var] = tmp_var[:, :, :-1]
 
+    def _update_cross_flow_latlon(self, ds_u, ds_v, dr_n, dr_s, dr_e, dr_w):
+        """This method will pull the latitude and longitude data at specific points along the
+        contour from the u and v grid datasets and put them into the self.data_cross_flow dataset"""
+        for var in ["longitude", "latitude"]:
+            tmp_var = xr.full_like(ds_u[var], np.nan)
+            tmp_var[dr_n] = ds_u[var].data[dr_n + 1]
+            tmp_var[dr_s] = ds_u[var].data[dr_s]
+            tmp_var[dr_e] = ds_v[var].data[dr_e + 1]
+            tmp_var[dr_w] = ds_v[var].data[dr_w]
+            tmp_var.attrs = {"standard_name": var.capitalize() + " at the contour-normal velocity grid points"}
+            self.data_cross_flow.assign_coords({var: tmp_var[:-1]})
+
     @staticmethod
     def _pressure_gradient_fpoint2(ds_t, ds_t_j1, ds_t_i1, ds_t_j1i1, r_ind, velocity_component):
         """
@@ -720,22 +726,10 @@ def calc_geostrophic_flow(
         da_x_ind = xr.DataArray(self.x_ind, dims=["r_dim"])
         u_ds = Gridded(fn_domain=self.filename_domain, config=config_u).dataset.isel(y_dim=da_y_ind, x_dim=da_x_ind)
         v_ds = Gridded(fn_domain=self.filename_domain, config=config_v).dataset.isel(y_dim=da_y_ind, x_dim=da_x_ind)
-        self._update_cross_flow_vars(
-            "longitude", u_ds.longitude, v_ds.longitude, dr_list[0], dr_list[1], dr_list[2], dr_list[3], 0
-        )
-        self._update_cross_flow_vars(
-            "latitude", u_ds.latitude, v_ds.latitude, dr_list[0], dr_list[1], dr_list[2], dr_list[3], 0
-        )
+
+        self._update_cross_flow_latlon(u_ds, v_ds, dr_list[0], dr_list[1], dr_list[2], dr_list[3])
         self._update_cross_flow_vars("e1", u_ds.e1, v_ds.e1, dr_list[0], dr_list[1], dr_list[2], dr_list[3], 0)
         self._update_cross_flow_vars("e2", u_ds.e2, v_ds.e2, dr_list[0], dr_list[1], dr_list[2], dr_list[3], 0)
-        self.data_cross_flow["latitude"].attrs = {
-            "standard_name": "Latitude at \
-                the contour-normal velocity grid points"
-        }
-        self.data_cross_flow["longitude"].attrs = {
-            "standard_name": "Longitude at \
-                the contour-normal velocity grid points"
-        }
 
         # DataArray attributes
         coords_hpg = {
@@ -814,6 +808,7 @@ class ContourT(Contour):
 
     def __init__(self, gridded_t: Coast, y_ind, x_ind, depth):
         super().__init__(gridded_t, y_ind, x_ind, depth)
+        self.data_along_flow = xr.Dataset()
 
     def construct_pressure(self, ref_density=None, z_levels=None, extrapolate=False):
         """
@@ -957,3 +952,231 @@ def construct_pressure(self, ref_density=None, z_levels=None, extrapolate=False)
             "units": "kg m^{-1} s^{-2}",
             "standard_name": "Surface perturbation pressure",
         }
+
+    def calc_along_contour_flow(self, gridded_u: Coast, gridded_v: Coast):
+        """
+        Function that will calculate the flow along the contour and store this data
+        within Contour_t.data_along_flow, which is an xarray.Dataset. Specifically
+        Contour_t.data_along_flow.velocities are the velocities along the contour with dimensions
+        (t_dim, z_dim, r_dim), where r_dim is the dimension along the contour.
+        Contour_t.data_along_flow.transport are the velocities along the contour multiplied by the
+        thickness of the cell (velocity * e3) with dimensions
+        (t_dim, z_dim, r_dim).
+
+        If the time dependent cell thicknesses (e3) on the u and v grids are
+        present in the gridded_u and gridded_v datasets they will be used, if they
+        are not then the initial cell thicknesses (e3_0) will be used.
+
+        Parameters
+        ----------
+        gridded_u : Coast
+            The nemo object containing the model data on the u-grid.
+        gridded_v : Coast
+            The nemo object containing the model data on the v-grid.
+
+        Returns
+        -------
+        None.
+
+        """
+        # compute transports flag; set to false if suitable e3 not found
+        compute_transports = True
+
+        # subset the u and v datasets
+        da_y_ind = xr.DataArray(self.y_ind, dims=["r_dim"])
+        da_x_ind = xr.DataArray(self.x_ind, dims=["r_dim"])
+        u_ds = gridded_u.dataset.isel(y_dim=da_y_ind, x_dim=da_x_ind)
+        v_ds = gridded_v.dataset.isel(y_dim=da_y_ind, x_dim=da_x_ind)
+
+        # use time varying if e3 is present, if not default to e3_0
+        if "e3" not in u_ds.data_vars:
+            if "e3_0" not in u_ds.data_vars:
+                warn("e3 not found, transports will not be calculated")
+                compute_transports = False
+            else:
+                u_ds["e3"] = u_ds.e3_0.broadcast_like(u_ds.u_velocity)
+        if "e3" not in v_ds.data_vars:
+            if "e3_0" not in v_ds.data_vars:
+                warn("e3 not found, transports will not be calculated")
+                compute_transports = False
+            else:
+                v_ds["e3"] = v_ds.e3_0.broadcast_like(v_ds.v_velocity)
+
+        # If time dimension is missing it can throw off the indexing so expand dims
+        if "t_dim" not in u_ds.dims:
+            u_ds["u_velocity"] = u_ds.u_velocity.expand_dims("t_dim", axis=0)
+            if compute_transports:
+                u_ds["e3"] = u_ds.e3.expand_dims("t_dim", axis=0)
+        if "t_dim" not in v_ds.dims:
+            v_ds["v_velocity"] = v_ds.v_velocity.expand_dims("t_dim", axis=0)
+            if compute_transports:
+                v_ds["e3"] = v_ds.e3.expand_dims("t_dim", axis=0)
+
+        dr_n = np.where(np.diff(self.y_ind) > 0, np.arange(0, u_ds.r_dim.size - 1), np.nan)
+        dr_n = dr_n[~np.isnan(dr_n)].astype(int)
+        dr_s = np.where(np.diff(self.y_ind) < 0, np.arange(0, u_ds.r_dim.size - 1), np.nan)
+        dr_s = dr_s[~np.isnan(dr_s)].astype(int)
+        dr_e = np.where(np.diff(self.x_ind) > 0, np.arange(0, v_ds.r_dim.size - 1), np.nan)
+        dr_e = dr_e[~np.isnan(dr_e)].astype(int)
+        dr_w = np.where(np.diff(self.x_ind) < 0, np.arange(0, v_ds.r_dim.size - 1), np.nan)
+        dr_w = dr_w[~np.isnan(dr_w)].astype(int)
+
+        tmp_velocities = xr.full_like(u_ds.u_velocity, np.nan)
+        tmp_velocities[:, :, dr_n] = v_ds.v_velocity.data[:, :, dr_n]
+        tmp_velocities[:, :, dr_s] = -v_ds.v_velocity.data[:, :, dr_s + 1]
+        tmp_velocities[:, :, dr_e] = u_ds.u_velocity.data[:, :, dr_e]
+        tmp_velocities[:, :, dr_w] = -u_ds.u_velocity.data[:, :, dr_w + 1]
+        self.data_along_flow["velocities"] = tmp_velocities[:, :, :-1]
+        self.data_along_flow["velocities"].attrs = {"units": "m/s", "standard_name": "contour-tangent velocities"}
+
+        # Store the length of contour segement between t-points
+        tmp_e4 = xr.full_like(u_ds.e1, np.nan)
+        tmp_e4[dr_n] = v_ds.e2.data[dr_n]
+        tmp_e4[dr_s] = v_ds.e2.data[dr_s + 1]
+        tmp_e4[dr_e] = u_ds.e1.data[dr_e]
+        tmp_e4[dr_w] = u_ds.e1.data[dr_w + 1]
+        self.data_along_flow["e4"] = tmp_e4[:-1]
+        self.data_along_flow["e4"].attrs = {
+            "units": "m",
+            "standard_name": "length of contour segment at the along-contour velocity grid points",
+        }
+
+        if compute_transports:
+            tmp_transport = xr.full_like(u_ds.u_velocity, np.nan)
+            tmp_transport[:, :, dr_n] = v_ds.v_velocity.data[:, :, dr_n] * v_ds.e3.data[:, :, dr_n]
+            tmp_transport[:, :, dr_s] = -v_ds.v_velocity.data[:, :, dr_s + 1] * v_ds.e3.data[:, :, dr_s + 1]
+            tmp_transport[:, :, dr_e] = u_ds.u_velocity.data[:, :, dr_e] * u_ds.e3.data[:, :, dr_e]
+            tmp_transport[:, :, dr_w] = -u_ds.u_velocity.data[:, :, dr_w + 1] * u_ds.e3.data[:, :, dr_w + 1]
+            self.data_along_flow["transport"] = tmp_transport[:, :, :-1]
+            self.data_along_flow["transport"].attrs = {
+                "units": "m^2/s",
+                "standard_name": "along-contour transport (v * e3)",
+            }
+
+        self._update_flow_vars("depth_0", u_ds.depth_0, v_ds.depth_0, dr_n, dr_s, dr_e, dr_w, 1)
+        self._update_along_flow_latlon(u_ds, v_ds, dr_n, dr_s, dr_e, dr_w)
+        self._update_flow_vars("bathymetry", u_ds.bathymetry, v_ds.bathymetry, dr_n, dr_s, dr_e, dr_w, 0)
+        self._update_flow_vars("e1", u_ds.e1, v_ds.e1, dr_n, dr_s, dr_e, dr_w, 0)
+        self._update_flow_vars("e2", u_ds.e2, v_ds.e2, dr_n, dr_s, dr_e, dr_w, 0)
+        if compute_transports:
+            self._update_flow_vars("e3", u_ds.e3, v_ds.e3, dr_n, dr_s, dr_e, dr_w, 2)
+
+        self.data_along_flow["depth_0"].attrs = {
+            "standard_name": "Depth at time zero on the along contour velocity grid points"
+        }
+
+        self.data_along_flow = self.data_along_flow.squeeze()
+
+    def calc_along_contour_flow_2d(self, gridded_u: Coast, gridded_v: Coast):
+        """
+        Function that will calculate the 2d flow (no vertical dimension
+        along the contour and store this data within Contour_t.data_along_flow,
+        which is an xarray.Dataset. Contour_t.data_along_flow.velocities are
+        the velocities along the contour with dimensions (t_dim, r_dim),
+        where r_dim is the dimension along the contour. e3 and
+        e3_0 are interpreted to be the water column thicknesses and
+        are included in the dataset as Contour_t.data_along_flow.e3 and
+        Contour_t.data_along_flow.e3_0
+
+        Parameters
+        ----------
+        gridded_u : Coast
+            The nemo object containing the model data on the u-grid.
+        gridded_v : Coast
+            The nemo object containing the model data on the v-grid.
+
+        Returns
+        -------
+        None.
+
+        """
+
+        # subset the u and v datasets
+        da_y_ind = xr.DataArray(self.y_ind, dims=["r_dim"])
+        da_x_ind = xr.DataArray(self.x_ind, dims=["r_dim"])
+        u_ds = gridded_u.dataset.isel(y_dim=da_y_ind, x_dim=da_x_ind)
+        v_ds = gridded_v.dataset.isel(y_dim=da_y_ind, x_dim=da_x_ind)
+
+        # If time dimension is missing it can throw off the indexing so expand dims
+        if "t_dim" not in u_ds.dims:
+            u_ds["u_velocity"] = u_ds.u_velocity.expand_dims("t_dim", axis=0)
+        if "t_dim" not in v_ds.dims:
+            v_ds["v_velocity"] = v_ds.v_velocity.expand_dims("t_dim", axis=0)
+
+        dr_n = np.where(np.diff(self.y_ind) > 0, np.arange(0, u_ds.r_dim.size - 1), np.nan)
+        dr_n = dr_n[~np.isnan(dr_n)].astype(int)
+        dr_s = np.where(np.diff(self.y_ind) < 0, np.arange(0, u_ds.r_dim.size - 1), np.nan)
+        dr_s = dr_s[~np.isnan(dr_s)].astype(int)
+        dr_e = np.where(np.diff(self.x_ind) > 0, np.arange(0, v_ds.r_dim.size - 1), np.nan)
+        dr_e = dr_e[~np.isnan(dr_e)].astype(int)
+        dr_w = np.where(np.diff(self.x_ind) < 0, np.arange(0, v_ds.r_dim.size - 1), np.nan)
+        dr_w = dr_w[~np.isnan(dr_w)].astype(int)
+
+        # Note that subsetting the dataset first instead of subsetting each array seperately,
+        # as we do here, is neater but significantly slower.
+        tmp_velocities = xr.full_like(u_ds.u_velocity, np.nan)
+        tmp_velocities[:, dr_n] = v_ds.v_velocity.data[:, dr_n]
+        tmp_velocities[:, dr_s] = -v_ds.v_velocity.data[:, dr_s + 1]
+        tmp_velocities[:, dr_e] = u_ds.u_velocity.data[:, dr_e]
+        tmp_velocities[:, dr_w] = -u_ds.u_velocity.data[:, dr_w + 1]
+        self.data_along_flow["velocities"] = tmp_velocities[:, :-1]
+        self.data_along_flow["velocities"].attrs = {"units": "m/s", "standard_name": "along-contour velocities"}
+
+        # Store the length of contour segement between t-points
+        tmp_e4 = xr.full_like(u_ds.e1, np.nan)
+        tmp_e4[dr_n] = v_ds.e2.data[dr_n]
+        tmp_e4[dr_s] = v_ds.e2.data[dr_s + 1]
+        tmp_e4[dr_e] = u_ds.e1.data[dr_e]
+        tmp_e4[dr_w] = u_ds.e1.data[dr_w + 1]
+        self.data_along_flow["e4"] = tmp_e4[:-1]
+        self.data_along_flow["e4"].attrs = {
+            "units": "m",
+            "standard_name": "length of contour segment at the along-contour velocity grid points",
+        }
+
+        self._update_along_flow_latlon(u_ds, v_ds, dr_n, dr_s, dr_e, dr_w)
+        self._update_flow_vars("bathymetry", u_ds.bathymetry, v_ds.bathymetry, dr_n, dr_s, dr_e, dr_w, 0)
+        self._update_flow_vars("e1", u_ds.e1, v_ds.e1, dr_n, dr_s, dr_e, dr_w, 0)
+        self._update_flow_vars("e2", u_ds.e2, v_ds.e2, dr_n, dr_s, dr_e, dr_w, 0)
+
+        if ("e3" in u_ds.data_vars) and ("e3" in v_ds.data_vars):
+            self._update_flow_vars("e3", u_ds.e3, v_ds.e3, dr_n, dr_s, dr_e, dr_w, 1)
+        if ("e3_0" in u_ds.data_vars) and ("e3_0" in v_ds.data_vars):
+            self._update_flow_vars("e3_0", u_ds.e3_0, v_ds.e3_0, dr_n, dr_s, dr_e, dr_w, 0)
+
+        self.data_along_flow = self.data_along_flow.squeeze()
+
+    def _update_flow_vars(self, var, u_var, v_var, dr_n, dr_s, dr_e, dr_w, pos):
+        """This method will pull variable data at specific points along the contour
+        from the u and v grid datasets and put them into the self.data_along_flow dataset"""
+        tmp_var = xr.full_like(u_var, np.nan)
+        if pos == 0:
+            tmp_var[dr_n] = v_var.data[dr_n]
+            tmp_var[dr_s] = v_var.data[dr_s + 1]
+            tmp_var[dr_e] = u_var.data[dr_e]
+            tmp_var[dr_w] = u_var.data[dr_w + 1]
+            self.data_along_flow[var] = tmp_var[:-1]
+        elif pos == 1:
+            tmp_var[:, dr_n] = v_var.data[:, dr_n]
+            tmp_var[:, dr_s] = v_var.data[:, dr_s + 1]
+            tmp_var[:, dr_e] = u_var.data[:, dr_e]
+            tmp_var[:, dr_w] = u_var.data[:, dr_w + 1]
+            self.data_along_flow[var] = tmp_var[:, :-1]
+        elif pos == 2:
+            tmp_var[:, :, dr_n] = v_var.data[:, :, dr_n]
+            tmp_var[:, :, dr_s] = v_var.data[:, :, dr_s + 1]
+            tmp_var[:, :, dr_e] = u_var.data[:, :, dr_e]
+            tmp_var[:, :, dr_w] = u_var.data[:, :, dr_w + 1]
+            self.data_along_flow[var] = tmp_var[:, :, :-1]
+
+    def _update_along_flow_latlon(self, ds_u, ds_v, dr_n, dr_s, dr_e, dr_w):
+        """This method will pull latitude and longitude data at specific points along the
+        contour from the u and v grid datasets and put them into the self.data_along_flow dataset"""
+        for var in ["longitude", "latitude"]:
+            tmp_var = xr.full_like(ds_u[var], np.nan)
+            tmp_var[dr_n] = ds_u[var].data[dr_n]
+            tmp_var[dr_s] = ds_u[var].data[dr_s + 1]
+            tmp_var[dr_e] = ds_v[var].data[dr_e]
+            tmp_var[dr_w] = ds_v[var].data[dr_w + 1]
+            tmp_var.attrs = {"standard_name": var.capitalize() + " at the along-contour velocity grid points"}
+            self.data_along_flow.assign_coords({var: tmp_var[:-1]})


Test patch:
diff --git a/unit_testing/test_isobath_contour_methods.py b/unit_testing/test_isobath_contour_methods.py
index 9f32ab67..cd31b9c5 100644
--- a/unit_testing/test_isobath_contour_methods.py
+++ b/unit_testing/test_isobath_contour_methods.py
@@ -11,7 +11,7 @@
 import datetime
 
 
-class test_isobath_contour_methods(unittest.TestCase):
+class test_contour_f_methods(unittest.TestCase):
     def test_extract_isobath_contour_between_two_points(self):
 
         with self.subTest("Extract contour"):
@@ -31,20 +31,6 @@ def test_extract_isobath_contour_between_two_points(self):
             plt.savefig(cont_path)
             plt.close("all")
 
-    def test_calculate_pressure_along_contour(self):
-        nemo_t = coast.Gridded(
-            fn_data=files.fn_nemo_grid_t_dat, fn_domain=files.fn_nemo_dom, config=files.fn_config_t_grid
-        )
-        contours, no_contours = coast.Contour.get_contours(nemo_t, 200)
-        y_ind, x_ind, contour = coast.Contour.get_contour_segment(nemo_t, contours[0], [50, -10], [60, 3])
-        cont_t = coast.ContourT(nemo_t, y_ind, x_ind, 200)
-        cont_t.construct_pressure(1027)
-        check1 = np.allclose(
-            (cont_t.data_contour.pressure_s + cont_t.data_contour.pressure_h_zlevels).sum().compute().item(),
-            27490693.20181531,
-        )
-        self.assertTrue(check1)
-
     def test_calculate_flow_across_contour(self):
         nemo_f = coast.Gridded(fn_domain=files.fn_nemo_dom, config=files.fn_config_f_grid)
         nemo_u = coast.Gridded(
@@ -63,7 +49,7 @@ def test_calculate_flow_across_contour(self):
         )
         self.assertTrue(check1, "check1")
 
-    def test_calculate_pressure_gradient_griven_flow(self):
+    def test_calculate_pressure_gradient_driven_flow(self):
         nemo_t = coast.Gridded(
             fn_data=files.fn_nemo_grid_t_dat, fn_domain=files.fn_nemo_dom, config=files.fn_config_t_grid
         )
@@ -84,3 +70,63 @@ def test_calculate_pressure_gradient_griven_flow(self):
             74.65002414,
         )
         self.assertTrue(check1, "check1")
+
+
+class test_contour_t_methods(unittest.TestCase):
+    def setUp(self):
+        # This is called at the beginning of every test_ method.
+        # load gridded data
+        self.nemo_t = coast.Gridded(files.fn_nemo_grid_t_dat, files.fn_nemo_dom, config=files.fn_config_t_grid)
+        # create contour dataset along 200 m isobath
+        contours, no_contours = coast.Contour.get_contours(self.nemo_t, 200)
+        y_ind, x_ind, contour = coast.Contour.get_contour_segment(self.nemo_t, contours[0], [50, -10], [60, 3])
+        self.cont_t = coast.ContourT(self.nemo_t, y_ind, x_ind, 200)
+
+    def test_along_contour_flow(self):
+        # calculate flow along contour
+        nemo_u = coast.Gridded(files.fn_nemo_grid_u_dat, files.fn_nemo_dom, config=files.fn_config_u_grid)
+        nemo_v = coast.Gridded(files.fn_nemo_grid_v_dat, files.fn_nemo_dom, config=files.fn_config_v_grid)
+        self.cont_t.calc_along_contour_flow(nemo_u, nemo_v)
+
+        with self.subTest("Check on velocities"):
+            cksum = (
+                (
+                    self.cont_t.data_along_flow.velocities
+                    * self.cont_t.data_along_flow.e3
+                    * self.cont_t.data_along_flow.e4
+                )
+                .sum()
+                .values
+            )
+            self.assertTrue(
+                np.isclose(cksum, 116660850), "velocities checksum: " + str(cksum) + ", should be 116660850"
+            )
+
+        with self.subTest("Check on transport"):
+            cksum = (self.cont_t.data_along_flow.transport * self.cont_t.data_along_flow.e4).sum().values
+            self.assertTrue(
+                np.isclose(cksum, 116660850), "transports checksum: " + str(cksum) + ", should be 116660850"
+            )
+
+    def test_along_contour_2d_flow(self):
+        # calculate flow along contour
+        nemo_u = coast.Gridded(files.fn_nemo_grid_u_dat, files.fn_nemo_dom, config=files.fn_config_u_grid)
+        nemo_v = coast.Gridded(files.fn_nemo_grid_v_dat, files.fn_nemo_dom, config=files.fn_config_v_grid)
+        nemo_u.dataset = nemo_u.dataset.isel(z_dim=0).squeeze()
+        nemo_v.dataset = nemo_v.dataset.isel(z_dim=0).squeeze()
+        self.cont_t.calc_along_contour_flow_2d(nemo_u, nemo_v)
+
+        cksum = (
+            (self.cont_t.data_along_flow.velocities * self.cont_t.data_along_flow.e3_0 * self.cont_t.data_along_flow.e4)
+            .sum()
+            .values
+        )
+        self.assertTrue(np.isclose(cksum, 293910.94), "velocities checksum: " + str(cksum) + ", should be 293910.94")
+
+    def test_calculate_pressure_along_contour(self):
+        self.cont_t.construct_pressure(1027)
+        check1 = np.allclose(
+            (self.cont_t.data_contour.pressure_s + self.cont_t.data_contour.pressure_h_zlevels).sum().compute().item(),
+            27490693.20181531,
+        )
+        self.assertTrue(check1)
diff --git a/unit_testing/unit_test.py b/unit_testing/unit_test.py
index 24f82e60..19584a5f 100644
--- a/unit_testing/unit_test.py
+++ b/unit_testing/unit_test.py
@@ -17,7 +17,7 @@
 from test_object_manipulation import test_object_manipulation
 from test_altimetry_methods import test_altimetry_methods
 from test_tidegauge_methods import test_tidegauge_methods
-from test_isobath_contour_methods import test_isobath_contour_methods
+from test_isobath_contour_methods import test_contour_t_methods, test_contour_f_methods
 from test_eof_methods import test_eof_methods
 from test_profile_methods import test_profile_methods
 from test_plot_utilities import test_plot_utilities
@@ -43,7 +43,8 @@
     test_altimetry_methods,
     test_tidegauge_methods,
     test_eof_methods,
-    test_isobath_contour_methods,
+    test_contour_f_methods,
+    test_contour_t_methods,
     test_profile_methods,
     test_plot_utilities,
     test_stats_utilities,