From 6b4880fc14441934c6a4f9df8fac36f84dcec4d1 Mon Sep 17 00:00:00 2001
From: Tristan Harmel <tristan.harmel@get.omp.eu>
Date: Tue, 12 Mar 2019 11:06:30 +0100
Subject: [PATCH] add 'run' file for swr, define output format

---
 build/lib/process/process.py            | 225 ++++++++++++++++++++----
 build/lib/process/process_compar_awr.py |  49 ++++--
 build/lib/process/process_test_setup.py |   2 +-
 build/lib/utils/utils.py                | 100 ++++++-----
 build/lib/visu/data_visu.py             |  73 ++++----
 process/run_iwr.py                      |  16 +-
 process/run_swr.py                      |  86 +++++++++
 setup.py                                |   2 +-
 trios.egg-info/PKG-INFO                 |   2 +-
 trios.egg-info/SOURCES.txt              |   6 +
 trios.egg-info/requires.txt             |   3 +
 trios.egg-info/top_level.txt            |   2 +
 12 files changed, 419 insertions(+), 147 deletions(-)
 create mode 100644 process/run_swr.py

diff --git a/build/lib/process/process.py b/build/lib/process/process.py
index 6e6f4a7..3c25eb7 100644
--- a/build/lib/process/process.py
+++ b/build/lib/process/process.py
@@ -1,11 +1,14 @@
 import numpy as np
 import pandas as pd
-import scipy.interpolate as si
+from scipy import interpolate, integrate
+from scipy.optimize import curve_fit
+
 import plotly.plotly as py
 # import plotly.graph_objs as go
 from plotly.graph_objs import *
 
 from utils.utils import reshape as r
+import utils.auxdata as ua
 from config import *
 
 
@@ -30,25 +33,33 @@ class awr_process:
         self.rhoM1999.dropna(inplace=True)
         self.rhoM2015.dropna(inplace=True)
 
-    def get_rho_values(self, sza, vza, azi, ws=2, aot=0.1, wl=[550]):
+    def get_rho_values(self, sza, vza, azi, ws=[2], aot=[0.1], wl=[550], sunglint=False):
         '''
-
-        :param sza:
-        :param vza:
-        :param azi:
-        :param ws:
-        :param aot:
-        :param wl:
+        Interpolate the rho factor values from tabulated data
+
+        :param sza: solar zenith angle in deg, array-like
+        :param vza: view zenith angle in deg, array-like
+        :param azi: relative azimuth in deg (=0 when looking at Sun), array-like
+        :param ws: wind speed, m/s,(based on Cox-Munk parametrization of surface roughness) array-like
+        :param aot: aerosol optical thickness at 550 nm, array-like
+        :param wl: wavelength in nm, array-like
+        :param sunglint: add sunglint component in rho calculation if True
         :return:
         '''
 
+        grid = self.rho.rho.index.levels
 
-
-        grid = self.rho.rho.index.levels[2:]
         # convert pandas dataframe into 6D array of the tabulated rho values for interpolation
-        rho_ = r().df2ndarray(self.rho, 'rho')
+        rhoname = 'rho'
+        if sunglint:
+            rhoname = 'rho_g'
+
+        rho_6d = r().df2ndarray(self.rho, rhoname)
+
+        rho_ = calc().spline_2d(grid[-2:], rho_6d, (azi, vza))
+
+        rho_wl = calc().spline_4d(grid[:-2], rho_, (ws, aot, wl, sza))
 
-        rho_wl = calc().spline_4d(grid, rho_[1, 1, ...], (wl, sza, azi, vza))
         return rho_wl.squeeze()
 
     def get_rho_mobley(self, rhodf, sza, vza, azi, ws):
@@ -78,10 +89,13 @@ class awr_process:
         Lt = self.df.loc[:, ("Lt")]
         Lsky = self.df.loc[:, ("Lsky")]
         Ed = self.df.loc[:, ("Ed")]
-        sza = self.df.loc[:, ("sza")]
-        return self.process(wl, Lt, Lsky, Ed, sza, vza, azi, ws, aot)
+        sza = self.df.loc[:, ("sza")].values.mean()
+        Rrs = self.process(wl, Lt, Lsky, Ed, sza, vza, azi, ws, aot)
+        Rrs.columns = pd.MultiIndex.from_product([['Rrs(awr)'], self.Rrs.columns], names=['param', 'wl'])
+        self.Rrs = Rrs
+        return self.Rrs
 
-    def process(self, wl, Lt, Lsky, Ed, sza, vza=[40], azi=[135], ws=2, aot=0.1):
+    def process(self, wl, Lt, Lsky, Ed, sza, vza=[40], azi=[135], ws=[2], aot=[0.1]):
         '''
 
         :param wl:
@@ -96,9 +110,8 @@ class awr_process:
         :return:
         '''
 
-        rho = self.get_rho_values([sza.values.mean()],vza,azi,wl=wl )
+        rho = self.get_rho_values([sza], vza, azi, wl=wl, ws=ws, aot=aot)
         self.Rrs = (Lt - rho * Lsky) / Ed
-        self.Rrs.columns = pd.MultiIndex.from_product([['Rrs(awr)'], self.Rrs.columns], names=['param', 'wl'])
 
         return self.Rrs, rho
 
@@ -108,13 +121,78 @@ class swr_process:
         self.df = df
         self.wl = wl
 
-    def process(self):
+    def call_process(self, shade_corr=False):
         wl = self.wl
-        df = self.df
-
-        Rrs = df.loc[:, ("Lu0+")] / df.loc[:, ("Ed")]
+        Lu = self.df.loc[:, ("Lu0+")]
+        Ed = self.df.loc[:, ("Ed")]
+        sza = self.df.loc[:, ("sza")].values.mean()
+        Rrs = self.process(Lu, Ed, sza, wl, shade_corr=shade_corr)
         Rrs.columns = pd.MultiIndex.from_product([['Rrs(swr)'], Rrs.columns], names=['param', 'wl'])
         self.Rrs = Rrs
