diff --git a/.gitignore b/.gitignore
index b9e571dfeac4502371741f0d3898316f157bc7b9..8255dbcd46f970101f2a5e54202238ea3d480cae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@ wheels/
 MANIFEST
 outputs
 .DS_Store
+DATA
 
 # PyInstaller
 #  Usually these files are written by a python script from a template
diff --git a/pynemo/tide/fes_extract_HC.py b/pynemo/tide/fes_extract_HC.py
new file mode 100644
index 0000000000000000000000000000000000000000..74037818a1b74a9f2c369c26a9b78dc2c2caff82
--- /dev/null
+++ b/pynemo/tide/fes_extract_HC.py
@@ -0,0 +1,260 @@
+'''
+This is to extract the tidal harmonic constants out of a tidal model
+for a given locations
+[amp,Gph] = tpxo_extract_HC(Model,lat,lon,type,Cid)
+
+@author: Mr. Srikanth Nagella
+'''
+
+# pylint: disable=E1103
+# pylint: disable=no-name-in-module
+from netCDF4 import Dataset
+from scipy import interpolate
+import numpy as np
+
+class FESExtract(object):
+    """ This is TPXO model extract_hc.c implementation in python"""
+    def __init__(self, settings, lat, lon, grid_type):
+        """initialises the Extract of tide information from the netcdf
+           Tidal files"""
+	# Set tide model
+        tide_model = 'fes'
+
+        if tide_model == 'fes':  # Define stuff to generalise Tide model
+           hRe_name = 'hRe'
+           hIm_name = 'hIm'
+           lon_z_name = 'lon_z'
+           lat_z_name = 'lat_z'	
+           URe_name = 'URe'
+           UIm_name = 'UIm'
+           lon_u_name = 'lon_u'
+           lat_u_name = 'lat_u'
+           VRe_name = 'VRe'
+           VIm_name = 'VIm'
+           lon_v_name = 'lon_v'
+           lat_v_name = 'lat_v'
+           mz_name = 'mz'
+           mu_name = 'mu'
+           mv_name = 'mv'
+           self.grid = Dataset(settings['tide_grid'])#../data/tide/grid_tpxo7.2.nc')
+           #read the height_dataset file
+           self.height_dataset = Dataset(settings['tide_h'])#../data/tide/h_tpxo7.2.nc')
+           #read the velocity_dataset file
+           self.velocity_dataset = Dataset(settings['tide_u'])#../data/tide/u_tpxo7.2.nc')
+
+           height_z = self.grid.variables['hz']
+           mask_z = self.grid.variables['mz']
+           lon_z = self.height_dataset.variables[lon_z_name][:, 0]
+           lat_z = self.height_dataset.variables[lat_z_name][0, :]
+           lon_resolution = lon_z[1] - lon_z[0]
+           data_in_km = 0 # added to maintain the reference to matlab tmd code
+           # Pull out the constituents that are avaibable
+           self.cons = []
+           for ncon in range(self.height_dataset.variables['con'].shape[0]):
+              self.cons.append(self.height_dataset.variables['con'][ncon, :].tostring().strip())
+        else:
+           print('Don''t know that tide model')
+
+        # Wrap coordinates in longitude if the domain is global
+        glob = 0
+        if lon_z[-1]-lon_z[0] == 360-lon_resolution:
+            glob = 1
+        if glob == 1:
+            lon_z = np.concatenate(([lon_z[0]-lon_resolution, ], lon_z,
+                                    [lon_z[-1]+lon_resolution, ]))
+            height_z = np.concatenate(([height_z[-1, :], ], height_z, [height_z[0, :],]), axis=0)
+            mask_z = np.concatenate(([mask_z[-1, :], ], mask_z, [mask_z[0, :], ]), axis=0)
+
+        #adjust lon convention
+        xmin = np.min(lon)
+
+        if data_in_km == 0:
+            if xmin < lon_z[0]:
+                lon[lon < 0] = lon[lon < 0] + 360
+            if xmin > lon_z[-1]:
+                lon[lon > 180] = lon[lon > 180]-360
+
+        #height_z[height_z==0] = np.NaN
+#        f=interpolate.RectBivariateSpline(lon_z,lat_z,height_z,kx=1,ky=1)
+#        depth = np.zeros(lon.size)
+#        for idx in range(lon.size):
+#            depth[idx] = f(lon[idx],lat[idx])
+#        print depth[369:371]
+
+#        H2 = np.ravel(height_z)
+#        H2[H2==0] = np.NaN
+#        points= np.concatenate((np.ravel(self.height_dataset.variables['lon_z']),
+#                                np.ravel(self.height_dataset.variables['lat_z'])))
+#        points= np.reshape(points,(points.shape[0]/2,2),order='F')
+#        print points.shape
+#        print np.ravel(height_z).shape
+#        depth = interpolate.griddata(points,H2,(lon,lat))
+#        print depth
+#        print depth.shape
+
+        height_z[height_z == 0] = np.NaN
+        lonlat = np.concatenate((lon, lat))
+        lonlat = np.reshape(lonlat, (lon.size, 2), order='F')
+
+        depth = interpolate.interpn((lon_z, lat_z), height_z, lonlat)
+#        f=interpolate.RectBivariateSpline(lon_z,lat_z,mask_z,kx=1,ky=1)
+#        depth_mask = np.zeros(lon.size)
+#        for idx in range(lon.size):
+#            depth_mask[idx] = f(lon[idx],lat[idx])
+        depth_mask = interpolate.interpn((lon_z, lat_z), mask_z, lonlat)
+        index = np.where((np.isnan(depth)) & (depth_mask > 0))
+
+        if index[0].size != 0:
+            depth[index] = bilinear_interpolation(lon_z, lat_z, height_z, lon[index], lat[index])
+
+        if grid_type == 'z' or grid_type == 't':
+            self.amp, self.gph = self.interpolate_constituents(self.height_dataset,
+                                                               hRe_name, hIm_name, lon_z_name, lat_z_name,
+							       lon, lat, maskname=mz_name)
+        elif grid_type == 'u':
+            self.amp, self.gph = self.interpolate_constituents(self.velocity_dataset,
+                                                               URe_name, UIm_name, lon_u_name, lat_u_name,
+                                                               lon, lat, depth, maskname=mu_name)
+        elif grid_type == 'v':
+            self.amp, self.gph = self.interpolate_constituents(self.velocity_dataset,
+                                                               VRe_name, VIm_name, lon_v_name, lat_v_name,
+                                                               lon, lat, depth, maskname=mv_name)
+        else:
+            print('Unknown grid_type')
+            return
+
+    def interpolate_constituents(self, nc_dataset, real_var_name, img_var_name, lon_var_name,
+                                 lat_var_name, lon, lat, height_data=None, maskname=None):
+        """ Interpolates the tidal constituents along the given lat lon coordinates """
+        amp = np.zeros((nc_dataset.variables['con'].shape[0], lon.shape[0],))
+        gph = np.zeros((nc_dataset.variables['con'].shape[0], lon.shape[0],))
+        data = np.array(np.ravel(nc_dataset.variables[real_var_name]), dtype=complex)
+        data.imag = np.array(np.ravel(nc_dataset.variables[img_var_name]))
+
+        data = data.reshape(nc_dataset.variables[real_var_name].shape)
+        #data[data==0] = np.NaN
+
+        #Lat Lon values
+        x_values = nc_dataset.variables[lon_var_name][:, 0]
+        y_values = nc_dataset.variables[lat_var_name][0, :]
+        x_resolution = x_values[1] - x_values[0]
+        glob = 0
+        if x_values[-1]-x_values[0] == 360-x_resolution:
+            glob = 1
+
+        if glob == 1:
+            x_values = np.concatenate(([x_values[0]-x_resolution,], x_values,
+                                       [x_values[-1]+x_resolution, ]))
+
+        #adjust lon convention
+        xmin = np.min(lon)
+        if xmin < x_values[0]:
+            lon[lon < 0] = lon[lon < 0] + 360
+        if xmin > x_values[-1]:
+            lon[lon > 180] = lon[lon > 180]-360
+
+        lonlat = np.concatenate((lon, lat))
+        lonlat = np.reshape(lonlat, (lon.size, 2), order='F')
+
+        mask = self.grid.variables[maskname]
+        mask = np.concatenate(([mask[-1, :], ], mask, [mask[0, :], ]), axis=0)
+        #interpolate the mask values
+        maskedpoints = interpolate.interpn((x_values, y_values), mask, lonlat)
+
+        data_temp = np.zeros((data.shape[0], lon.shape[0], 2, ))
+        for cons_index in range(data.shape[0]):
+            #interpolate real values
+            data_temp[cons_index, :, 0] = interpolate_data(x_values, y_values,
+                                                                data[cons_index, :, :].real,
+                                                                maskedpoints, lonlat)
+            #interpolate imag values
+            data_temp[cons_index, :, 1] = interpolate_data(x_values, y_values,
+                                                                data[cons_index, :, :].imag,
+                                                                maskedpoints, lonlat)
+
+            #for velocity_dataset values
+            if height_data is not None:
+                data_temp[cons_index, :, 0] = data_temp[cons_index, :, 0]/height_data*100
+                data_temp[cons_index, :, 1] = data_temp[cons_index, :, 1]/height_data*100
+
+            zcomplex = np.array(data_temp[cons_index, :, 0], dtype=complex)
+            zcomplex.imag = data_temp[cons_index, :, 1]
+
+            amp[cons_index, :] = np.absolute(zcomplex)
+            gph[cons_index, :] = np.arctan2(-1*zcomplex.imag, zcomplex.real)
+        gph = gph*180.0/np.pi
+        gph[gph < 0] = gph[gph < 0]+360.0
+        return amp, gph
+
+def interpolate_data(lon, lat, data, mask, lonlat):
+    """ Interpolate data data on regular grid for given lonlat coordinates """
+    result = np.zeros((lonlat.shape[0], ))
+    data[data == 0] = np.NaN
+    data = np.concatenate(([data[-1, :], ], data, [data[0, :], ]), axis=0)
+    result[:] = interpolate.interpn((lon, lat), data, lonlat)
+    index = np.where((np.isnan(result)) & (mask > 0))
+    if index[0].size != 0:
+        result[index] = bilinear_interpolation(lon, lat, data, np.ravel(lonlat[index, 0]),
+                                               np.ravel(lonlat[index, 1]))
+    return result
+
+def bilinear_interpolation(lon, lat, data, lon_new, lat_new):
+    """ Does a bilinear interpolation of grid where the data values are NaN's"""
+    glob = 0
+    lon_resolution = lon[1] - lon[0]
+    if lon[-1] - lon[1] == 360 - lon_resolution:
+        glob = 1
+    inan = np.where(np.isnan(data))
+    data[inan] = 0
+    mask = np.zeros(data.shape)
+    mask[data != 0] = 1
+#    n = lon.size
+#    m = lat.size
+    if lon.size != data.shape[0] or lat.size != data.shape[1]:
+        print('Check Dimensions')
+        return np.NaN
+    if glob == 1:
+        lon = np.concatenate(([lon[0] - 2 * lon_resolution, lon[0] - lon_resolution, ],
+                              lon, [lon[-1] + lon_resolution, lon[-1] + 2 * lon_resolution]))
+        data = np.concatenate((data[-2, :], data[-1, :], data, data[0, :], data[1, :]), axis=0)
+        mask = np.concatenate((mask[-2, :], mask[-1, :], mask, mask[0, :], mask[1, :]), axis=0)
+    lon_new_copy = lon_new
+
+    nonmask_index = np.where((lon_new_copy < lon[0]) & (lon_new_copy > lon[-1]))
+    if lon[-1] > 180:
+        lon_new_copy[nonmask_index] = lon_new_copy[nonmask_index] + 360
+    if lon[-1] < 0:
+        lon_new_copy[nonmask_index] = lon_new_copy[nonmask_index] - 360
+    lon_new_copy[lon_new_copy > 360] = lon_new_copy[lon_new_copy > 360] - 360
+    lon_new_copy[lon_new_copy < -180] = lon_new_copy[lon_new_copy < -180] + 360
+
+    weight_factor_0 = 1 / (4 + 2 * np.sqrt(2))
+    weight_factor_1 = weight_factor_0 / np.sqrt(2)
+    height_temp = weight_factor_1 * data[0:-2, 0:-2] + weight_factor_0 * data[0:-2, 1:-1] + \
+                  weight_factor_1 * data[0:-2, 2:] + weight_factor_1 * data[2:, 0:-2] + \
+                  weight_factor_0 * data[2:, 1:-1] + weight_factor_1 * data[2:, 2:] + \
+                  weight_factor_0 * data[1:-1, 0:-2] + weight_factor_0 * data[1:-1, 2:]
+    mask_temp = weight_factor_1 * mask[0:-2, 0:-2] + weight_factor_0 * mask[0:-2, 1:-1] + \
+                weight_factor_1 * mask[0:-2, 2:] + weight_factor_1 * mask[2:, 0:-2] + \
+                weight_factor_0 * mask[2:, 1:-1] + weight_factor_1 * mask[2:, 2:] + \
+                weight_factor_0 * mask[1:-1, 0:-2] + weight_factor_0 * mask[1:-1, 2:]
+    mask_temp[mask_temp == 0] = 1
+    data_copy = data.copy()
+    data_copy[1:-1, 1:-1] = np.divide(height_temp, mask_temp)
+    nonmask_index = np.where(mask == 1)
+    data_copy[nonmask_index] = data[nonmask_index]
+    data_copy[data_copy == 0] = np.NaN
+    lonlat = np.concatenate((lon_new_copy, lat_new))
+    lonlat = np.reshape(lonlat, (lon_new_copy.size, 2), order='F')
+    result = interpolate.interpn((lon, lat), data_copy, lonlat)
+
+    return result
+
+
+#lat=[42.8920,42.9549,43.0178]
+#lon=[339.4313,339.4324,339.4335]
+#lat_u=[42.8916,42.9545,43.0174]
+#lon_u=[339.4735,339.4746,339.4757]
+#lat = np.array(lat_u)
+#lon = np.array(lon_u)
+#lon = TPXO_Extract(lat,lon,'velocity_dataset')