PyMVP 0.2.3__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyMVP
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Python package for Moving Vessel Profiler correction and analysis
5
5
  Author: MaximilienWemaere
6
6
  Requires-Python: >=3.10
@@ -114,8 +114,8 @@ class Analyzer:
114
114
  self.PH_mvp = nc['PH'].values
115
115
  self.SALT_mvp = nc['SAL'].values
116
116
  self.TIME_mvp = nc['TIME_s'].values
117
- self.LAT_mvp = nc['LATITUDE'].values
118
- self.LON_mvp = nc['LONGITUDE'].values
117
+ self.Lat_mvp = nc['LATITUDE'].values
118
+ self.Lon_mvp = nc['LONGITUDE'].values
119
119
  self.DATETIME_mvp = nc['profile_time'].values
120
120
  self.DIR = nc['direction'].values
121
121
  self.label_mvp = nc['profile'].values
@@ -293,8 +293,8 @@ class Analyzer:
293
293
  self.PH_mvp = PH_mvp
294
294
  self.SALT_mvp = SALT_mvp
295
295
  self.TIME_mvp = TIME_mvp
296
- self.LAT_mvp = LAT_mvp
297
- self.LON_mvp = LON_mvp
296
+ self.Lat_mvp = LAT_mvp
297
+ self.Lon_mvp = LON_mvp
298
298
  self.DATETIME_mvp = DATETIME_mvp
299
299
  self.DIR = DIR
300
300
  self.label_mvp = Label_mvp
@@ -341,8 +341,8 @@ class Analyzer:
341
341
  self.PH_mvp = nc['PH'].values
342
342
  self.SALT_mvp = nc['SAL'].values
343
343
  self.TIME_mvp = nc['TIME'].values
344
- self.LAT_mvp = nc['LATITUDE'].values
345
- self.LON_mvp = nc['LONGITUDE'].values
344
+ self.Lat_mvp = nc['LATITUDE'].values
345
+ self.Lon_mvp = nc['LONGITUDE'].values
346
346
  self.DATETIME_mvp = nc['profile_time'].values
347
347
  self.DIR = nc['direction'].values
348
348
  self.Label_mvp = nc['profile'].values
@@ -481,8 +481,8 @@ class Analyzer:
481
481
  self.PH_mvp = np.hstack((self.PH_mvp, nan_cols))
482
482
  self.SALT_mvp = np.hstack((self.SALT_mvp, nan_cols))
483
483
  self.TIME_mvp = np.hstack((self.TIME_mvp, nan_cols))
484
- self.LAT_mvp = np.hstack((self.LAT_mvp, nan_cols))
485
- self.LON_mvp = np.hstack((self.LON_mvp, nan_cols))
484
+ self.Lat_mvp = np.hstack((self.Lat_mvp, nan_cols))
485
+ self.Lon_mvp = np.hstack((self.Lon_mvp, nan_cols))
486
486
 
487
487
 
488
488
 
@@ -547,8 +547,8 @@ class Analyzer:
547
547
  self.PH_mvp = np.concatenate((self.PH_mvp, PH_mvp), axis=0)
548
548
  self.SALT_mvp = np.concatenate((self.SALT_mvp, SALT_mvp), axis=0)
549
549
  self.TIME_mvp = np.concatenate((self.TIME_mvp, TIME_mvp), axis=0)
550
- self.LAT_mvp = np.concatenate((self.LAT_mvp, LAT_mvp), axis=0)
551
- self.LON_mvp = np.concatenate((self.LON_mvp, LON_mvp), axis=0)
550
+ self.Lat_mvp = np.concatenate((self.Lat_mvp, LAT_mvp), axis=0)
551
+ self.Lon_mvp = np.concatenate((self.Lon_mvp, LON_mvp), axis=0)
552
552
 
553
553
  self.DATETIME_mvp.extend(DATETIME_mvp)
554
554
  self.DIR.extend(DIR)
@@ -585,7 +585,7 @@ class Analyzer:
585
585
  TEMP_ctd_temp = []
586
586
  COND_ctd_temp = []
587
587
  TURB_ctd_temp = []
588
- OXY_ctd_temp = []
588
+ DO_ctd_temp = []
589
589
  FLUO_ctd_temp = []
590
590
  CDOM_ctd_temp = []
591
591
  DATETIME_ctd = []
@@ -603,8 +603,8 @@ class Analyzer:
603
603
  SALT_ctd_temp.append(nc['SAL'].values[1])
604
604
  TURB_ctd_temp.append(nc['TURB'].values[0])