+        return Rrs
+
+    def process(self, Lu, Ed, sza, wl, R=0.05, shade_corr=False):
+        Rrs = Lu / Ed
+        ang_w = calc().angle_w(sza)
+
+        iopw = ua.iopw()
+        iopw.load_iopw()
+        iopw.get_iopw(wl)
+        a, bb = iopw.aw, iopw.bbw
+        # TODO add particulate and dissolved component to a and bb values
+        # a,bb = aux.get_iop(..., withwater=True)
+        acdom = ua.cdom(0.5, wl).get_acdom()
+        a = a + acdom + 0.4
+        bb = bb + 0.05
+        if shade_corr:
+            Rrs = self.shade_corr(Rrs, R, ang_w, a, bb, wl)
+        # Rrs.columns = pd.MultiIndex.from_product([['Rrs(swr)'], Rrs.columns], names=['param', 'wl'])
+        self.Rrs = Rrs
+        self.a = a
+        self.bb = bb
+        self.acdom = acdom
+        return self.Rrs
+
+    def epsilon(self, K, R, ang_w):
+        '''
+        epsilon from Shang et al, 2017, Applied Optics
+        :param K:
+        :param R:
+        :param ang_w: Sun zenith angle below surface (in deg)
+        :return:
+        '''
+
+        self.eps = np.array(1 - np.exp(-K * R / np.tan(np.radians(ang_w))))
+        return self.eps
+
+    def K(self, a, bb, ang_w):
+        '''
+        K (sum attenuation coef. of Lu in and outside the shade) from Shang et al, 2017, Applied Optics
+        :param a: total absorption coefficient (m-1)
+        :param bb: total backscattering coefficient (m-1)
+        :param ang_w: Sun zenith angle below surface (in deg)
+        :return:
+        '''
+        sin_ang_w = np.sin(np.radians(ang_w))
+        self.K_ = (3.15 * sin_ang_w + 1.15) * a * np.exp(-1.57 * bb) \
+                  + (5.62 * sin_ang_w - 0.23) * bb * np.exp(-0.5 * a)
+        return self.K_
+
+    def shade_corr(self, Rrs, R, ang_w, a, bb, wl, wl_cutoff=900):
+        '''
+        Correction of shading error from Shang et al, 2017, Applied Optics
+        :param Rrs:
+        :param R:
+        :param ang_w:
+        :param a:
+        :param bb:
+        :return:
+        '''
+
+        K = self.K(a, bb, ang_w)
+        eps = self.epsilon(K, R, ang_w)
+        eps[wl > wl_cutoff] = 0
+        self.Rrs = Rrs / (1 - eps)
         return self.Rrs
 
 
@@ -127,18 +205,33 @@ class iwr_process:
         wl = self.wl
         df = self.df
 
-        Rrs = df.loc[:, ("Lu0+")] / df.loc[:, ("Ed")]
-        Rrs.columns = pd.MultiIndex.from_product([['Rrs(swr)'], Rrs.columns], names=['param', 'wl'])
-        self.Rrs = Rrs
-        return self.Rrs
+        reflectance = df.loc[:, ("Luz")] / df.loc[:, ("Edz")]
+        reflectance.columns = pd.MultiIndex.from_product([['reflectance'], reflectance.columns], names=['param', 'wl'])
+        self.reflectance = reflectance
+
+        df['rounded_depth', ''] = df.prof_Edz.round(1)
+        df.groupby('rounded_depth').mean()
+
+        return self.reflectance
+
+    @staticmethod
+    def f_Edz(depth, Kd, Ed0):
+        '''simple Edz model for homogeneous water column'''
+        return Ed0 * np.exp(-Kd*depth)
+
+    @staticmethod
+    def f_logEdz(depth, Kd, Ed0):
+        '''simple Edz model for homogeneous water column'''
+        return np.log(1 + iwr_process.f_Edz(depth, Kd, Ed0)) #Ed0) -Kd*depth
+
 
     def Kd(self, depth, Edz):
         Kd = np.diff(Edz) / np.diff(depth)
 
