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.
- {pymvp-0.2.3 → pymvp-0.2.4}/PKG-INFO +1 -1
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP/main.py +76 -73
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP/mvp_routines.py +52 -0
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP.egg-info/PKG-INFO +1 -1
- {pymvp-0.2.3 → pymvp-0.2.4}/pyproject.toml +1 -1
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP/__init__.py +0 -0
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP.egg-info/SOURCES.txt +0 -0
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP.egg-info/dependency_links.txt +0 -0
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP.egg-info/requires.txt +0 -0
- {pymvp-0.2.3 → pymvp-0.2.4}/PyMVP.egg-info/top_level.txt +0 -0
- {pymvp-0.2.3 → pymvp-0.2.4}/setup.cfg +0 -0
|
@@ -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.
|
|
118
|
-
self.
|
|
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.
|
|
297
|
-
self.
|
|
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.
|
|
345
|
-
self.
|
|
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.
|
|
485
|
-
self.
|
|
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.
|
|
551
|
-
self.
|
|
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
|
-
|
|
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
|
-
|
|
607
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
735
|
-
self.
|
|
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.
|
|
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.
|
|
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.
|
|
846
|
-
lon = self.
|
|
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.
|
|
929
|
-
plt.plot(self.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
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
|
-
|
|
1288
|
-
|
|
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(
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
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 =
|
|
1295
|
+
diff = oxy_mvp - oxy_ctd
|
|
1296
1296
|
|
|
1297
|
-
A = np.vstack([
|
|
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
|
-
|
|
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((
|
|
1310
|
-
rmse_after = np.sqrt(np.nanmean((
|
|
1311
|
-
|
|
1312
|
-
|
|
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(
|
|
1328
|
-
plt.plot(
|
|
1329
|
-
plt.plot(
|
|
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('
|
|
1332
|
-
plt.ylabel('
|
|
1333
|
-
plt.title('
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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("
|
|
1914
|
+
ax.set_title(f"{var} transect (interpolated)")
|
|
1912
1915
|
cbar = plt.colorbar(pcm, ax=ax)
|
|
1913
|
-
cbar.set_label("
|
|
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
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|