605
605
  TURB_ctd_temp.append(nc['TURB'].values[1])
606
- OXY_ctd_temp.append(nc['OXY'].values[0])
607
- OXY_ctd_temp.append(nc['OXY'].values[1])
606
+ DO_ctd_temp.append(nc['OXY'].values[0])
607
+ DO_ctd_temp.append(nc['OXY'].values[1])
608
608
  FLUO_ctd_temp.append(nc['FLUO'].values[0])
609
609
  FLUO_ctd_temp.append(nc['FLUO'].values[1])
610
610
  CDOM_ctd_temp.append(nc['CDOM'].values[0])
@@ -622,12 +622,13 @@ class Analyzer:
622
622
  self.COND_ctd = np.array(COND_ctd_temp)
623
623
  self.SALT_ctd = np.array(SALT_ctd_temp)
624
624
  self.TURB_ctd = np.array(TURB_ctd_temp)
625
- self.OXY_ctd = np.array(OXY_ctd_temp)
625
+ self.DO_ctd = np.array(DO_ctd_temp)
626
626
  self.FLUO_ctd = np.array(FLUO_ctd_temp)
627
627
  self.CDOM_ctd = np.array(CDOM_ctd_temp)
628
628
  self.LAT_ctd = np.array(LAT_ctd_temp)
629
629
  self.LON_ctd = np.array(LON_ctd_temp)
630
630
  self.DATETIME_ctd = np.array(DATETIME_ctd)
631
+ self.TIME_ctd = np.array([(np.datetime64(dt) - np.datetime64(self.date_ref)) / np.timedelta64(1, 'D') for dt in self.DATETIME_ctd])
631
632
 
632
633
 
633
634
  print('CTD data loaded successfully.')
@@ -687,7 +688,7 @@ class Analyzer:
687
688
  print('MVP data:')
688
689
  print('Number of profiles: ' + str(len(self.DATETIME_mvp)))
689
690
  for i in range(0,len(self.DATETIME_mvp)):
690
- print(f" Profil down {2*i} - Profil up {2*i+1} - Latitude: {self.LAT_mvp[2*i,0]:.5f}, Longitude: {self.LON_mvp[2*i,0]:.5f}, Date/Heure: {self.DATETIME_mvp[i]}")
691
+ print(f" Profil down {2*i} - Profil up {2*i+1} - Latitude: {self.Lat_mvp[2*i,0]:.5f}, Longitude: {self.Lon_mvp[2*i,0]:.5f}, Date/Heure: {self.DATETIME_mvp[i]}")
691
692
 
692
693
  if self.ctd:
693
694
  print('CTD data:')
@@ -731,8 +732,8 @@ class Analyzer:
731
732
  self.PH_mvp = self.PH_mvp[l_id,:]
732
733
  self.SALT_mvp = self.SALT_mvp[l_id,:]
733
734
  self.TIME_mvp = self.TIME_mvp[l_id,:]
734
- self.LAT_mvp = self.LAT_mvp[l_id,:]
735
- self.LON_mvp = self.LON_mvp[l_id,:]
735
+ self.Lat_mvp = self.Lat_mvp[l_id,:]
736
+ self.Lon_mvp = self.Lon_mvp[l_id,:]
736
737
  self.DATETIME_mvp = np.array(self.DATETIME_mvp)[l_id2]
737
738
  self.DIR = np.array(self.DIR)[l_id]
738
739
  self.label_mvp = np.array(self.label_mvp)[l_id]
@@ -751,7 +752,7 @@ class Analyzer:
751
752
  self.SALT_ctd = self.SALT_ctd[l_id,:]
752
753
  self.COND_ctd = self.COND_ctd[l_id,:]
753
754
  self.TURB_ctd = self.TURB_ctd[l_id,:]
754
- self.OXY_ctd = self.OXY_ctd[l_id,:]
755
+ self.DO_ctd = self.DO_ctd[l_id,:]
755
756
  self.FLUO_ctd = self.FLUO_ctd[l_id,:]
756
757
  self.CDOM_ctd = self.CDOM_ctd[l_id,:]
757
758
  self.LAT_ctd = self.LAT_ctd[l_id,:]
@@ -834,7 +835,7 @@ class Analyzer:
834
835
 
835
836
  put_label = True
836
837
  c = 0
837
- for i in range(0,self.LAT_mvp.shape[0],2):
838
+ for i in range(0,self.Lat_mvp.shape[0],2):
838
839
  if i>0:
839
840
  if self.label_mvp[i] == self.label_mvp[i-1]:
840
841
  put_label = False
@@ -842,8 +843,8 @@ class Analyzer:
842
843
  put_label = True
843
844
  c+=1
844
845
 
845
- lat = self.LAT_mvp[i,0] if self.LAT_mvp.ndim == 2 else self.LAT_mvp[i]
846
- lon = self.LON_mvp[i,0] if self.LON_mvp.ndim == 2 else self.LON_mvp[i]
846
+ lat = self.Lat_mvp[i,0] if self.Lat_mvp.ndim == 2 else self.Lat_mvp[i]
847
+ lon = self.Lon_mvp[i,0] if self.Lon_mvp.ndim == 2 else self.Lon_mvp[i]
847
848
  ax.scatter(lon, lat, color=colors[c], marker='o', label='MVP '+self.label_mvp[i] if put_label else "", transform=ccrs.PlateCarree())
848
849
 
849
850
  # CTD
@@ -925,8 +926,8 @@ class Analyzer:
925
926
  plt.plot(self.DO_mvp[id_mvp],self.PRES_mvp[id_mvp],label='MVP down')
926
927
  plt.plot(self.DO_mvp[id_mvp+1],self.PRES_mvp[id_mvp+1],label='MVP up')
927
928
  if self.ctd:
928
- plt.plot(self.OXY_ctd[id_ctd],self.PRES_ctd[id_ctd],label='CTD down')
929
- plt.plot(self.OXY_ctd[id_ctd+1],self.PRES_ctd[id_ctd+1],label='CTD up')
929
+ plt.plot(self.DO_ctd[id_ctd],self.PRES_ctd[id_ctd],label='CTD down')
930
+ plt.plot(self.DO_ctd[id_ctd+1],self.PRES_ctd[id_ctd+1],label='CTD up')
930
931
  plt.legend()
931
932
  plt.gca().invert_yaxis()
932
933
  plt.grid()
@@ -1073,7 +1074,7 @@ class Analyzer:
1073
1074
 
1074
1075
  TEMP_ctd_interp = mvp.vertical_interp(self.PRES_ctd[id_ctd1,:],self.TEMP_ctd[id_ctd1,:], pressure_grid)
1075
1076
  SALT_ctd_interp = mvp.vertical_interp(self.PRES_ctd[id_ctd1,:],self.SALT_ctd[id_ctd1,:], pressure_grid)
1076
- DO_ctd_interp = mvp.vertical_interp(self.PRES_ctd[id_ctd1,:],self.OXY_ctd[id_ctd1,:], pressure_grid)
1077
+ DO_ctd_interp = mvp.vertical_interp(self.PRES_ctd[id_ctd1,:],self.DO_ctd[id_ctd1,:], pressure_grid)
1077
1078
  COND_ctd_interp = mvp.vertical_interp(self.PRES_ctd[id_ctd1,:],self.COND_ctd[id_ctd1,:], pressure_grid)
1078
1079
 
1079
1080
  # differences study between MVP down and CTD profiles
@@ -1256,7 +1257,7 @@ class Analyzer:
1256
1257
  print(f" MVP down: {rmse_cond_down:.4f} S/m (deep: {rmse_cond_down_deep:.4f} S/m)")
1257
1258
  print(f" MVP up: {rmse_cond_up:.4f} S/m (deep: {rmse_cond_up_deep:.4f} S/m)")
1258
1259
 