-    def plot_raw(self):
+    def plot_raw(self,x='Luz',y='prof_Luz'):
         trace = Scattergl(
-            x=self.df['Luz'].values,
-            y=self.df['depth_Luz'].values,
+            x=self.df[x].values,
+            y=self.df[y].values,
 
             text=self.df.index.get_level_values(0),
             hoverinfo="text",
@@ -172,8 +265,8 @@ class iwr_process:
                 title=''
             ),
             yaxis=dict(
-                range=[min(-5, min(self.df['depth_Luz'])),
-                       max(0, max(self.df['depth_Luz']))],
+                range=[min(-5, min(self.df[y])),
+                       max(0, max(self.df[y]))],
                 showline=False,
                 fixedrange=True,
                 zeroline=False,
@@ -200,7 +293,7 @@ class self_shading:
         self.eps_dif_EuZ = 2.70
 
     def epsilon(self, sza):
-        eps = si.interp1d(self.ang, self.eps_dif_EuZ)(sza)
+        eps = interpolate.interp1d(self.ang, self.eps_dif_EuZ)(sza)
         return eps
 
 
@@ -208,6 +301,33 @@ class calc:
     def __init__(self):
         pass
 
+    def PAR(self, wl, Ed):
+        '''
+        Compute instantaneous PAR from Ed spectrum.
+        PAR in mW m-2
+        PAR_quanta in µmol photon m-2 s-1
+        :param wl:
+        :param Ed:
+        :return:
+        '''
+        # ---------------------------------------------
+        #      PARAMETERS
+        # Planck constant in J s or W s2
+        h = 6.6260695729e-3  # d-34
+        # light speed in m s-1
+        c = 2.99792458e0  # d8
+        # Avogadro Number in mol-1
+        Avogadro = 6.0221412927e0  # d23
+        hc = Avogadro * h * c
+        # ---------------------------------------------
+
+        idx_par = (wl >= 400) & (wl <= 700)
+        wl = wl[idx_par]
+        Ed = Ed[idx_par]
+        par = integrate.trapz(Ed, wl)
+        par_quanta = integrate.trapz(np.multiply(wl,Ed), wl) / hc
+        return par, par_quanta
+
     def earth_sun_correction(self, dayofyear):
         '''
         Earth-Sun distance correction factor for adjustment of mean solar irradiance
@@ -226,6 +346,40 @@ class calc:
 
         return bidir
 
+    def angle_w(self, angle_air, n=1.334):
+        '''
+        convert above surface angle (angle_air) into sub-surface angle
+        :param angle_air in deg
+        :param n: refractive index of water
+        :return: sub-surface angle in deg
+        '''
+        return np.degrees(np.arcsin(np.sin(np.radians(angle_air)) / n))
+
+    def spline_2d(self, gin, arr, gout):
+        '''
+        Interpolation of a 6D array (arr) with bicubic splines on a 2D grid
+        corresponding to the 5th and 6th dimensions of arr.
+        Return 4D array interpolated on gout.
+
+        :param gin: regular 2D grid of the tabulated data (tuple/array/list of arrays)
+        :param arr: tabulated data (N dimensions, interpolation on N-1 and N)
+        :param gout: new 2D grid on which data are interpolated (with dims 2 and 3 of the same length);
+                    (tuple/array/list of arrays)
+        :return: Interpolated data (1D or 3D array depending on the dimension shapes of gout
+        '''
+
+        N = arr.shape
+        interp = np.zeros(N[:-2])
+
+        for i in range(N[0]):
+            for j in range(N[1]):
+                for k in range(N[2]):
+                    for l in range(N[3]):
+                        interp[i, j, k, l] = interpolate.RectBivariateSpline(gin[0], gin[1], arr[i, j, k, l, ...])(
+                            gout[0], gout[1], grid=False)
+
+        return interp
+
     def spline_4d(self, gin, lut, gout):
         '''
         Interpolation with two successive bicubic splines on a regular 4D grid.
@@ -239,7 +393,6 @@ class calc:
                     (tuple/array/list of arrays)
         :return: Interpolated data (1D or 3D array depending on the dimension shapes of gout
         '''
-        import scipy.interpolate as si
 
         N = gin[0].__len__(), gin[1].__len__(), gin[2].__len__(), gin[3].__len__()
         Nout = gout[0].__len__(), gout[1].__len__(), gout[2].__len__()
@@ -247,15 +400,15 @@ class calc:
 
         for i in range(N[0]):
             for j in range(N[1]):
-                tmp[i, j, :] = si.RectBivariateSpline(gin[2], gin[3], lut[i, j, :, :])(gout[2], gout[3], grid=False)
+                tmp[i, j, :] = interpolate.RectBivariateSpline(gin[2], gin[3], lut[i, j, :, :])(gout[2], gout[3], grid=False)
         if Nout[0] == Nout[1] == 1:
             interp = np.ndarray(Nout[2])
             for iband in range(Nout[2]):
-                interp[iband] = si.RectBivariateSpline(gin[0], gin[1], tmp[:, :, iband])(gout[0], gout[1], grid=False)
+                interp[iband] = interpolate.RectBivariateSpline(gin[0], gin[1], tmp[:, :, iband])(gout[0], gout[1], grid=False)
         else:
             interp = np.ndarray([Nout[0], Nout[1], Nout[2]])
             for iband in range(Nout[2]):
-                interp[:, :, iband] = si.RectBivariateSpline(gin[0], gin[1], tmp[:, :, iband])(gout[0], gout[1],
+                interp[:, :, iband] = interpolate.RectBivariateSpline(gin[0], gin[1], tmp[:, :, iband])(gout[0], gout[1],
                                                                                                grid=True)
 
         return interp
diff --git a/build/lib/process/process_compar_awr.py b/build/lib/process/process_compar_awr.py
index 9ccfa92..6fae7a2 100644
--- a/build/lib/process/process_compar_awr.py
+++ b/build/lib/process/process_compar_awr.py
@@ -13,6 +13,7 @@ from scipy.interpolate import interp1d
 
 from utils.sunposition import sunpos
 import utils.utils as u
+import utils.auxdata as ua
 from process.process import *
 
 coordf = glob.glob("/DATA/OBS2CO/data/info/mesures_in_situ.csv")[0]
@@ -23,6 +24,8 @@ awrfiles = glob.glob("/DATA/OBS2CO/data/trios/raw/aw*idpr*.csv")
 # awrfiles = glob.glob("/DATA/OBS2CO/data/trios/test_setup/raw/aw*idpr*.csv")
 swrfiles = glob.glob("/DATA/OBS2CO/data/trios/raw/Lu0*idpr*.csv")
 
+iopw = ua.iopw()
+iopw.load_iopw()
 
 def add_curve(ax, x, mean, std, c='red', label=''):
     ax.plot(x, mean, linestyle='solid', c=c, lw=2.5,
@@ -36,7 +39,7 @@ idpr = '167'
 
 # get idpr numbers
 idprs = np.unique([re.findall(r'idpr(\d+)', x)[0] for x in swrfiles])
-idprs = np.array(['156'])
+#idprs = np.array(['170'])
 # loop over idpr
 for idpr in idprs:
     c = coords[coords.ID_prel == int(idpr)]  # .values[0]
@@ -52,23 +55,29 @@ for idpr in idprs:
     #   SWR processing
     # -----------------------------------------------
 
-    swr = u.swr_data(idpr, swrfiles)
-    if swr.file:
-        df, wl_swr = swr.reader(lat, lon, alt)
-        Rrs_swr = swr_process(df, wl_swr).process()
-    add_curve(ax, wl_swr, Rrs_swr.transpose().mean(axis=1), Rrs_swr.transpose().std(axis=1), label='swr', c='black')
-
+    uswr = u.swr_data(idpr, swrfiles)
+    if uswr.file:
+        df, wl_swr = uswr.reader(lat, lon, alt)
+        df['sza', ''] = np.nan
+        for index, row in df.iterrows():
+            # print index
+            sza = sunpos(index, lat, lon, alt)[1]
+            df.at[index, 'sza'] = sza
+        swr = swr_process(df, wl_swr)
+        Rrs_swr = swr.call_process()
+        add_curve(ax, wl_swr, Rrs_swr.transpose().mean(axis=1), Rrs_swr.transpose().std(axis=1), label='swr', c='black')
+        Rrs_swr = swr.call_process(shade_corr=True)
+        add_curve(ax, wl_swr, Rrs_swr.transpose().mean(axis=1), Rrs_swr.transpose().std(axis=1), label='swr', c='red')
 
     # -----------------------------------------------
     #   AWR processing
     # -----------------------------------------------
+    azi = 135
+    vza = 40
     awr = u.awr_data(idpr, awrfiles)
     if awr.Edf:
 
-
         index_idx = [0]
-        azi = 135
-        vza = 40
 
         d = u.data(index_idx)
         Ed, wl_Ed = d.load_csv(awr.Edf)
@@ -115,9 +124,9 @@ for idpr in idprs:
             sza = sunpos(index, lat, lon, alt)[1]
             df.at[index, 'sza'] = sza
 
-        rho_h = awr.get_rho_values([df.sza.min()], [vza], [azi], wl=wl)
-        rho15 = awr.get_rho_mobley(awr.rhoM2015, [df.sza.min()], [vza], [azi], [ws])
-        rho99 = awr.get_rho_mobley(awr.rhoM1999, [df.sza.min()], [vza], [azi], [ws])
+        rho_h = awr.get_rho_values([df.sza.mean()], [vza], [azi], wl=wl)
+        rho15 = awr.get_rho_mobley(awr.rhoM2015, [df.sza.mean()], [vza], [azi], [ws])
+        rho99 = awr.get_rho_mobley(awr.rhoM1999, [df.sza.mean()], [vza], [azi], [ws])
 
         Rrs_h = (df.loc[:, 'Lt'] - rho_h * df.loc[:, 'Lsky']) / df.loc[:, 'Ed']
         Rrs15 = (df.loc[:, 'Lt'] - rho15 * df.loc[:, 'Lsky']) / df.loc[:, 'Ed']
@@ -125,12 +134,14 @@ for idpr in idprs:
         Rrs99 = (df.loc[:, 'Lt'] - rho99 * df.loc[:, 'Lsky']) / df.loc[:, 'Ed']
         # plt.figure()
 
-        add_curve(ax, wl, Rrs15.transpose().mean(axis=1), Rrs15.transpose().std(axis=1), label='M2015')
-        add_curve(ax, wl, Rrs99.transpose().mean(axis=1), Rrs99.transpose().std(axis=1), c='orange', label='M1999')
-        add_curve(ax, wl, Rrs_h.transpose().mean(axis=1), Rrs_h.transpose().std(axis=1), c='grey', label='h')
+        add_curve(ax, wl, Rrs15.transpose().mean(axis=1), Rrs15.transpose().std(axis=1),
+                  label='M2015 (' + str(rho15) + ')')
+        add_curve(ax, wl, Rrs99.transpose().mean(axis=1), Rrs99.transpose().std(axis=1), c='orange',
+                  label='M1999(' + str(rho99) + ')')
+        add_curve(ax, wl, Rrs_h.transpose().mean(axis=1), Rrs_h.transpose().std(axis=1), c='grey',
+                  label='h(' + str(rho_h.mean()) + ')')
 
-
-    ax.set_title('azi=' + str(azi) + ', vza=' + str(vza)+', sza='+str(sza))
+    ax.set_title('azi=' + str(azi) + ', vza=' + str(vza) + ', sza=' + str(sza))
 
     ax.legend(loc='best', frameon=False)
 
@@ -138,4 +149,4 @@ for idpr in idprs:
     ax.set_xlabel(r'Wavelength (nm)')
     fig.savefig(os.path.join(dirfig, 'trios_awr_' + name + '_idpr' + idpr + '.png'))
     plt.close()
-    Lt.index.names
+
diff --git a/build/lib/process/process_test_setup.py b/build/lib/process/process_test_setup.py
index 55d6cae..b3bf378 100644
--- a/build/lib/process/process_test_setup.py
+++ b/build/lib/process/process_test_setup.py
@@ -71,7 +71,7 @@ fig.subplots_adjust(left=0.1, right=0.9, hspace=.5, wspace=0.65)
 i=0
 for azi, Lt1 in Lt0.groupby(level=2):
     for vza,Lt in Lt1.groupby(level=1):
-        ax=axs.flat[i]
+        ax = axs.flat[i]
         i=i+1
         print(azi,vza)
 
diff --git a/build/lib/utils/utils.py b/build/lib/utils/utils.py
index a2b7bca..53ecc69 100644
--- a/build/lib/utils/utils.py
+++ b/build/lib/utils/utils.py
@@ -10,7 +10,7 @@ class awr_data:
     Above-water radiometry
     '''
 
-    def __init__(self, idpr, files):
+    def __init__(self, idpr=None, files=None):
         # ''' get file names for Ed, Lsky and Lt data'''
         self.file = list(filter(lambda x: 'idpr' + idpr in x, files))
         file = self.file
@@ -41,7 +41,7 @@ class awr_data:
         df = pd.DataFrame()
 
         # ''' read files with pandas format '''
-        d=data(index_idx)
+        d = data(index_idx)
         Ed, wl_Ed = d.load_csv(self.Edf)
         Lsky, wl_Lsky = d.load_csv(self.Lskyf)
         Lt, wl_Lt = d.load_csv(self.Ltf)
@@ -90,7 +90,7 @@ class iwr_data:
         self.Luzf = list(filter(lambda x: 'Luz' in x, file))
         self.idpr = idpr
 
-    def reader(self, lat=None, lon=None, alt=0, name=''):
+    def reader(self, lat, lon, alt=0, name='', delta_Lu_depth=0, delta_Edz_depth=0):
         '''
         Read above-water data files for a given acquisition series (idpr),
         merge the different data types:
@@ -105,6 +105,9 @@ class iwr_data:
         :param lat: latitude (decimal)
         :param lon: longitude (decimal)
         :param alt: altitude (m)
+        :param delta_Lu_depth: adjustment of actual depth for Lu sensor (distance from depth sensor);
+                               in meters for depth counted positively
+        :param delta_Edz_depth: similar to delta_Lu_depth for Edz sensor
         :param idpr: ID of the acquisition series
         :return:
         '''
@@ -112,29 +115,42 @@ class iwr_data:
         df = pd.DataFrame()
 
         # ''' read files with pandas format '''
-        Ed, wl_Ed = self.load_csv(self.Edf)
-        Edz, wl_Edz = self.load_csv(self.Edzf)
-        Luz, wl_Luz = self.load_csv(self.Luzf)
+        d = data([1, 0])
+
+        Ed, wl_Ed = d.load_csv(self.Edf)
+        Edz, wl_Edz = d.load_csv(self.Edzf)
+        Luz, wl_Luz = d.load_csv(self.Luzf)
+
+        #mask negative values TODO save number of discarded data
+        # Ed.mask(Ed<0,inplace=True)
+        # Edz.mask(Edz<0,inplace=True)
+        # Luz.mask(Luz<0,inplace=True)
+
+
 
         # copy depth data to Ed frame on date index
-        Ed.index = Ed.index.droplevel(level=1)
+        # Ed.index = Ed.index.droplevel(level=1)
 
-        # ''' interpolate Ed and Lsky data upon Lt wavelength'''
+        #''' interpolate Ed and Lsky data upon Lt wavelength'''
         wl = wl_Luz
-        Luz.columns = pd.MultiIndex.from_tuples(zip(['Luz'] * len(wl), wl), names=['param', 'wl'])
+        Luz.columns = pd.MultiIndex.from_tuples(list(zip(['Luz'] * len(wl), wl)), names=['param', 'wl'])
         intEd = interp1d(wl_Ed, Ed.values, fill_value='extrapolate')(wl)
-        newEd = pd.DataFrame(index=Ed.index,
-                             columns=pd.MultiIndex.from_tuples(zip(['Ed'] * len(wl), wl), names=['param', 'wl']),
+        newEd = pd.DataFrame(index=Ed.index.get_level_values(0),
+                             columns=pd.MultiIndex.from_tuples(list(zip(['Ed'] * len(wl), wl)), names=['param', 'wl']),
                              data=intEd)
         intEdz = interp1d(wl_Edz, Edz.values, fill_value='extrapolate')(wl)
-        newEdz = pd.DataFrame(index=Edz.index, columns=pd.MultiIndex.from_tuples(zip(['Edz'] * len(wl), wl),
+        newEdz = pd.DataFrame(index=Edz.index, columns=pd.MultiIndex.from_tuples(list(zip(['Edz'] * len(wl), wl)),
                                                                                  names=['param', 'wl']), data=intEdz)
 
-        # merge sensor data on time
+        # correct depth data for sensor to sensor distance
         Luz.reset_index(level=1, inplace=True)
+        Luz.iloc[:, 0] = Luz.iloc[:, 0] + delta_Lu_depth
         # newEd.reset_index(level=1,inplace=True)
 
         newEdz.reset_index(level=1, inplace=True)
+        newEdz.iloc[:, 0] = newEdz.iloc[:, 0] + delta_Edz_depth
+
+        # merge sensor data on time
         df = pd.merge_asof(Luz, newEd, left_index=True, right_index=True, tolerance=pd.Timedelta("2 seconds"),
                            direction="nearest")
         df = pd.merge_asof(df, newEdz, left_index=True, right_index=True, suffixes=('_Luz', '_Edz'),
@@ -150,26 +166,26 @@ class iwr_data:
             df.at[index, 'sza'] = sza
 
         df['idpr', ''] = self.idpr
-        df['name', ''] = self.name
+        df['name', ''] = name
 
         return df, wl
 
-    def load_csv(self, file):
-
-        dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
-        if len(file) > 1:
-            print('Warning! Multiple files found but only one expected, process first file of the list:')
-            print(file)
-        file = file[0]
-        df = pd.read_csv(file, sep=';', index_col=[1, 0], na_values=['-NAN'])
-        df = df.dropna(axis=1, how='all').dropna(axis=0, how='all')
-        df.index = df.index.set_levels([pd.to_datetime(df.index.levels[0]), df.index.levels[1]])
-        df.columns = df.columns.astype('float')  # str.extract('(\d+)',expand=False).astype('float')
-        # resort to get data in increasing time order
-        df.sort_index(inplace=True, level=0)
-        wl = df.columns
-
-        return df, wl
+    # def load_csv(self, file):
+    #
+    #     dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
+    #     if len(file) > 1:
+    #         print('Warning! Multiple files found but only one expected, process first file of the list:')
+    #         print(file)
+    #     file = file[0]
+    #     df = pd.read_csv(file, sep=';', index_col=[1, 0], na_values=['-NAN'])
+    #     df = df.dropna(axis=1, how='all').dropna(axis=0, how='all')
+    #     df.index = df.index.set_levels([pd.to_datetime(df.index.levels[0]), df.index.levels[1]])
+    #     df.columns = df.columns.astype('float')  # str.extract('(\d+)',expand=False).astype('float')
+    #     # resort to get data in increasing time order
+    #     df.sort_index(inplace=True, level=0)
+    #     wl = df.columns
+    #
+    #     return df, wl
 
 
 class swr_data:
@@ -235,28 +251,28 @@ class swr_data:
 
 
 class data:
-    def __init__(self,index_idx=[0]):
+    def __init__(self, index_idx=[0]):
         # first position should be datetime index
         # followed by the other parameters used for indexing (e.g. azimuth, view angle)
-        self.index_idx=index_idx
+        self.index_idx = index_idx
         pass
 
     def load_csv(self, file):
+        print(file)
         dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
         if len(file) > 1:
-            print( 'Warning! Multiple files found but only one expected, process first file of the list:')
+            print('Warning! Multiple files found but only one expected, process first file of the list:')
             print(file)
-        file = file[0]
-        #df = pd.read_csv(file, date_parser=dateparse, sep=';', index_col=0, na_values=['-NAN'])
-        df=pd.read_csv(file, sep=';', na_values=['-NAN'])
-        df = df.dropna(axis=1, how='all').dropna(axis=0, how='all')
-
-        #get list of indexes
-        col=df.columns.values[self.index_idx]
-        df[col[0]]=pd.to_datetime(df[col[0]])
+        file_ = file[0]
+        # df = pd.read_csv(file, date_parser=dateparse, sep=';', index_col=0, na_values=['-NAN'])
+        df = pd.read_csv(file_, sep=';', na_values=['-NAN'])
 
-        df.set_index(col.tolist(),inplace=True)
+        # get list of indexes
+        col = df.columns.values[self.index_idx]
+        df[col[0]] = pd.to_datetime(df[col[0]])
 
+        df.set_index(col.tolist(), inplace=True)
+        df = df.dropna(axis=1, how='all').dropna(axis=0, how='all')
         df.columns = df.columns.astype('float')  # str.extract('(\d+)',expand=False).astype('float')
         # resort to get data in increasing time order
         df.sort_index(inplace=True)
diff --git a/build/lib/visu/data_visu.py b/build/lib/visu/data_visu.py
index 72a35f8..539a7b0 100644
--- a/build/lib/visu/data_visu.py
+++ b/build/lib/visu/data_visu.py
@@ -13,6 +13,7 @@ import pandas as pd
 import plotly.graph_objs as go
 from dash.dependencies import Input, Output
 
+
 def main():
     app = dash.Dash()
     # app.css.append_css('data/aeronet_layout.css')
@@ -58,9 +59,9 @@ def main():
                    'width': '100%', 'display': 'inline-block',
                    }),
         html.Div([
-            html.H4('File...', id='filename',style={'float': 'left','width': '60%'}),
+            html.H4('File...', id='filename', style={'float': 'left', 'width': '60%'}),
             html.Div([
-                html.H4('Color variable:',style={'margin-bottom': '0','width':'50%'}),
+                html.H4('Color variable:', style={'margin-bottom': '0', 'width': '50%'}),
                 html.Div([
                     dcc.Dropdown(
                         id='color-column',
@@ -73,7 +74,7 @@ def main():
                     #     value='Linear',
                     #     labelStyle={'width': '25%','display': 'inline-block'})],
                 ],
-                style={'width': '50%','display': 'inline-block'})],
+                    style={'width': '50%', 'display': 'inline-block'})],
                 style={'width': '40%',
                        'margin-top': '0',
                        'display': 'inline-block',
@@ -101,8 +102,8 @@ def main():
                     value='Lt'),
             ],
                 style={'width': '48.9%',
-                       'float': 'right', }),],
-            style={'width':'100%','margin-block-start': '1%'}),
+                       'float': 'right', }), ],
+            style={'width': '100%', 'margin-block-start': '1%'}),
 
         html.Div([
             html.Div([
@@ -123,7 +124,7 @@ def main():
                        }),
         ],
 
-             style={'height': '20%'},
+            style={'height': '20%'},
             # className='row'
         ),
 
@@ -191,27 +192,26 @@ def main():
             'margin-left': 'auto',
             'margin-right': 'auto'})
 
-
     def figure_spectrum(df, column_name, color_column_name):
         dff = df
-        layout = go.Layout( xaxis={'title': 'Wavelength (nm)'},
-                            yaxis={'title': column_name},
-                            margin={'l': 50, 'b': 40, 't': 20, 'r': 50},
-                            hovermode='closest',
-                            height=300,
-                            font=dict(color='#CCCCCC'),
-                            titlefont=dict(color='#CCCCCC', size=14),
-                            plot_bgcolor="#191A1A",
-                            paper_bgcolor="#020202")
-
-        if not(column_name in dff.columns.get_level_values(0)):
-            return  {'data': [],
-                     'layout': layout}
+        layout = go.Layout(xaxis={'title': 'Wavelength (nm)'},
+                           yaxis={'title': column_name},
+                           margin={'l': 50, 'b': 40, 't': 20, 'r': 50},
+                           hovermode='closest',
+                           height=300,
+                           font=dict(color='#CCCCCC'),
+                           titlefont=dict(color='#CCCCCC', size=14),
+                           plot_bgcolor="#191A1A",
+                           paper_bgcolor="#020202")
+
+        if not (column_name in dff.columns.get_level_values(0)):
+            return {'data': [],
+                    'layout': layout}
 
         parameters = df.loc[:, (color_column_name)].values
         dff = dff.loc[:, ([column_name])]
         wl = dff.columns.droplevel().values