1259
- def correct_oxygen(self,id_mvp=None,id_ctd=None,num_sample=500,plotting=False,):
1260
+ def correct_oxygen(self,id_mvp=None,id_ctd=None,plotting=False,):
1260
1261
  """
1261
1262
  Apply oxygen correction to MVP dissolved oxygen profiles thanks to CTD data.
1262
1263
  Args:
@@ -1278,63 +1279,65 @@ class Analyzer:
1278
1279
  id_ctd = id_mvp
1279
1280
 
1280
1281
 
1281
- # Interpolate MVP and CTD data to match pressure levels
1282
- pmin = np.nanmin(self.PRES_mvp)
1283
- pmax = np.nanmax(self.PRES_mvp)
1284
- pressure_grid = np.linspace(pmin, pmax, num_sample)
1285
-
1282
+ if hasattr(self,'DO_mvp_corr_interp') == False:
1283
+ raise ValueError("Please run the interpolation method first to create the DO_mvp_corr_interp attribute.")
1284
+
1286
1285
 
1287
- DO_mvp_interp = mvp.vertical_interp(self.PRES_mvp[id_mvp,:], self.DO_mvp[id_mvp,:], pressure_grid)
1288
- DO_ctd_interp = mvp.vertical_interp(self.PRES_ctd[id_ctd,:],self.OXY_ctd[id_ctd,:], pressure_grid)
1286
+ oxy_mvp = self.DO_mvp_corr_interp[id_mvp]
1287
+ oxy_ctd = self.DO_ctd_interp[id_ctd]
1288
+ pres = self.PRES_mvp_corr_interp[id_mvp]
1289
1289
 
1290
- mask = ~np.isnan(DO_mvp_interp) & ~np.isnan(DO_ctd_interp)
1291
- pressure_grid = pressure_grid[mask[0]]
1292
- DO_mvp_interp = DO_mvp_interp[mask]
1293
- DO_ctd_interp = DO_ctd_interp[mask]
1290
+ mask = ~np.isnan(oxy_mvp) & ~np.isnan(oxy_ctd)
1291
+ oxy_mvp = oxy_mvp[mask]
1292
+ oxy_ctd = oxy_ctd[mask]
1293
+ pres = pres[mask]
1294
1294
 
1295
- diff = DO_mvp_interp-DO_ctd_interp
1295
+ diff = oxy_mvp - oxy_ctd
1296
1296
 
1297
- A = np.vstack([pressure_grid, np.ones_like(pressure_grid)]).T
1298
- print(A.shape, diff.shape)
1297
+ A = np.vstack([oxy_ctd, np.ones(len(oxy_ctd))]).T
1299
1298
  diff = diff.flatten()
1300
- a_estime, b_estime = np.linalg.lstsq(A, diff, rcond=None)[0]
1301
-
1302
- print(f"Pente estimée (a) : {a_estime:.6f} ")
1303
- print(f"Biais estimé (b) : {b_estime:.6f} ")
1304
1299
 
1305
- DO_mvp_corr = DO_mvp_interp - (a_estime*pressure_grid + b_estime)
1300
+ a_estim, b_estim = np.linalg.lstsq(A, diff, rcond=None)[0]
1301
+ print(f"Estimated linear relationship: diff = {a_estim:.4f} * oxy_ctd + {b_estim:.4f}")
1306
1302
 
1303
+ Do_mvp_corr = self.DO_mvp_corr_interp[id_mvp] - (a_estim * self.DO_ctd_interp[id_ctd] + b_estim)
1307
1304
 
1308
1305
 
1309
- rmse_before = np.sqrt(np.nanmean((DO_mvp_interp - DO_ctd_interp)**2))
1310
- rmse_after = np.sqrt(np.nanmean((DO_mvp_corr - DO_ctd_interp)**2))
1311
- print(f"RMSE before correction: {rmse_before:.4f}")
1312
- print(f"RMSE after correction: {rmse_after:.4f}")
1313
-
1314
- DO_mvp_corr_full = self.DO_mvp - (a_estime*self.PRES_mvp + b_estime)
1315
-
1316
- DO_mvp_corr_full_interp = mvp.vertical_interp(self.PRES_mvp, DO_mvp_corr_full, pressure_grid)
1317
- rmse_after_full = np.mean(np.sqrt(np.nanmean((DO_mvp_corr_full_interp - DO_ctd_interp)**2,axis=1)))
1318
- print(f"RMSE after correction (full profile): {rmse_after_full:.4f}")
1319
-
1320
- self.DO_mvp_raw = self.DO_mvp.copy()
1321
- self.DO_mvp = DO_mvp_corr_full
1306
+ rmse_before = np.sqrt(np.nanmean((self.DO_mvp_corr_interp[id_mvp] - self.DO_ctd_interp[id_ctd])**2))
1307
+ rmse_after = np.sqrt(np.nanmean((Do_mvp_corr - self.DO_ctd_interp[id_ctd])**2))
1308
+ if plotting:
1309
+ print(f"RMSE before correction: {rmse_before:.4f}")
1310
+ print(f"RMSE after correction: {rmse_after:.4f}")
1322
1311
 
1323
1312
 
1324
1313
  if plotting:
1325
1314
 
1326
- plt.figure()
1327
- plt.plot(DO_mvp_interp,pressure_grid,label='MVP')
1328
- plt.plot(DO_ctd_interp,pressure_grid,label='CTD')
1329
- plt.plot(DO_mvp_corr,pressure_grid,label='MVP corrected')
1315
+ plt.figure(figsize=(6,8))
1316
+ plt.plot(oxy_mvp, pres, label='MVP DO')
1317
+ plt.plot(Do_mvp_corr[mask],pres,label='MVP DO corrigé')
1318
+ plt.plot(oxy_ctd, pres, label='CTD DO')
1330
1319
  plt.gca().invert_yaxis()
1331
- plt.xlabel('Dissolved Oxygen, %')
1332
- plt.ylabel('Pressure, dbar')
1333
- plt.title('Oxygen correction')
1320
+ plt.xlabel('Oxygène dissous [µmol/kg]')
1321
+ plt.ylabel('Profondeur [m]')
1322
+ plt.title(f'Profil de DO - Profil {id_mvp} MVP vs Profil {id_ctd} CTD')
1334
1323
  plt.legend()
1335
- plt.grid()
1336
1324
  plt.show()
1337
1325
 
1326
+ self.DO_mvp_corr_interp[id_mvp] = Do_mvp_corr
1327
+
1328
+
1329
+ def correct_oxygen_all(self,mode):
1330
+
1331
+
1332
+
1333
+ for id_mvp in range(0,self.PRES_mvp.shape[0]):
1334
+
1335
+ id_nearest_ctd = mvp.find_nearest_profile(self.TIME_mvp_corr_interp[id_mvp],self.Lat_mvp_corr_interp[id_mvp], self.Lon_mvp_corr_interp[id_mvp],self.TIME_ctd ,self.LAT_ctd, self.LON_ctd,mode)[0]
1336
+ print(id_mvp,id_nearest_ctd)
1337
+ self.correct_oxygen(id_mvp=id_mvp, id_ctd=id_nearest_ctd, plotting=False)
1338
+
1339
+ print("Oxygen correction applied to all MVP profiles using nearest CTD profiles.")
1340
+
1338
1341
 
1339
1342
  def mvp_correction(self,high_cutoff=1,dp=0.1):
1340
1343
 
@@ -1437,7 +1440,7 @@ class Analyzer:
1437
1440
  self.PRES_ctd_interp = mvp.vertical_interp(self.PRES_ctd, self.PRES_ctd, pressure_grid)
1438
1441
  self.COND_ctd_interp = mvp.vertical_interp(self.PRES_ctd, self.COND_ctd, pressure_grid)
1439
1442
  self.SALT_ctd_interp = mvp.vertical_interp(self.PRES_ctd, self.SALT_ctd, pressure_grid)
1440
- self.DO_ctd_interp = mvp.vertical_interp(self.PRES_ctd, self.OXY_ctd, pressure_grid)
1443
+ self.DO_ctd_interp = mvp.vertical_interp(self.PRES_ctd, self.DO_ctd, pressure_grid)
1441
1444
  self.FLUO_ctd_interp = mvp.vertical_interp(self.PRES_ctd, self.FLUO_ctd, pressure_grid)
1442
1445
  self.TURB_ctd_interp = mvp.vertical_interp(self.PRES_ctd, self.TURB_ctd, pressure_grid)
1443
1446
  self.TEMP_mvp_corr_interp = mvp.vertical_interp(PRES_mvp_corr_mat, TEMP_mvp_corr_mat, pressure_grid)
@@ -1633,9 +1636,9 @@ class Analyzer:
1633
1636
 
1634
1637
  # Position and time arrays (2D)
1635
1638
  if hasattr(self, 'LAT_mvp'):
1636
- add_var('LATITUDE', self.LAT_mvp, units='degrees_north', long_name='Latitude at sample')
1639
+ add_var('LATITUDE', self.Lat_mvp, units='degrees_north', long_name='Latitude at sample')
1637
1640
  if hasattr(self, 'LON_mvp'):
1638
- add_var('LONGITUDE', self.LON_mvp, units='degrees_east', long_name='Longitude at sample')
1641
+ add_var('LONGITUDE', self.Lon_mvp, units='degrees_east', long_name='Longitude at sample')
1639
1642
  # Time seconds since reference
1640
1643
  data_vars['TIME'] = (
1641
1644
  ('profile', 'sample'), time_seconds,
@@ -1710,11 +1713,11 @@ class Analyzer:
1710
1713
 
1711
1714
  if hasattr(self, 'LAT_mvp'):
1712
1715
  coords['profile_lat'] = (
1713
- 'profile', first_valid(self.LAT_mvp), {'units': 'degrees_north', 'long_name': 'Profile latitude'}
1716
+ 'profile', first_valid(self.Lat_mvp), {'units': 'degrees_north', 'long_name': 'Profile latitude'}
1714
1717
  )
1715
1718
  if hasattr(self, 'LON_mvp'):
1716
1719
  coords['profile_lon'] = (
1717
- 'profile', first_valid(self.LON_mvp), {'units': 'degrees_east', 'long_name': 'Profile longitude'}
1720
+ 'profile', first_valid(self.Lon_mvp), {'units': 'degrees_east', 'long_name': 'Profile longitude'}
1718
1721
  )
1719
1722
 
1720
1723
  # Global attributes
@@ -1796,7 +1799,7 @@ class Analyzer:
1796
1799
 
1797
1800
  """