-        dff = dff.stack(level=['wl'])
+        #dff = dff.stack(level=['wl'])
         norm = mpl.colors.Normalize(vmin=np.nanmin(parameters), vmax=np.nanmax(parameters))
         # create a ScalarMappable and initialize a data structure
         cmap = cm.Spectral
@@ -219,11 +219,14 @@ def main():
         s_m.set_array([])
         i = 0
         trace = []
-        for date, x in dff.groupby(level=0):
+        #for date, x_ in dff.groupby(level=0):
+        for idx, x in dff.iterrows():
+            date = x.name.__str__()
+            #print(idx,x)
             trace.append(go.Scattergl(
                 x=wl,  # spectrum,
-                y=x[column_name].values.flatten(),
-                text=dff.index.get_level_values(0),
+                y=x[column_name],
+                text=date,#str(parameters[i]),#dff.index.get_level_values(0),
                 name=str(parameters[i]),
                 mode='lines',
                 marker={
@@ -244,7 +247,6 @@ def main():
             'layout': layout
         }
 
-
     def list_data(contents, level=0):
         # content_type, content_string = contents.split(',')
         # decoded = base64.b64decode(content_string)
@@ -253,6 +255,7 @@ def main():
         # remove useless variables
         c = c.drop(filter(lambda s: re.match('.*(Wave|Tri|[sS]ite|Dat)', s), c))
         return [{'label': i, 'value': i} for i in c]
+
     #
     def parse_contents(contents):
         global df
@@ -275,7 +278,6 @@ def main():
         parse_contents(contents)
         return contents
 
-
     @app.callback(Output('filename', 'children'),
                   [Input('upload-data', 'filename')])
     def show_filename(filename):
@@ -289,68 +291,59 @@ def main():
     def update_dropdown(contents):
         return list_data(contents)
 
-
     @app.callback(Output('spectrum1', 'options'),
                   [Input('dataset', 'children')])
     def update_dropdown(contents):
         return list_data(contents, level=0)
 
-
     @app.callback(Output('spectrum2', 'options'),
                   [Input('dataset', 'children')])
     def update_dropdown(contents):
         return list_data(contents, level=0)
 
-
     @app.callback(Output('spectrum3', 'options'),
                   [Input('dataset', 'children')])
     def update_dropdown(contents):
         return list_data(contents, level=0)
 
-
     @app.callback(Output('spectrum4', 'options'),
                   [Input('dataset', 'children')])
     def update_dropdown(contents):
         return list_data(contents, level=0)
 
-
     # selection from time series graph -> spectrum graph
     @app.callback(Output('graph1', 'figure'),
                   [Input('spectrum1', 'value'),
                    Input('color-column', 'value'),
                    Input('dataset', 'children')])
-    def spectrum_figure(column_name, color_column_name,void):
+    def spectrum_figure(column_name, color_column_name, void):
         return figure_spectrum(df, column_name, color_column_name)
 
-
     # selection from time series graph -> spectrum graph
     @app.callback(Output('graph2', 'figure'),
                   [Input('spectrum2', 'value'),
                    Input('color-column', 'value'),
                    Input('dataset', 'children')])
-    def spectrum_figure(column_name, color_column_name,void):
+    def spectrum_figure(column_name, color_column_name, void):
         return figure_spectrum(df, column_name, color_column_name)
 
-
     @app.callback(Output('graph3', 'figure'),
                   [Input('spectrum3', 'value'),
                    Input('color-column', 'value'),
                    Input('dataset', 'children')])
-    def spectrum_figure(column_name, color_column_name,void):
+    def spectrum_figure(column_name, color_column_name, void):
         return figure_spectrum(df, column_name, color_column_name)
 
-
     # selection from time series graph -> spectrum graph
     @app.callback(Output('graph4', 'figure'),
                   [Input('spectrum4', 'value'),
                    Input('color-column', 'value'),
                    Input('dataset', 'children')])
-    def spectrum_figure(column_name, color_column_name,void):
+    def spectrum_figure(column_name, color_column_name, void):
         return figure_spectrum(df, column_name, color_column_name)
 
-
     app.run_server(port=8060)
 
+
 if __name__ == "__main__":
     main()
-
diff --git a/process/run_iwr.py b/process/run_iwr.py
index e5d120e..357695a 100644
--- a/process/run_iwr.py
+++ b/process/run_iwr.py
@@ -32,7 +32,7 @@ class fit:
 # ------------------------------------------------
 # above-water data files
 dirfig = os.path.abspath('/DATA/OBS2CO/data/trios/fig')
-dirout = os.path.abspath('/DATA/OBS2CO/data/trios/above_water')
+dirout = os.path.abspath('/DATA/OBS2CO/data/trios/in_water')
 
 iwrfiles = glob.glob("/DATA/OBS2CO/data/trios/raw/uw*idpr*.csv")
 
@@ -42,6 +42,14 @@ coords
 # get idpr numbers
 idprs = np.unique([re.findall(r'idpr(\d+)', x)[0] for x in iwrfiles])
 
+
+def add_curve(ax, x, mean, std, c='red', label=''):
+    ax.plot(x, mean, linestyle='solid', c=c, lw=2.5,
+            alpha=0.8, label=label)
+    ax.fill_between(x,
+                    mean - std,
+                    mean + std, alpha=0.35, color=c)
+
 ################
 # load aux data
 iopw = ua.iopw()
@@ -142,12 +150,6 @@ for idpr in idprs:#[-1:]:
         plt.close()
 
 
-        def add_curve(ax, x, mean, std, c='red', label=''):
-            ax.plot(x, mean, linestyle='solid', c=c, lw=2.5,
-            alpha=0.8, label=label)
-            ax.fill_between(x,
-                    mean - std,
-                    mean + std, alpha=0.35, color=c)
 
         mpl.rcParams.update({'font.size': 18})
         fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(15, 6))
diff --git a/process/run_swr.py b/process/run_swr.py
new file mode 100644
index 0000000..4d6f25c
--- /dev/null
+++ b/process/run_swr.py
@@ -0,0 +1,86 @@
+import base64
+import pandas as pd
+import numpy as np
+import glob
+import io
+import os
+from textwrap import dedent as d
+import re
+import matplotlib.pyplot as plt
+import plotly
+import plotly.graph_objs as go
+from scipy.interpolate import interp1d
+
+from utils.sunposition import sunpos
+import utils.utils as u
+import utils.auxdata as ua
+from process.process import *
+
+plot=False
+odir = os.path.abspath('/DATA/OBS2CO/data/trios/surface_water')
+coordf = glob.glob("/DATA/OBS2CO/data/info/mesures_in_situ.csv")[0]
+coords = pd.read_csv(coordf, sep=';')
+coords['Date_prel']=pd.to_datetime(coords['Date_prel'])
+
+dirfig = os.path.abspath('/DATA/OBS2CO/data/trios/fig')
+
+awrfiles = glob.glob("/DATA/OBS2CO/data/trios/raw/aw*idpr*.csv")
+# awrfiles = glob.glob("/DATA/OBS2CO/data/trios/test_setup/raw/aw*idpr*.csv")
+swrfiles = glob.glob("/DATA/OBS2CO/data/trios/raw/Lu0*idpr*.csv")
+
+iopw = ua.iopw()
+iopw.load_iopw()
+
+def add_curve(ax, x, mean, std, c='red', label=''):
+    ax.plot(x, mean, linestyle='solid', c=c, lw=2.5,
+            alpha=0.8, label=label)
+    ax.fill_between(x,
+                    mean - std,
+                    mean + std, alpha=0.35, color=c)
+
+
+idpr = '167'
+
+# get idpr numbers
+idprs = np.unique([re.findall(r'idpr(\d+)', x)[0] for x in swrfiles])
+#idprs = np.array(['170'])
+# loop over idpr
+for idpr in idprs:
+    c = coords[coords.ID_prel == int(idpr)]  # .values[0]
+    date=c['Date_prel'].dt.strftime('%Y%m%d')
+    lat = c['Lat'].values[0]
+    lon = c['Lon'].values[0]
+    alt = 0  # c['Altitude']
+    name = c['ID_lac'].values[0]
+
+    ofile=os.path.join(odir,'Rrs_swr_idpr'+idpr+'_'+name+'_'+date.values[0]+'.csv')
+    header = c.stack()
+    header.index = header.index.droplevel()
+    header.to_csv(ofile, header=None)
+
+
+
+    # -----------------------------------------------
+    #   SWR processing
+    # -----------------------------------------------
+
+    uswr = u.swr_data(idpr, swrfiles)
+    if uswr.file:
+        df, wl_swr = uswr.reader(lat, lon, alt)
+        df['sza', ''] = np.nan
+        for index, row in df.iterrows():
+            # print index
+            sza = sunpos(index, lat, lon, alt)[1]
+            df.at[index, 'sza'] = sza
+        swr = swr_process(df, wl_swr)
+        Rrs_swr = swr.call_process()
+        Rrs_stat = Rrs_swr.describe()
+        Rrs_stat.columns=Rrs_stat.columns.droplevel()
+        Rrs_stat = Rrs_stat.T
+        Rrs_stat.to_csv(ofile,mode='a')
+        if plot:
+            fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(10, 8))
+            fig.subplots_adjust(left=0.1, right=0.9, hspace=.5, wspace=0.65)
+            add_curve(ax, wl_swr, Rrs_swr.transpose().mean(axis=1), Rrs_swr.transpose().std(axis=1), label='swr', c='black')
+            Rrs_swr = swr.call_process(shade_corr=True)
+            add_curve(ax, wl_swr, Rrs_swr.transpose().mean(axis=1), Rrs_swr.transpose().std(axis=1), label='swr', c='red')
diff --git a/setup.py b/setup.py
index 422fe17..e450da8 100644
--- a/setup.py
+++ b/setup.py
@@ -19,7 +19,7 @@ setup(
     author_email='tristan.harmel@ntymail.com',
     description='Package to help process TriOS radiometer data for various above-water or in-water setups',
     # TODO update Dependent packages (distributions)
-    install_requires=['pandas', 'scipy', 'numpy', 'netCDF4', 'matplotlib', 'docopt', 'GDAL', 'python-dateutil'],
+    install_requires=['dash','dash_core_components','dash_html_components','pandas', 'scipy', 'numpy', 'netCDF4', 'matplotlib', 'docopt', 'GDAL', 'python-dateutil'],
 
     entry_points={
         'console_scripts': [
diff --git a/trios.egg-info/PKG-INFO b/trios.egg-info/PKG-INFO
index de2f375..2dce818 100644
--- a/trios.egg-info/PKG-INFO
+++ b/trios.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: trios
-Version: 1.1.0
+Version: 1.1.1
 Summary: Package to help process TriOS radiometer data for various above-water or in-water setups
 Home-page: https://gitlab.irstea.fr/ETL-TELQUEL/etl/tree/dev/preprocessing/trios
 Author: T. Harmel
diff --git a/trios.egg-info/SOURCES.txt b/trios.egg-info/SOURCES.txt
index 9bd76c5..bd300bd 100644
--- a/trios.egg-info/SOURCES.txt
+++ b/trios.egg-info/SOURCES.txt
@@ -1,9 +1,13 @@
 README.md
 setup.py
+aux/__init__.py
+aux/sensors_spec.py
 process/__init__.py
 process/process.py
 process/process_compar_awr.py
+process/process_sabine.py
 process/process_test_setup.py
+process/run_iwr.py
 simulation/__init__.py
 simulation/rho_snapshot.py
 trios.egg-info/PKG-INFO
@@ -12,8 +16,10 @@ trios.egg-info/dependency_links.txt
 trios.egg-info/entry_points.txt
 trios.egg-info/requires.txt
 trios.egg-info/top_level.txt
+utils/DBtrios.py
 utils/DButils.py
 utils/__init__.py
+utils/auxdata.py
 utils/format_info4acix.py
 utils/sunposition.py
 utils/utils.py
diff --git a/trios.egg-info/requires.txt b/trios.egg-info/requires.txt
index 25ab4e9..a424c23 100644
--- a/trios.egg-info/requires.txt
+++ b/trios.egg-info/requires.txt
@@ -1,3 +1,6 @@
+dash
+dash_core_components
+dash_html_components
 pandas
 scipy
 numpy
diff --git a/trios.egg-info/top_level.txt b/trios.egg-info/top_level.txt
index 14f0538..60bfdba 100644
--- a/trios.egg-info/top_level.txt
+++ b/trios.egg-info/top_level.txt
@@ -1,3 +1,5 @@
+aux
+build
 process
 simulation
 utils
-- 
GitLab