1798
1801
 
1799
- if self.hasattr('PRES_mvp_corr_interp') == False:
1802
+ if hasattr(self, 'PRES_mvp_corr_interp') == False:
1800
1803
  raise ValueError("Corrected and interpolated MVP data not available. Apply corrections and interpolation first.")
1801
1804
 
1802
1805
  if l_id is None:
@@ -1908,9 +1911,9 @@ class Analyzer:
1908
1911
  ax.invert_yaxis()
1909
1912
  ax.set_xlabel("Distance le long du transect [km]")
1910
1913
  ax.set_ylabel("Profondeur [m]")
1911
- ax.set_title("Transect de température (interpolé)")
1914
+ ax.set_title(f"{var} transect (interpolated)")
1912
1915
  cbar = plt.colorbar(pcm, ax=ax)
1913
- cbar.set_label("Température [°C]")
1916
+ cbar.set_label(f"{var} (units)")
1914
1917
  plt.show()
1915
1918
 
1916
1919
 
@@ -1074,3 +1074,55 @@ def align_profiles(P, T_ref, T_to_align_raw, min_depth=0,max_shift=20):
1074
1074
  T_out[T_out_indices[mask_corrected]] = T_corrected[mask_corrected]
1075
1075
 
1076
1076
  return T_out, deltaP, deltaT
1077
+
1078
+
1079
+
1080
+
1081
+ def find_nearest_profile(time_mvp,Lat_mvp,Lon_mvp,time_ctd,Lat_ctd,Lon_ctd,mode):
1082
+
1083
+ if mode=='Dist':
1084
+ idx = len(Lat_mvp)//2
1085
+ Lat_mvp = np.radians(Lat_mvp[idx])
1086
+ Lon_mvp = np.radians(Lon_mvp[idx])
1087
+
1088
+ R = 6371.0
1089
+
1090
+ min_dist = np.inf
1091
+ nearest_index = -1
1092
+
1093
+ for i in range(len(Lat_ctd)):
1094
+
1095
+ lat,lon = np.radians(Lat_ctd[i]), np.radians(Lon_ctd[i])
1096
+ mask = np.isfinite(lat) & np.isfinite(lon)
1097
+ lat,lon = lat[mask], lon[mask]
1098
+ lat,lon = lat[0],lon[0]
1099
+
1100
+ dlon = lon - Lon_mvp
1101
+ dlat = lat - Lat_mvp
1102
+ a = np.sin(dlat / 2)**2 + np.cos(Lat_mvp) * np.cos(lat) * np.sin(dlon / 2)**2
1103
+ c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
1104
+ dist = R * c * 1e3 # Convert to meters
1105
+ if dist < min_dist:
1106
+ min_dist = dist
1107
+ nearest_index = i
1108
+
1109
+
1110
+ return nearest_index, min_dist
1111
+
1112
+ elif mode=='Time':
1113
+ time_mvp = time_mvp[len(time_mvp)//2] # Take the middle time of the MVP cycle as reference
1114
+
1115
+ min_time_diff = np.inf
1116
+ nearest_index = -1
1117
+ for i in range(len(time_ctd)):
1118
+ time_diff = np.abs(time_ctd[i,-1] - time_mvp)
1119
+ if time_diff < min_time_diff:
1120
+ min_time_diff = time_diff
1121
+ nearest_index = i
1122
+ return nearest_index, min_time_diff
1123
+
1124
+ else:
1125
+ raise ValueError("Mode should be 'Dist' or 'Time'")
1126
+
1127
+
1128
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyMVP
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Python package for Moving Vessel Profiler correction and analysis
5
5
  Author: MaximilienWemaere
6
6
  Requires-Python: >=3.10
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "PyMVP"
3
- version = "0.2.3"
3
+ version = "0.2.4"
4
4
  description = "Python package for Moving Vessel Profiler correction and analysis"
5
5
  authors = [{name="MaximilienWemaere"}]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes