Example #1
0
def add_psal(netCDFfile):
    ds = Dataset(netCDFfile, 'a')

    var_temp = ds.variables["TEMP"]
    var_psal = ds.variables["PSAL"]
    var_pres = ds.variables["PRES"]

    t = var_temp[:]
    SP = var_psal[:]
    p = var_pres[:]

    SA = gsw.SA_from_SP(SP, p, ds.longitude, ds.latitude)
    pt = gsw.pt0_from_t(SA, t, p)

    oxsol = gsw.O2sol_SP_pt(SP, pt)

    ncVarOut = ds.createVariable("OXSOL", "f4", ("TIME",), fill_value=np.nan, zlib=True)  # fill_value=nan otherwise defaults to max
    ncVarOut[:] = oxsol
    ncVarOut.units = "umol/kg"
    ncVarOut.comment = "calculated using gsw-python https://teos-10.github.io/GSW-Python/index.html function gsw.O2sol_SP_pt"

    # update the history attribute
    try:
        hist = ds.history + "\n"
    except AttributeError:
        hist = ""

    ds.setncattr('history', hist + datetime.utcnow().strftime("%Y-%m-%d") + " : added oxygen solubility")

    ds.close()
Example #2
0
    def _compute_data(self,data, units, names, p_ref = 0, baltic = False, lon=0, lat=0, isen = '0'):
        """ Computes convservative temperature, absolute salinity and potential density from input data, expects a recarray with the following entries data['C']: conductivity in mS/cm, data['T']: in Situ temperature in degree Celsius (ITS-90), data['p']: in situ sea pressure in dbar
        
        Arguments:
           p_ref: Reference pressure for potential density
           baltic: if True use the Baltic Sea density equation instead of open ocean
           lon: Longitude of ctd cast default=0
           lat: Latitude of ctd cast default=0
        Returns:
           list [cdata,cunits,cnames] with cdata: recarray with entries 'SP', 'SA', 'pot_rho', etc., cunits: dictionary with units, cnames: dictionary with names 
        """
        sen = isen + isen
        # Check for units and convert them if neccessary
        if(units['C' + isen] == 'S/m'):
            logger.info('Converting conductivity units from S/m to mS/cm')
            Cfac = 10

        if(('68' in units['T' + isen]) or ('68' in names['T' + isen]) ):
            logger.info('Converting IPTS-68 to T90')
            T = gsw.t90_from_t68(data['T' + isen])
        else:
            T = data['T' + isen]
            
        SP = gsw.SP_from_C(data['C' + isen], T, data['p'])
        SA = gsw.SA_from_SP(SP,data['p'],lon = lon, lat = lat)
        if(baltic == True):
            SA = gsw.SA_from_SP_Baltic(SA,lon = lon, lat = lat)
            
        PT = gsw.pt0_from_t(SA, T, data['p'])
        CT = gsw.CT_from_t(SA, T, data['p'])        
        pot_rho                = gsw.pot_rho_t_exact(SA, T, data['p'], p_ref)
        names                  = ['SP' + sen,'SA' + sen,'pot_rho' + sen,'pt0' + sen,'CT' + sen]
        formats                = ['float','float','float','float','float']        
        cdata                  = {}
        cdata['SP' + sen]      = SP
        cdata['SA' + sen]      = SA
        cdata['pot_rho' + sen] = pot_rho
        cdata['pt' + sen]      = PT
        cdata['CT' + sen]      = CT
        cnames           = {'SA' + sen:'Absolute salinity','SP' + sen: 'Practical Salinity on the PSS-78 scale',
                            'pot_rho' + sen: 'Potential density',
                            'pt' + sen:'potential temperature with reference sea pressure (p_ref) = 0 dbar',
                            'CT' + sen:'Conservative Temperature (ITS-90)'}
       
        cunits = {'SA' + sen:'g/kg','SP' + sen:'PSU','pot_rho' + sen:'kg/m^3' ,'CT' + sen:'deg C','pt' + sen:'deg C'}
        
        return [cdata,cunits,cnames]
Example #3
0
def add_SA_CT_PT(xray):
    if 'PRES' in list(xray.data_vars):
        PRES_out = xray['PRES']
    else:
        PRES_out = -gsw.p_from_z(xray['DEPTH'])
    SA_out = gsw.SA_from_SP(xray['PSAL'], PRES_out, xray.LONGITUDE,
                            xray.LATITUDE)
    if 'PTMP' in list(xray.data_vars):
        PT_out = xray['PTMP']
    else:
        PT_out = gsw.pt0_from_t(SA_out, xray['TEMP'], PRES_out)
    CT_out = gsw.CT_from_pt(SA_out, PT_out)
    PD_out = gsw.sigma0(SA_out, CT_out)
    xray['ASAL'] = (('TIME', 'DEPTH'), SA_out)
    xray['PTMP'] = (('TIME', 'DEPTH'), PT_out)
    xray['CTMP'] = (('TIME', 'DEPTH'), CT_out)
    xray['PDEN'] = (('TIME', 'DEPTH'), PD_out)
Example #4
0
def oxygen(netCDFfile):
    ds = Dataset(netCDFfile, 'a')

    if 'DOX2_RAW' not in ds.variables:
        ds.close()
        return

    var_temp = ds.variables["TEMP"]
    var_psal = ds.variables["PSAL"]
    if 'PRES' in ds.variables:
        var_pres = ds.variables["PRES"]
        p = var_pres[:]
    elif 'NOMINAL_DEPTH' in ds.variables:
        var_pres = ds.variables["NOMINAL_DEPTH"]
        p = var_pres[:]
    else:
        p = 1.0

    t = var_temp[:]
    SP = var_psal[:]

    SA = gsw.SA_from_SP(SP, p, ds.variables["LONGITUDE"][0],
                        ds.variables["LATITUDE"][0])
    CT = gsw.CT_from_t(SA, t, p)
    pt = gsw.pt0_from_t(SA, t, p)

    sigma_theta0 = gsw.sigma0(SA, CT)

    ts = np.log((298.15 - t) / (273.15 + t))

    # psal correction, from Aanderra TD-218, Gordon and Garcia oxygaen solubility salinity coefficents, salinity coeff, col 5 combined fit (ml/l).
    B0 = -6.24097e-3
    C0 = -3.11680e-7
    B1 = -6.93498e-3
    B2 = -6.90358e-3
    B3 = -4.29155e-3

    psal_correction = np.exp(
        SP * (B0 + B1 * ts + B2 * np.power(ts, 2) + B3 * np.power(ts, 3)) +
        np.power(SP, 2) * C0)

    # get correction slope, offset
    slope = 1.0
    offset = 0.0
    try:
        slope = ds.variables['DOX2_RAW'].calibration_slope
        offset = ds.variables['DOX2_RAW'].calibration_offset
    except AttributeError:
        pass

    # calculate disolved oxygen, umol/kg
    dox2_raw = ds.variables['DOX2_RAW'] * psal_correction * slope + offset
    dox2 = 1000 * dox2_raw / (sigma_theta0 + 1000)
    #dox2 = dox2_raw

    if 'DOX2' not in ds.variables:
        ncVarOut = ds.createVariable(
            "DOX2", "f4", ("TIME", ), fill_value=np.nan,
            zlib=True)  # fill_value=nan otherwise defaults to max
    else:
        ncVarOut = ds.variables['DOX2']

    ncVarOut[:] = dox2
    ncVarOut.standard_name = "moles_of_oxygen_per_unit_mass_in_sea_water"
    ncVarOut.long_name = "moles_of_oxygen_per_unit_mass_in_sea_water"
    ncVarOut.units = "umol/kg"
    ncVarOut.comment1 = "calculated using DOX2_uM = DOX2_RAW * PSAL_CORRECTION .. Aanderaa TD210 Optode Manual (optode/SBE63 only)"
    ncVarOut.comment2 = "DOX2 = DOX2_uM / ((sigma_theta(P=0,Theta,S) + 1000).. Sea Bird AN 64 (unit conversion umol/l -> umol/kg)"
    ncVarOut.comment_calibration = "calibration slope " + str(
        slope) + " offset " + str(offset) + " umol/l"
    ncVarOut.coordinates = 'TIME LATITUDE LONGITUDE NOMINAL_DEPTH'

    # finish off, and close file

    # update the history attribute
    try:
        hist = ds.history + "\n"
    except AttributeError:
        hist = ""

    ds.setncattr(
        'history', hist + datetime.utcnow().strftime("%Y-%m-%d") +
        " added derived oxygen, DOX2")

    ds.close()

    return netCDFfile
Example #5
0
def process_all_new():

    ssscc_file = 'data/ssscc.csv'
    iniFile = 'data/ini-files/configuration.ini'
    config = configparser.RawConfigParser()
    config.read(iniFile)

    # maybe reformat config file?
    # fold this code into config module
    p_col = config['analytical_inputs']['p']
    p_btl_col = config['inputs']['p']
    t1_col = config['analytical_inputs']['t1']
    t1_btl_col = config['inputs']['t1']
    t2_col = config['analytical_inputs']['t2']
    t2_btl_col = config['inputs']['t2']
    c1_col = config['analytical_inputs']['c1']
    c1_btl_col = config['inputs']['c1']
    c2_col = config['analytical_inputs']['c2']
    c2_btl_col = config['inputs']['c2']
    sal_col = config['analytical_inputs']['salt']
    reft_col = config['inputs']['reft']
    sample_rate = config['ctd_processing']['sample_rate']
    search_time = config['ctd_processing']['roll_filter_time']

    expocode = config['cruise']['expocode']
    sectionID = config['cruise']['sectionid']
    raw_directory = config['ctd_processing']['raw_data_directory']
    time_directory = config['ctd_processing']['time_data_directory']
    pressure_directory = config['ctd_processing']['pressure_data_directory']
    oxygen_directory = config['ctd_processing']['oxygen_directory']
    btl_directory = config['ctd_processing']['bottle_directory']
    o2flask_file = config['ctd_processing']['o2flask_file']
    log_directory = config['ctd_processing']['log_directory']
    sample_rate = config['ctd_processing']['sample_rate']
    search_time = config['ctd_processing']['roll_filter_time']
    ctd = config['ctd_processing']['ctd_serial']

    # MK: import from settings/config instead of hard code?
    btl_data_prefix = 'data/bottle/'
    btl_data_postfix = '_btl_mean.pkl'
    time_data_prefix = 'data/time/'
    time_data_postfix = '_time.pkl'
    p_log_file = 'data/logs/ondeck_pressure.csv'
    t1_btl_col = 'CTDTMP1'
    t2_btl_col = 'CTDTMP2'
    t1_col = 'CTDTMP1'
    t2_col = 'CTDTMP2'
    p_btl_col = 'CTDPRS'
    p_col = 'CTDPRS'
    c1_btl_col = 'CTDCOND1'
    c2_btl_col = 'CTDCOND2'
    c1_col = 'CTDCOND1'
    c2_col = 'CTDCOND2'
    reft_col = 'T90'
    refc_col = 'BTLCOND'
    sal_col = 'CTDSAL'

    #time_column_data = config['time_series_output']['data_names'].split(',')
    time_column_data = config['time_series_output']['data_output']
    time_column_names = config['time_series_output']['column_name'].split(',')
    time_column_units = config['time_series_output']['column_units'].split(',')
    time_column_format = config['time_series_output']['format']

    #pressure_column_data = config['time_series_output']['data_names'].split(',')
    p_column_data = config['pressure_series_output']['data'].split(',')
    p_column_names = config['pressure_series_output']['column_name'].split(',')
    p_column_units = config['pressure_series_output']['column_units'].split(
        ',')
    p_column_format = config['pressure_series_output']['format']
    p_column_qual = config['pressure_series_output']['qual_columns'].split(',')
    p_column_one = list(
        config['pressure_series_output']['q1_columns'].split(','))

    # Columns from btl file to be read:
    cols = [
        'index', 'CTDTMP1', 'CTDTMP2', 'CTDPRS', 'CTDCOND1', 'CTDCOND2',
        'CTDSAL', 'CTDOXY1', 'CTDOXYVOLTS', 'CTDXMISS', 'ALT', 'REF_PAR',
        'GPSLAT', 'GPSLON', 'new_fix', 'pressure_temp_int', 'pump_on',
        'btl_fire', 'scan_datetime', 'btl_fire_num'
    ]

    # Load ssscc from file
    ssscc = []
    with open(ssscc_file, 'r') as filename:
        ssscc = [line.strip() for line in filename]

        #check for already converted files to skip later
    time_start = time.perf_counter()
    cnv_dir_list = os.listdir('data/converted/')
    time_dir_list = os.listdir('data/time/')

    for x in ssscc:
        if '{}.pkl'.format(x) in cnv_dir_list:
            continue
        #convert hex to ctd
        subprocess.run([
            'odf_convert_sbe.py', 'data/raw/' + x + '.hex',
            'data/raw/' + x + '.XMLCON', '-o', 'data/converted'
        ],
                       stdout=subprocess.PIPE)
        print('odf_convert_sbe.py SSSCC: ' + x + ' done')

    time_convert = time.perf_counter()

    for x in ssscc:
        if '{}_time.pkl'.format(x) in time_dir_list:
            continue
        subprocess.run(['odf_sbe_metadata.py', 'data/converted/' + x + '.pkl'],
                       stdout=subprocess.PIPE)
        print('odf_sbe_metadata.py SSSCC: ' + x + ' done')

    btl_dir_list = os.listdir('data/bottle/')
    for x in ssscc:
        if '{}_btl_mean.pkl'.format(x) in btl_dir_list:
            continue
        #process bottle file
        subprocess.run([
            'odf_process_bottle.py', 'data/converted/' + x + '.pkl', '-o',
            'data/bottle/'
        ],
                       stdout=subprocess.PIPE)
        print('odf_process_bottle.py SSSCC: ' + x + ' done')
    time_bottle = time.perf_counter()

    # generate salts file here: (salt parser)
    salt_dir = './data/salt/'
    import scripts.odf_salt_parser as salt_parser

    file_list = os.listdir(salt_dir)
    files = []
    for file in file_list:
        if '.' not in file:
            files.append(file)

    for file in files:
        print(file)
        salt_path = salt_dir + file
        saltDF = salt_parser.salt_loader(saltpath=salt_path)
        salt_parser.salt_df_parser(saltDF, salt_dir)

    # generate reft file here
    reft_path = './data/reft/'
    import scripts.odf_reft_parser as reft_parser
    for station in ssscc:
        with open(reft_path + station + '.cap', 'r') as ssscc_reftemp:
            # create csv files
            df_part = reft_parser.parse(ssscc_reftemp, station)

        df_part.to_csv(reft_path + station + '_reft.csv', index=False)

    # generate oxy file here (separate out from calib)

    ###########################################################################

    ### File I/O

    # Load in all bottle, time, ref_data files into DataFrame

    btl_data_all = process_ctd.load_all_ctd_files(ssscc, btl_data_prefix,
                                                  btl_data_postfix, 'bottle',
                                                  cols)
    time_data_all = process_ctd.load_all_ctd_files(ssscc, time_data_prefix,
                                                   time_data_postfix, 'time',
                                                   None)
    ##
    # end of data collection, begin calibration
    ################################################################################

    ### Pressure Calibration

    # Determine Pressure offset from logs

    pressure_log = process_ctd.load_pressure_logs(p_log_file)
    p_off = process_ctd.get_pressure_offset(
        pressure_log.ondeck_start_p,
        pressure_log.ondeck_end_p)  # insert logic to check if good value?

    btl_data_all = fit_ctd.apply_pressure_offset(
        btl_data_all, p_btl_col, p_off)  # not actually bottle data
    time_data_all = fit_ctd.apply_pressure_offset(time_data_all, p_col,
                                                  p_off)  # continuous data
    # btl_data_all[p_btl_col] = fit_ctd.apply_pressure_offset(btl_data_all[p_btl_col], p_off)
    # time_data_all[p_col] = fit_ctd.apply_pressure_offset(time_data_all[p_col],p_off)

    ###########################################################################

    ### Temperature Calibration
    for x in range(
            2):  # 2 passes checks for outliers twice (i.e. before/after fit)

        # Second order calibration

        df_temp_good = process_ctd.prepare_fit_data(btl_data_all, 'T90')

        df_ques_reft = process_ctd.quality_check(df_temp_good[t2_btl_col],
                                                 df_temp_good[t1_btl_col],
                                                 df_temp_good[p_btl_col],
                                                 df_temp_good['SSSCC'],
                                                 df_temp_good['btl_fire_num'],
                                                 'quest')
        df_ques_reft['Parameter'] = 'REF_TEMP'

        # sort out fit parameters, what order P, what order T
        # only fit `linear' regions, i.e. not mixed/benthic layers
        # built better way to handle xRange?
        coef_temp_1, df_ques_t1 = process_ctd.calibrate_param(
            df_temp_good[t1_btl_col],
            df_temp_good[reft_col],
            df_temp_good[p_btl_col],
            'TP',
            2,
            df_temp_good.SSSCC,
            df_temp_good.btl_fire_num,
            xRange='800:6000')
        coef_temp_2, df_ques_t2 = process_ctd.calibrate_param(
            df_temp_good[t2_btl_col],
            df_temp_good[reft_col],
            df_temp_good[p_btl_col],
            'TP',
            2,
            df_temp_good.SSSCC,
            df_temp_good.btl_fire_num,
            xRange='1500:6000')

        # Apply fitting coef to data

        btl_data_all[t1_btl_col] = fit_ctd.temperature_polyfit(
            btl_data_all[t1_btl_col], btl_data_all[p_btl_col], coef_temp_1)
        btl_data_all[t2_btl_col] = fit_ctd.temperature_polyfit(
            btl_data_all[t2_btl_col], btl_data_all[p_btl_col], coef_temp_2)

        time_data_all[t1_col] = fit_ctd.temperature_polyfit(
            time_data_all[t1_col], time_data_all[p_col], coef_temp_1)
        time_data_all[t2_col] = fit_ctd.temperature_polyfit(
            time_data_all[t2_col], time_data_all[p_col], coef_temp_2)

        # Construct Quality Flag file

        qual_flag_temp = process_ctd.combine_quality_flags(
            [df_ques_reft, df_ques_t1, df_ques_t2])

        ## First order calibtation

        df_temp_good = process_ctd.prepare_fit_data(btl_data_all, 'T90')

        #        df_ques_reft = process_ctd.quality_check(df_temp_good[t2_btl_col], df_temp_good[t1_btl_col], df_temp_good[p_btl_col], df_temp_good['SSSCC'], df_temp_good['btl_fire_num'], 'quest')
        #        df_ques_reft['Parameter'] = 'REF_TEMP'

        coef_temp_prim, df_ques_t1 = process_ctd.calibrate_param(
            df_temp_good[t1_btl_col], df_temp_good[reft_col],
            df_temp_good[p_btl_col], 'T', 1, df_temp_good.SSSCC,
            df_temp_good.btl_fire_num)
        coef_temp_sec, df_ques_t2 = process_ctd.calibrate_param(
            df_temp_good[t2_btl_col], df_temp_good[reft_col],
            df_temp_good[p_btl_col], 'T', 1, df_temp_good.SSSCC,
            df_temp_good.btl_fire_num)

        btl_data_all[t1_btl_col] = fit_ctd.temperature_polyfit(
            btl_data_all[t1_btl_col], btl_data_all[p_btl_col], coef_temp_prim)
        btl_data_all[t2_btl_col] = fit_ctd.temperature_polyfit(
            btl_data_all[t2_btl_col], btl_data_all[p_btl_col], coef_temp_sec)

        # Apply fitting coef to data

        btl_data_all[t1_btl_col] = fit_ctd.temperature_polyfit(
            btl_data_all[t1_btl_col], btl_data_all[p_btl_col], coef_temp_prim)
        btl_data_all[t2_btl_col] = fit_ctd.temperature_polyfit(
            btl_data_all[t2_btl_col], btl_data_all[p_btl_col], coef_temp_sec)

        time_data_all[t1_col] = fit_ctd.temperature_polyfit(
            time_data_all[t1_col], time_data_all[p_col], coef_temp_prim)
        time_data_all[t2_col] = fit_ctd.temperature_polyfit(
            time_data_all[t2_col], time_data_all[p_col], coef_temp_sec)

        qual_flag_temp = process_ctd.combine_quality_flags(
            [df_ques_reft, df_ques_t1, df_ques_t2])

    ###########################################################################

#
### Conductivity Calibration
    for x in range(2):
        # Update ref conductivity from salinometer

        btl_data_all['BTLCOND'] = fit_ctd.CR_to_cond(btl_data_all.CRavg,
                                                     btl_data_all.BathTEMP,
                                                     btl_data_all.CTDTMP1,
                                                     btl_data_all.CTDPRS)
        df_cond_good = process_ctd.prepare_fit_data(btl_data_all, 'BTLCOND')

        df_ques_refc = process_ctd.quality_check(df_cond_good['CTDCOND2'],
                                                 df_temp_good['CTDCOND1'],
                                                 df_temp_good['CTDPRS'],
                                                 df_temp_good['SSSCC'],
                                                 df_temp_good['btl_fire_num'],
                                                 'quest')
        df_ques_refc['Parameter'] = 'REF_COND'

        # Second Order Calibration

        # can probably use same xRange as temp, unless C sensor has some quirk
        coef_cond_1, df_ques_c1 = process_ctd.calibrate_param(
            df_cond_good.CTDCOND1,
            df_cond_good.BTLCOND,
            df_cond_good.CTDPRS,
            'CP',
            2,
            df_cond_good.SSSCC,
            df_cond_good.btl_fire_num,
            xRange='800:6000')
        coef_cond_2, df_ques_c2 = process_ctd.calibrate_param(
            df_cond_good.CTDCOND2,
            df_cond_good.BTLCOND,
            df_cond_good.CTDPRS,
            'CP',
            2,
            df_cond_good.SSSCC,
            df_cond_good.btl_fire_num,
            xRange='1500:6000')

        # Apply fitting coef to data

        # fit_ctd.conductivity_polyfit has salinity commented out? (fit_ctd.py, ln 460) MK
        btl_data_all['CTDCOND1'] = fit_ctd.conductivity_polyfit(
            btl_data_all['CTDCOND1'], btl_data_all['CTDTMP1'],
            btl_data_all['CTDPRS'], coef_cond_1)
        btl_data_all['CTDCOND2'] = fit_ctd.conductivity_polyfit(
            btl_data_all['CTDCOND2'], btl_data_all['CTDTMP2'],
            btl_data_all['CTDPRS'], coef_cond_2)
        # btl_data_all['CTDCOND1'],btl_data_all['CTDSAL'] = fit_ctd.conductivity_polyfit(btl_data_all['CTDCOND1'],btl_data_all['CTDTMP1'],btl_data_all['CTDPRS'],coef_cond_1)
        # btl_data_all['CTDCOND2'],sal_2 = fit_ctd.conductivity_polyfit(btl_data_all['CTDCOND2'],btl_data_all['CTDTMP2'],btl_data_all['CTDPRS'],coef_cond_2)

        # fit_ctd.conductivity_polyfit has salinity commented out? (fit_ctd.py, ln 460) MK
        time_data_all['CTDCOND1'] = fit_ctd.conductivity_polyfit(
            time_data_all['CTDCOND1'], time_data_all['CTDTMP1'],
            time_data_all['CTDPRS'], coef_cond_1)
        time_data_all['CTDCOND2'] = fit_ctd.conductivity_polyfit(
            time_data_all['CTDCOND2'], time_data_all['CTDTMP2'],
            time_data_all['CTDPRS'], coef_cond_2)
        # time_data_all['CTDCOND1'],time_data_all['CTDSAL'] = fit_ctd.conductivity_polyfit(time_data_all['CTDCOND1'], time_data_all['CTDTMP1'], time_data_all['CTDPRS'], coef_cond_1)
        # time_data_all['CTDCOND2'],sal2 = fit_ctd.conductivity_polyfit(time_data_all['CTDCOND2'], time_data_all['CTDTMP2'], time_data_all['CTDPRS'], coef_cond_2)

        qual_flag_cond = process_ctd.combine_quality_flags(
            [df_ques_c1, df_ques_c2, df_ques_refc])

        # Finally WRT to Cond

        btl_data_all['BTLCOND'] = fit_ctd.CR_to_cond(btl_data_all.CRavg,
                                                     btl_data_all.BathTEMP,
                                                     btl_data_all.CTDTMP1,
                                                     btl_data_all.CTDPRS)
        df_cond_good = process_ctd.prepare_fit_data(btl_data_all, 'BTLCOND')

        coef_cond_prim, df_ques_c1 = process_ctd.calibrate_param(
            df_cond_good.CTDCOND1, df_cond_good.BTLCOND, df_cond_good.CTDPRS,
            'C', 2, df_cond_good.SSSCC, df_cond_good.btl_fire_num)
        coef_cond_sec, df_ques_c2 = process_ctd.calibrate_param(
            df_cond_good.CTDCOND2, df_cond_good.BTLCOND, df_cond_good.CTDPRS,
            'C', 2, df_cond_good.SSSCC, df_cond_good.btl_fire_num)

        # Apply fitting coef to data

        # fit_ctd.conductivity_polyfit has salinity commented out? (fit_ctd.py, ln 460) MK
        btl_data_all['CTDCOND1'] = fit_ctd.conductivity_polyfit(
            btl_data_all['CTDCOND1'], btl_data_all['CTDTMP1'],
            btl_data_all['CTDPRS'], coef_cond_prim)
        btl_data_all['CTDCOND2'] = fit_ctd.conductivity_polyfit(
            btl_data_all['CTDCOND2'], btl_data_all['CTDTMP2'],
            btl_data_all['CTDPRS'], coef_cond_sec)
        # btl_data_all['CTDCOND1'],sal_1 = fit_ctd.conductivity_polyfit(btl_data_all['CTDCOND1'],btl_data_all['CTDTMP1'],btl_data_all['CTDPRS'],coef_cond_prim)
        # btl_data_all['CTDCOND2'],sal_2 = fit_ctd.conductivity_polyfit(btl_data_all['CTDCOND2'],btl_data_all['CTDTMP2'],btl_data_all['CTDPRS'],coef_cond_sec)

        # fit_ctd.conductivity_polyfit has salinity commented out? (fit_ctd.py, ln 460) MK
        time_data_all['CTDCOND1'] = fit_ctd.conductivity_polyfit(
            time_data_all['CTDCOND1'], time_data_all['CTDTMP1'],
            time_data_all['CTDPRS'], coef_cond_prim)
        time_data_all['CTDCOND2'] = fit_ctd.conductivity_polyfit(
            time_data_all['CTDCOND2'], time_data_all['CTDTMP2'],
            time_data_all['CTDPRS'], coef_cond_sec)
        # time_data_all['CTDCOND1'],time_data_all['CTDSAL'] = fit_ctd.conductivity_polyfit(time_data_all['CTDCOND1'], time_data_all['CTDTMP1'], time_data_all['CTDPRS'], coef_cond_prim)
        # time_data_all['CTDCOND2'],sal2 = fit_ctd.conductivity_polyfit(time_data_all['CTDCOND2'], time_data_all['CTDTMP2'], time_data_all['CTDPRS'], coef_cond_sec)

        qual_flag_cond = process_ctd.combine_quality_flags(
            [df_ques_c1, df_ques_c2, df_ques_refc])
    ###########################################################################
#
#    ## Oxygen Calibration
#    btl_data_all,time_data_all = oxy_fitting.calibrate_oxygen(time_data_all,btl_data_all,ssscc)

#    subprocess.run(['oxy_fit_script.py'], stdout=subprocess.PIPE)
#
#
#    subprocess.run(['ctd_to_bottle.py'], stdout=subprocess.PIPE)
#
#
#   ##########################################################################

#####
# Oxygen calibration (MK)
# look over this code again, maybe refence matlab scripts from PMEL

    import ctdcal.oxy_fitting as oxy_fitting
    import gsw

    # definitions
    import ctdcal.settings as settings
    hex_prefix = settings.ctd_processing_dir['hex_prefix']
    hex_postfix = settings.ctd_processing_dir['hex_postfix']
    xml_prefix = settings.ctd_processing_dir['xml_prefix']
    xml_postfix = settings.ctd_processing_dir['xml_postfix']
    oxy_btl_col = settings.bottle_inputs['btl_oxy']
    rinko_volts = settings.ctd_inputs['rinko_oxy']
    rinko_btl_volts = settings.bottle_inputs['rinko_oxy']
    dov_col = settings.ctd_inputs['dov']

    # unsure about these
    lat_col = config['analytical_inputs']['lat']
    lon_col = config['analytical_inputs']['lon']
    lat_btl_col = config['inputs']['lat']
    lon_btl_col = config['inputs']['lon']
    sal_btl_col = config['analytical_inputs']['btl_salt']
    t_btl_col = config['inputs']['t']
    t_col = config['analytical_inputs']['t']

    # calculate sigma
    btl_data_all['sigma_btl'] = oxy_fitting.sigma_from_CTD(
        btl_data_all[sal_btl_col], btl_data_all[t_btl_col],
        btl_data_all[p_btl_col], btl_data_all[lon_btl_col],
        btl_data_all[lat_btl_col])
    time_data_all['sigma_ctd'] = oxy_fitting.sigma_from_CTD(
        time_data_all[sal_col], time_data_all[t_col], time_data_all[p_col],
        time_data_all[lon_col], time_data_all[lat_col])

    btl_data_all[oxy_btl_col] = oxy_fitting.calculate_bottle_oxygen(
        ssscc, btl_data_all['SSSCC'], btl_data_all['TITR_VOL'],
        btl_data_all['TITR_TEMP'], btl_data_all['FLASKNO'])
    btl_data_all[oxy_btl_col] = oxy_fitting.oxy_ml_to_umolkg(
        btl_data_all[oxy_btl_col], btl_data_all['sigma_btl'])
    btl_data_all['OXYGEN_FLAG_W'] = oxy_fitting.flag_winkler_oxygen(
        btl_data_all[oxy_btl_col])

    # Calculate SA and PT
    btl_data_all['SA'] = gsw.SA_from_SP(btl_data_all[sal_btl_col],
                                        btl_data_all[p_btl_col],
                                        btl_data_all[lon_btl_col],
                                        btl_data_all[lat_btl_col])
    btl_data_all['PT'] = gsw.pt0_from_t(btl_data_all['SA'],
                                        btl_data_all[t_btl_col],
                                        btl_data_all[p_btl_col])

    time_data_all['SA'] = gsw.SA_from_SP(time_data_all[sal_col],
                                         time_data_all[p_col],
                                         time_data_all[lon_col],
                                         time_data_all[lat_col])
    time_data_all['PT'] = gsw.pt0_from_t(time_data_all['SA'],
                                         time_data_all[t_col],
                                         time_data_all[p_col])

    # Calculate OS in µmol/kg

    btl_data_all['OS_btl'] = oxy_fitting.os_umol_kg(btl_data_all['SA'],
                                                    btl_data_all['PT'])
    time_data_all['OS_ctd'] = oxy_fitting.os_umol_kg(time_data_all['SA'],
                                                     time_data_all['PT'])

    # collect data by stations

    btl_data_all['oxy_stn_group'] = btl_data_all['SSSCC'].str[0:3]
    time_data_all['oxy_stn_group'] = time_data_all['SSSCC'].str[0:3]

    station_list = time_data_all['oxy_stn_group'].unique()
    station_list = station_list.tolist()
    station_list.sort()

    btl_data_oxy = btl_data_all.copy()  #loc[btl_data_all['OXYGEN'].notnull()]

    rinko_coef0 = rinko.rinko_o2_cal_parameters()

    all_rinko_df = pd.DataFrame()
    all_sbe43_df = pd.DataFrame()
    rinko_dict = {}
    sbe43_dict = {}
    for station in station_list:

        #time_data = time_data_all[time_data_all['SSSCC'].str[0:3] == station].copy()
        #btl_data = btl_data_oxy[btl_data_oxy['SSSCC'].str[0:3] == station].copy()

        time_data = time_data_all[time_data_all['oxy_stn_group'] ==
                                  station].copy()
        btl_data = btl_data_oxy[btl_data_oxy['oxy_stn_group'] ==
                                station].copy()

        if (btl_data['OXYGEN_FLAG_W'] == 9).all():
            rinko_dict[station] = np.full(8, np.nan)
            sbe43_dict[station] = np.full(7, np.nan)
            print(station + ' skipped, all oxy data is NaN')
            continue

        rinko_coef, rinko_oxy_df = rinko.rinko_oxygen_fit(
            btl_data[p_btl_col], btl_data[oxy_btl_col], btl_data['sigma_btl'],
            time_data['sigma_ctd'], time_data['OS_ctd'], time_data[p_col],
            time_data[t_col], time_data[rinko_volts], rinko_coef0,
            btl_data['SSSCC'])

        station_ssscc = time_data['SSSCC'].values[0]
        hex_file = hex_prefix + station_ssscc + hex_postfix
        xml_file = xml_prefix + station_ssscc + xml_postfix
        sbe_coef0 = oxy_fitting.get_SB_coef(hex_file, xml_file)
        sbe_coef, sbe_oxy_df = oxy_fitting.sbe43_oxy_fit(
            btl_data[p_btl_col], btl_data[oxy_btl_col], btl_data['sigma_btl'],
            time_data['sigma_ctd'], time_data['OS_ctd'], time_data[p_col],
            time_data[t_col], time_data[dov_col], time_data['scan_datetime'],
            sbe_coef0, btl_data['SSSCC'])

        rinko_dict[station] = rinko_coef
        sbe43_dict[station] = sbe_coef
        all_rinko_df = pd.concat([all_rinko_df, rinko_oxy_df])
        all_sbe43_df = pd.concat([all_sbe43_df, sbe_oxy_df])

        print(station + ' Done!')

    sbe43_coef_df = oxy_fitting.create_coef_df(sbe43_dict)
    rinko_coef_df = oxy_fitting.create_coef_df(rinko_dict)

    btl_data_all = btl_data_all.merge(
        all_rinko_df,
        left_on=['SSSCC', p_btl_col],
        right_on=['SSSCC_rinko', 'CTDPRS_rinko_btl'],
        how='left')

    btl_data_all = btl_data_all.merge(
        all_sbe43_df,
        left_on=['SSSCC', p_btl_col],
        right_on=['SSSCC_sbe43', 'CTDPRS_sbe43_btl'],
        how='left')

    btl_data_all.drop(list(btl_data_all.filter(regex='rinko')),
                      axis=1,
                      inplace=True)

    btl_data_all.drop(list(btl_data_all.filter(regex='sbe43')),
                      axis=1,
                      inplace=True)

    ### Handle Missing Values

    X = btl_data_all['CTDOXYVOLTS_x'], btl_data_all['CTDPRS'], btl_data_all[
        t_btl_col], btl_data_all['dv_dt_x'], btl_data_all['OS_btl']
    rinko_X = btl_data_all[p_btl_col], btl_data_all[t_btl_col], btl_data_all[
        'CTDRINKOVOLTS'], btl_data_all['OS_btl']

    for station in btl_data_all['SSSCC']:
        coef_43 = sbe43_coef_df.loc[station[0:3]]
        coef_rinko = rinko_coef_df.loc[station[0:3]]
        btl_data_all['CTDOXY_fill'] = oxy_fitting.oxy_equation(
            X, coef_43[0], coef_43[1], coef_43[2], coef_43[3], coef_43[4],
            coef_43[5], coef_43[6])
        btl_data_all['CTDRINKO_fill'] = rinko.rinko_curve_fit_eq(
            rinko_X, coef_rinko[0], coef_rinko[1], coef_rinko[2],
            coef_rinko[3], coef_rinko[4], coef_rinko[5], coef_rinko[6],
            coef_rinko[7])

    btl_data_all.loc[btl_data_all['CTDOXY'].isnull(), 'CTDOXY_FLAG_W'] = 2
    btl_data_all.loc[btl_data_all['CTDOXY'].isnull(),
                     'CTDOXY'] = btl_data_all.loc[
                         btl_data_all['CTDOXY'].isnull(), 'CTDOXY_fill']
    btl_data_all.loc[btl_data_all['CTDRINKO'].isnull(), 'CTDRINKO_FLAG_W'] = 2
    btl_data_all.loc[btl_data_all['CTDRINKO'].isnull(),
                     'CTDRINKO'] = btl_data_all.loc[
                         btl_data_all['CTDRINKO'].isnull(), 'CTDRINKO_fill']

    btl_data_all = oxy_fitting.flag_oxy_data(btl_data_all)
    btl_data_all = oxy_fitting.flag_oxy_data(btl_data_all,
                                             ctd_oxy_col='CTDRINKO',
                                             flag_col='CTDRINKO_FLAG_W')

    btl_data_all[
        'res_rinko'] = btl_data_all['OXYGEN'] - btl_data_all['CTDRINKO']
    btl_data_all['res_sbe43'] = btl_data_all['OXYGEN'] - btl_data_all['CTDOXY']
    btl_data_all.loc[
        np.abs(btl_data_all['res_rinko']) >= 6,
        'CTDRINKO_FLAG_W'] = 3  # what's the benefit of np.abs() vs abs()?
    btl_data_all.loc[np.abs(btl_data_all['res_sbe43']) >= 6,
                     'CTDOXY_FLAG_W'] = 3

    time_data_all['CTDOXY'] = '-999'
    time_data_all['CTDRINKO'] = '-999'
    btl_data_all.sort_values(by='sigma_btl', inplace=True)
    time_data_all.sort_values(by='sigma_ctd', inplace=True)
    for station in station_list:
        rinko_coef = rinko_coef_df.loc[station].values
        if np.isnan(rinko_coef).all():
            print(station + ' data bad, leaving -999 values and flagging as 9')
            time_data_all.loc[time_data_all['SSSCC'].str[0:3] == station,
                              'CTDRINKO_FLAG_W'] = 9
            time_data_all.loc[time_data_all['SSSCC'].str[0:3] == station,
                              'CTDOXY_FLAG_W'] = 9
            continue

        time_data = time_data_all[time_data_all['oxy_stn_group'] ==
                                  station].copy()
        time_data['CTDOXY'] = oxy_fitting.SB_oxy_eq(
            sbe43_coef_df.loc[station], time_data[dov_col], time_data[p_col],
            time_data[t_col], time_data['dv_dt'], time_data['OS_ctd'])
        time_data['CTDRINKO'] = rinko.rinko_curve_fit_eq(
            (time_data[p_col], time_data[t_col], time_data[rinko_volts],
             time_data['OS_ctd']), rinko_coef[0], rinko_coef[1], rinko_coef[2],
            rinko_coef[3], rinko_coef[4], rinko_coef[5], rinko_coef[6],
            rinko_coef[7])

        time_data_all.loc[time_data_all['SSSCC'].str[0:3] == station,
                          'CTDOXY'] = time_data['CTDOXY']
        time_data_all.loc[time_data_all['SSSCC'].str[0:3] == station,
                          'CTDRINKO'] = time_data['CTDRINKO']
        time_data_all.loc[time_data_all['SSSCC'].str[0:3] == station,
                          'CTDRINKO_FLAG_W'] = 2
        time_data_all.loc[time_data_all['SSSCC'].str[0:3] == station,
                          'CTDOXY_FLAG_W'] = 2
        print(station + ' time data done')

    #####

    #######################
    # turn correction instantaneous CTD measurements into points @ bottle firings
    # subprocess.run(['ctd_to_bottle.py'], stdout=subprocess.PIPE)


################ Clean and export data #######################
# btl_data_all = process_ctd.merge_cond_flags(btl_data_all,qual_flag_cond, c_btl_col) # make code not require specific column input
    btl_data_all = process_ctd.merge_refcond_flags(btl_data_all,
                                                   qual_flag_cond)
    # btl_data_all = process_ctd.merge_temp_flags(btl_data_all, qual_flag_temp, t_btl_col)
    btl_data_all = process_ctd.merged_reftemp_flags(btl_data_all,
                                                    qual_flag_temp)

    ### Export Quality Flags

    qual_flag_temp.to_csv('data/logs/qual_flag_temp_new.csv', index=False)
    qual_flag_cond.to_csv('data/logs/qual_flag_cond_new.csv', index=False)

    ### Clean up Bottle Data by removing rows with no ctd data

    btl_data_all = oxy_fitting.clean_oxygen_df(
        btl_data_all)  # clean up column names
    btl_data_all = btl_data_all.dropna(subset=cols)

    ### Create CT Files(oxygen done by hand)

    # needed to run when there's no data available yet (i.e. at sea)
    # btl_data_all['OXYGEN'] = -999
    # btl_data_all['OXYGEN'] = -999
    # time_data_all['CTDOXY'] = -999

    # depreciated according to process_ctd.py (MK)
    # process_ctd.export_btl_data(btl_data_all,expocode,sectionID,expocode)
    # process_ctd.export_time_data(time_data_all,ssscc,int(sample_rate),int(search_time),expocode,sectionID,ctd,p_column_names,p_column_units)

    ### MK
    # create depth_log.csv
    station_list = time_data_all['SSSCC'].str[0:3].unique()
    depth_dict = {}
    for station in station_list:
        print(station)
        time_data = time_data_all[time_data_all['SSSCC'].str[0:3] ==
                                  station].copy()
        max_depth = process_ctd.find_cast_depth(time_data['CTDPRS'],
                                                time_data['GPSLAT'],
                                                time_data['ALT'])
        depth_dict[station] = max_depth

    depth_df = pd.DataFrame.from_dict(depth_dict, orient='index')
    depth_df.reset_index(inplace=True)
    depth_df.rename(columns={0: 'DEPTH', 'index': 'STNNBR'}, inplace=True)

    depth_df.to_csv('data/logs/depth_log.csv', index=False)

    # needs depth_log.csv, manual_depth_log.csv
    process_ctd.export_ct1(time_data_all, ssscc, expocode, sectionID, ctd,
                           p_column_names, p_column_units)
Example #6
0
def derive_ctd_parameters(dba):

    # Get the list of sensors parsed from the dba_file
    dba_sensors = [s['sensor_name'] for s in dba['sensors']]

    ctd_sensors = []
    found_ctd_sensors = [s for s in SCI_CTD_SENSORS if s in dba_sensors]
    if len(found_ctd_sensors) == len(SCI_CTD_SENSORS):
        ctd_sensors = SCI_CTD_SENSORS
    else:
        found_ctd_sensors = [s for s in M_CTD_SENSORS if s in dba_sensors]
        if len(found_ctd_sensors) == len(M_CTD_SENSORS):
            ctd_sensors = M_CTD_SENSORS

    if not ctd_sensors:
        logging.warning('Required CTD sensors not found in {:s}'.format(dba['file_metadata']['source_file']))
        return dba
    else:
        lati = dba_sensors.index(ctd_sensors[0])
        loni = dba_sensors.index(ctd_sensors[1])
        pi = dba_sensors.index(ctd_sensors[2])
        ti = dba_sensors.index(ctd_sensors[3])
        ci = dba_sensors.index(ctd_sensors[4])

        lat = dba['data'][:, lati]
        lon = dba['data'][:, loni]
        p = dba['data'][:, pi]
        t = dba['data'][:, ti]
        c = dba['data'][:, ci]

        # Calculate salinity
        salt = calculate_practical_salinity(c, t, p)
        # Calculate density
        density = calculate_density(t, p, salt, lat, lon)
        # Calculate potential temperature
        p_temp = pt0_from_t(salt, t, p)

        # Add parameters as long as they exist in ncw.nc_sensor_defs
        # if 'salinity' in ncw.nc_sensor_defs:
        sensor_def = {'sensor_name': 'salinity',
                      'attrs': {'ancillary_variables': 'conductivity,temperature,presssure',
                                'observation_type': 'calculated'}}
        dba['data'] = np.append(dba['data'], np.expand_dims(salt, 1), axis=1)
        dba['sensors'].append(sensor_def)

        # if 'density' in ncw.nc_sensor_defs:
        sensor_def = {'sensor_name': 'density',
                      'attrs': {
                          'ancillary_variables': 'conductivity,temperature,presssure,latitude,longitude',
                          'observation_type': 'calculated'}}
        dba['data'] = np.append(dba['data'], np.expand_dims(density, 1), axis=1)
        dba['sensors'].append(sensor_def)

        # if 'potential_temperature' in ncw.nc_sensor_defs:
        sensor_def = {'sensor_name': 'potential_temperature',
                      'attrs': {'ancillary_variables': 'salinity,temperature,presssure',
                                'observation_type': 'calculated'}}
        dba['data'] = np.append(dba['data'], np.expand_dims(p_temp, 1), axis=1)
        dba['sensors'].append(sensor_def)

        # if 'sound_speed' in ncw.nc_sensor_defs:
            # Calculate sound speed
        svel = calculate_sound_speed(t, p, salt, lat, lon)
        sensor_def = {'sensor_name': 'sound_speed',
                      'attrs': {
                          'ancillary_variables': 'conductivity,temperature,presssure,latitude,longitude',
                          'observation_type': 'calculated'}}
        dba['data'] = np.append(dba['data'], np.expand_dims(svel, 1), axis=1)
        dba['sensors'].append(sensor_def)

    return dba
Example #7
0
def add_oxsol(netCDFfile):
    ds = Dataset(netCDFfile, 'a')

    var_temp = ds.variables["TEMP"]
    var_psal = ds.variables["PSAL"]

    t = var_temp[:]
    SP = var_psal[:]

    if "PRES" in ds.variables:
        var_pres = ds.variables["PRES"]
        pres_var = "PRES"
        comment = ""
        p = var_pres[:]
    elif "NOMINAL_DEPTH" in ds.variables:
        var_pres = ds.variables["NOMINAL_DEPTH"]
        pres_var = "NOMINAL_DEPTH"
        comment = ", using nominal depth of " + str(var_pres[:])
        p = var_pres[:]
    else:
        p = 0
        pres_var = "nominal depth of 0 dbar"
        comment = ", using nominal depth 0 dbar"

    lat = -47
    lon = 142
    try:
        lat = ds.variables["LATITUDE"][0]
        lon = ds.variables["LONGITUDE"][0]
    except:
        pass

    SA = gsw.SA_from_SP(SP, p, lon, lat)
    pt = gsw.pt0_from_t(SA, t, p)

    oxsol = gsw.O2sol_SP_pt(SP, pt)

    if 'OXSOL' in ds.variables:
        ncVarOut = ds.variables['OXSOL']
    else:
        ncVarOut = ds.createVariable(
            "OXSOL", "f4", ("TIME", ), fill_value=np.nan,
            zlib=True)  # fill_value=nan otherwise defaults to max

    ncVarOut[:] = oxsol
    ncVarOut.units = "umol/kg"
    ncVarOut.long_name = "moles_of_oxygen_per_unit_mass_in_sea_water_at_saturation"
    ncVarOut.comment = "calculated using gsw-python https://teos-10.github.io/GSW-Python/index.html function gsw.O2sol_SP_pt" + comment
    ncVarOut.coordinates = 'TIME LATITUDE LONGITUDE NOMINAL_DEPTH'

    # update the history attribute
    try:
        hist = ds.history + "\n"
    except AttributeError:
        hist = ""

    ds.setncattr(
        'history', hist + datetime.utcnow().strftime("%Y-%m-%d") +
        " added oxygen solubility")

    ds.close()

    return netCDFfile
Example #8
0
def eps_overturn(P, Z, T, S, lon, lat, dnoise=0.001, pdref=4000):
    '''
    Calculate profile of turbulent dissipation epsilon from structure of a ctd
    profile.
    Currently this takes only one profile and not a matrix from a whole twoyo.
    '''
    import numpy as np
    import gsw

    # avoid error due to nan's in conditional statements
    np.seterr(invalid='ignore')

    z0 = Z.copy()
    z0 = z0.astype('float')

    # Find non-NaNs
    x = np.where(np.isfinite(T))
    x = x[0]

    # Extract variables without the NaNs
    p = P[x].copy()
    z = Z[x].copy()
    z = z.astype('float')
    t = T[x].copy()
    s = S[x].copy()
    # cn2   = ctdn['n2'][x].copy()

    SA = gsw.SA_from_SP(s, t, lon, lat)
    CT = gsw.CT_from_t(SA, t, p)
    PT = gsw.pt0_from_t(SA, t, p)

    sg4 = gsw.pot_rho_t_exact(SA, t, p, pdref)-1000

    # Create intermediate density profile
    D0 = sg4[0]
    sgt = D0-sg4[0]
    n = sgt/dnoise
    n = np.round(n)
    sgi = [D0+n*dnoise]  # first element
    for i in np.arange(1, np.alen(sg4), 1):
        sgt = sg4[i]-sgi[i-1]
        n = sgt/dnoise
        n = np.round(n)
        sgi.append(sgi[i-1]+n*dnoise)
    sgi = np.array(sgi)

    # Sort
    Ds = np.sort(sgi, kind='mergesort')
    Is = np.argsort(sgi, kind='mergesort')

    # Calculate Thorpe length scale
    TH = z[Is]-z
    cumTH = np.cumsum(TH)

    aa = np.where(cumTH > 1)
    aa = aa[0]

    # last index in overturns
    aatmp = aa.copy()
    aatmp = np.append(aatmp, np.nanmax(aa)+10)
    aad = np.diff(aatmp)
    aadi = np.where(aad > 1)
    aadi = aadi[0]
    LastItems = aa[aadi].copy()

    # first index in overturns
    aatmp = aa.copy()
    aatmp = np.insert(aatmp, 0, -1)
    aad = np.diff(aatmp)
    aadi = np.where(aad > 1)
    aadi = aadi[0]
    FirstItems = aa[aadi].copy()

    # % Sort temperature and salinity for calculating the buoyancy frequency
    PTs = PT[Is]
    SAs = SA[Is]
    CTs = CT[Is]

    # % Loop through detected overturns
    # % and calculate Thorpe Scales, N2 and dT/dz over the overturn
    # THsc = nan(size(Z));
    THsc = np.zeros_like(z)*np.nan
    N2 = np.zeros_like(z)*np.nan
    # CN2  = np.ones_like(z)*np.nan
    DTDZ = np.zeros_like(z)*np.nan

    out = {}
    out['idx'] = np.zeros_like(z0)

    for iostart, ioend in zip(FirstItems, LastItems):
        idx = np.arange(iostart, ioend+1, 1)
        out['idx'][x[idx]] = 1
        sc = np.sqrt(np.mean(np.square(TH[idx])))
        # ctdn2 = np.nanmean(cn2[idx])
        # Buoyancy frequency calculated over the overturn from sorted profiles
        # Go beyond overturn (I am sure this will cause trouble with the
        # indices at some point)
        n2, Np = gsw.Nsquared(SAs[[iostart-1, ioend+1]],
                              CTs[[iostart-1, ioend+1]],
                              p[[iostart-1, ioend+1]], lat)
        # Fill depth range of the overturn with the Thorpe scale
        THsc[idx] = sc
        # Fill depth range of the overturn with N^2
        N2[idx] = n2
        # Fill depth range of the overturn with average 10m N^2
        # CN2[idx]  = ctdn2

    # % Calculate epsilon
    THepsilon = 0.9*THsc**2.0*np.sqrt(N2)**3
    THepsilon[N2 <= 0] = np.nan
    THk = 0.2*THepsilon/N2

    out['eps'] = np.zeros_like(z0)*np.nan
    out['eps'][x] = THepsilon
    out['k'] = np.zeros_like(z0)*np.nan
    out['k'][x] = THk
    out['n2'] = np.zeros_like(z0)*np.nan
    out['n2'][x] = N2
    out['Lt'] = np.zeros_like(z0)*np.nan
    out['Lt'][x] = THsc

    return out
Example #9
0
def oxygen(netCDFfile):
    ds = Dataset(netCDFfile, 'a')

    var_temp = ds.variables["TEMP"]
    var_psal = ds.variables["PSAL"]
    var_pres = ds.variables["PRES"]

    t = var_temp[:]
    SP = var_psal[:]
    p = var_pres[:]

    SA = gsw.SA_from_SP(SP, p, ds.variables["LONGITUDE"][0], ds.variables["LATITUDE"][0])
    CT = gsw.CT_from_t(SA, t, p)
    pt = gsw.pt0_from_t(SA, t, p)

    sigma_theta0 = gsw.sigma0(SA, CT)
    oxsol = ds.variables["OXSOL"][:]

    ts = np.log((298.15 - t) / (273.15 + t))

    # psal correction, from Aanderra TD-218, Gordon and Garcia oxygaen solubility salinity coefficents
    B0 = -6.24097e-3
    C0 = -3.11680e-7
    B1 = -6.93498e-3
    B2 = -6.90358e-3
    B3 = -4.29155e-3

    psal_correction =  np.exp(SP *(B0 + B1 * ts + B2 * np.power(ts, 2) + B3 * np.power(ts, 3)) + np.power(SP, 2) * C0)

    # get correction slope, offset
    slope = 1.0
    offset = 0.0
    try:
        slope = ds.variables['DOX2_RAW'].calibration_slope
        offset = ds.variables['DOX2_RAW'].calibration_offset
    except AttributeError:
        pass

    # calculate disolved oxygen, umol/kg
    dox2_raw = ds.variables['DOX2_RAW'] * psal_correction * slope + offset
    dox2 = 1000 * dox2_raw / (sigma_theta0 + 1000)

    if 'DOX2' not in ds.variables:
        ncVarOut = ds.createVariable("DOX2", "f4", ("TIME",), fill_value=np.nan, zlib=True)  # fill_value=nan otherwise defaults to max
    else:
        ncVarOut = ds.variables['DOX2']

    ncVarOut[:] = dox2
    ncVarOut.units = "umol/kg"
    ncVarOut.comment = "calculated using DOX2 = DOX2_RAW * PSAL_CORRECTION / ((sigma_theta(P=0,Theta,S) + 1000).. Sea Bird AN 64, Aanderaa TD210 Optode Manual"
    ncVarOut.comment_calibration = "calibration slope " + str(slope) + " offset " + str(offset) + " umol/l"

    # calculate, and write the oxygen mass/seawater mass
    if 'DOX_MG' not in ds.variables:
        ncVarOut = ds.createVariable("DOXY", "f4", ("TIME",), fill_value=np.nan, zlib=True)  # fill_value=nan otherwise defaults to max
    else:
        ncVarOut = ds.variables['DOXY']

    ncVarOut[:] = dox2_raw / 31.24872
    ncVarOut.units = "mg/l"
    ncVarOut.comment = "calculated using DOXY =  * DOX2_RAW * PSAL_CORRECTION / 31.24872... Aanderaa TD210 Optode Manual"
    ncVarOut.comment_calibration = "calibration slope " + str(slope) + " offset " + str(offset) + " umol/l"

    # calculate and write oxygen solubility, ratio of disolved oxgen / oxygen solubility
    if 'DOXS' not in ds.variables:
        ncVarOut = ds.createVariable("DOXS", "f4", ("TIME",), fill_value=np.nan, zlib=True)  # fill_value=nan otherwise defaults to max
    else:
        ncVarOut = ds.variables['DOXS']

    ncVarOut[:] = dox2/oxsol
    ncVarOut.units = "1"
    ncVarOut.comment = "calculated using DOX2/OXSOL"

    # finish off, and close file

    # update the history attribute
    try:
        hist = ds.history + "\n"
    except AttributeError:
        hist = ""

    ds.setncattr('history', hist + datetime.utcnow().strftime("%Y-%m-%d") + " : added derived oxygen, DOX2, DOXS, DOX_MG")

    ds.close()
Example #10
0
def process_all_new():

    # Directory and file information
    expocode = settings.cruise['expocode']
    sectionID = settings.cruise['sectionid']
    raw_directory = settings.ctd_processing_dir['raw_data_directory']
    time_directory = settings.ctd_processing_dir['time_data_directory']
    converted_directory = settings.ctd_processing_dir['converted_directory']
    pressure_directory = settings.ctd_processing_dir['pressure_data_directory']
    oxygen_directory = settings.ctd_processing_dir['oxygen_directory']
    btl_directory = settings.ctd_processing_dir['bottle_directory']
    o2flask_file = settings.ctd_processing_dir['o2flask_file']
    log_directory = settings.ctd_processing_dir['log_directory']
    p_log_file = settings.ctd_processing_dir['pressure_log']
    hex_prefix = settings.ctd_processing_dir['hex_prefix']
    hex_postfix = settings.ctd_processing_dir['hex_postfix']
    xml_prefix = settings.ctd_processing_dir['xml_prefix']
    xml_postfix = settings.ctd_processing_dir['xml_postfix']

    # CTD Data Inputs
    p_col = settings.ctd_inputs['p']
    t_col = settings.ctd_inputs['t']
    t1_col = settings.ctd_inputs['t1']
    t2_col = settings.ctd_inputs['t2']
    c_col = settings.ctd_inputs['c']
    c1_col = settings.ctd_inputs['c1']
    c2_col = settings.ctd_inputs['c2']
    sal_col = settings.ctd_inputs['salt']
    dov_col = settings.ctd_inputs['dov']
    lat_col = settings.ctd_inputs['lat']
    lon_col = settings.ctd_inputs['lon']
    time_col = settings.ctd_inputs['scan_datetime']

    # Bottle Data Inputs
    p_btl_col = settings.bottle_inputs['p']
    t_btl_col = settings.bottle_inputs['t']
    t1_btl_col = settings.bottle_inputs['t1']
    t2_btl_col = settings.bottle_inputs['t2']
    c_btl_col = settings.bottle_inputs['c']
    c1_btl_col = settings.bottle_inputs['c1']
    c2_btl_col = settings.bottle_inputs['c2']
    reft_col = settings.bottle_inputs['reft']
    cond_col = settings.bottle_inputs['btl_cond']
    cr_avg = settings.bottle_inputs['cond_ratio']
    bath_temp = settings.bottle_inputs['bath_temp']
    sal_btl_col = settings.bottle_inputs['salt']
    dov_btl_col = settings.bottle_inputs['dov']
    lat_btl_col = settings.bottle_inputs['lat']
    lon_btl_col = settings.bottle_inputs['lon']
    oxy_btl_col = settings.bottle_inputs['btl_oxy']
    time_btl_col = settings.bottle_inputs['scan_datetime']

    # CTD Information
    sample_rate = settings.ctd_processing_constants['sample_rate']
    search_time = settings.ctd_processing_constants['roll_filter_time']
    ctd = settings.ctd_processing_constants['ctd_serial']

    p_column_names = settings.pressure_series_output['column_name']
    p_column_units = settings.pressure_series_output['column_units']

    btl_data_prefix = 'data/bottle/'
    btl_data_postfix = '_btl_mean.pkl'
    time_data_prefix = 'data/time/'
    time_data_postfix = '_time.pkl'
    p_log_file = 'data/logs/ondeck_pressure.csv'

    # Columns from btl and ctd file to be read:
    btl_cols = settings.btl_input_array
    ctd_cols = settings.ctd_input_array

    ssscc = settings.ssscc

    #    time_start = time.perf_counter()
    cnv_dir_list = os.listdir(converted_directory)
    time_dir_list = os.listdir(time_directory)
    btl_dir_list = os.listdir(btl_directory)

    for station in ssscc:
        if '{}.pkl'.format(station) in cnv_dir_list:
            continue
        #convert hex to ctd
        hex_file = hex_prefix + station + hex_postfix
        xml_file = xml_prefix + station + xml_postfix

        sbe_convert.convert_sbe(station, hex_file, xml_file,
                                converted_directory)
        print('Converted_sbe SSSCC: ' + station + ' done')

#    time_convert = time.perf_counter()

    for station in ssscc:
        if '{}_time.pkl'.format(station) in time_dir_list:
            continue
        sbe_convert.sbe_metadata(station)
        print('sbe_metadata SSSCC: ' + station + ' done')

    for station in ssscc:
        if '{}_btl_mean.pkl'.format(station) in btl_dir_list:
            continue
        #process bottle file
        sbe_convert.process_bottle(station)
        print('process_bottle SSSCC: ' + station + ' done')
#    time_bottle = time.perf_counter()

###########################################################################

### File I/O

# Load in all bottle, time, ref_data files into DataFrame

    btl_data_all = process_ctd.load_all_ctd_files(ssscc, btl_data_prefix,
                                                  btl_data_postfix, 'bottle',
                                                  btl_cols)
    time_data_all = process_ctd.load_all_ctd_files(ssscc, time_data_prefix,
                                                   time_data_postfix, 'time',
                                                   ctd_cols)

    ################################################################################

    ### Pressure Calibration

    # Determine Pressure offset from logs

    pressure_log = process_ctd.load_pressure_logs(p_log_file)
    p_off = process_ctd.get_pressure_offset(pressure_log.ondeck_start_p,
                                            pressure_log.ondeck_end_p)

    btl_data_all[p_btl_col] = fit_ctd.apply_pressure_offset(
        btl_data_all[p_btl_col], p_off)
    time_data_all[p_col] = fit_ctd.apply_pressure_offset(
        time_data_all[p_col], p_off)

    ###########################################################################

    df_ques_t1 = pd.DataFrame()
    df_ques_t2 = pd.DataFrame()

    df_ques_c1 = pd.DataFrame()
    df_ques_c2 = pd.DataFrame()

    ### Temperature Calibration
    for x in range(2):

        # Second order calibration

        df_temp_good = process_ctd.prepare_fit_data(btl_data_all, reft_col)

        df_ques_reft = process_ctd.quality_check(df_temp_good[t2_btl_col],
                                                 df_temp_good[t1_btl_col],
                                                 df_temp_good[p_btl_col],
                                                 df_temp_good['SSSCC'],
                                                 df_temp_good['btl_fire_num'],
                                                 'quest')
        df_ques_reft['Parameter'] = 'REF_TEMP'

        if settings.do_primary == 1:
            coef_temp_1, df_ques_t1 = process_ctd.calibrate_param(
                df_temp_good[t1_btl_col],
                df_temp_good[reft_col],
                df_temp_good[p_btl_col],
                'TP',
                2,
                df_temp_good.SSSCC,
                df_temp_good.btl_fire_num,
                xRange='800:6000')
            btl_data_all[t1_btl_col] = fit_ctd.temperature_polyfit(
                btl_data_all[t1_btl_col], btl_data_all[p_btl_col], coef_temp_1)
            time_data_all[t1_col] = fit_ctd.temperature_polyfit(
                time_data_all[t1_col], time_data_all[p_col], coef_temp_1)

        elif settings.do_secondary == 1:
            coef_temp_2, df_ques_t2 = process_ctd.calibrate_param(
                df_temp_good[t2_btl_col],
                df_temp_good[reft_col],
                df_temp_good[p_btl_col],
                'TP',
                2,
                df_temp_good.SSSCC,
                df_temp_good.btl_fire_num,
                xRange='1500:6000')
            btl_data_all[t2_btl_col] = fit_ctd.temperature_polyfit(
                btl_data_all[t2_btl_col], btl_data_all[p_btl_col], coef_temp_2)
            time_data_all[t2_col] = fit_ctd.temperature_polyfit(
                time_data_all[t2_col], time_data_all[p_col], coef_temp_2)

    # Apply fitting coef to data

    # Construct Quality Flag file

        qual_flag_temp = process_ctd.combine_quality_flags(
            [df_ques_reft, df_ques_t1, df_ques_t2])

        ## First order calibtation

        df_temp_good = process_ctd.prepare_fit_data(btl_data_all, reft_col)

        #        df_ques_reft = process_ctd.quality_check(df_temp_good[t2_btl_col], df_temp_good[t1_btl_col], df_temp_good[p_btl_col], df_temp_good['SSSCC'], df_temp_good['btl_fire_num'], 'quest')
        #        df_ques_reft['Parameter'] = 'REF_TEMP'
        if settings.do_primary == 1:
            coef_temp_prim, df_ques_t1 = process_ctd.calibrate_param(
                df_temp_good[t1_btl_col], df_temp_good[reft_col],
                df_temp_good[p_btl_col], 'T', 1, df_temp_good.SSSCC,
                df_temp_good.btl_fire_num)
            btl_data_all[t1_btl_col] = fit_ctd.temperature_polyfit(
                btl_data_all[t1_btl_col], btl_data_all[p_btl_col],
                coef_temp_prim)
            time_data_all[t1_col] = fit_ctd.temperature_polyfit(
                time_data_all[t1_col], time_data_all[p_col], coef_temp_prim)

        elif settings.do_secondary == 1:
            coef_temp_sec, df_ques_t2 = process_ctd.calibrate_param(
                df_temp_good[t2_btl_col], df_temp_good[reft_col],
                df_temp_good[p_btl_col], 'T', 1, df_temp_good.SSSCC,
                df_temp_good.btl_fire_num)
            btl_data_all[t2_btl_col] = fit_ctd.temperature_polyfit(
                btl_data_all[t2_btl_col], btl_data_all[p_btl_col],
                coef_temp_sec)
            time_data_all[t2_col] = fit_ctd.temperature_polyfit(
                time_data_all[t2_col], time_data_all[p_col], coef_temp_sec)

    # Apply fitting coef to data

        qual_flag_temp = process_ctd.combine_quality_flags(
            [df_ques_reft, df_ques_t1, df_ques_t2])

    ###########################################################################

#
### Conductivity Calibration
    for x in range(2):

        btl_data_all[cond_col] = fit_ctd.CR_to_cond(btl_data_all[cr_avg],
                                                    btl_data_all[bath_temp],
                                                    btl_data_all[t1_btl_col],
                                                    btl_data_all[p_btl_col])
        df_cond_good = process_ctd.prepare_fit_data(btl_data_all, cond_col)

        df_ques_refc = process_ctd.quality_check(df_cond_good[c2_btl_col],
                                                 df_temp_good[c1_btl_col],
                                                 df_temp_good[p_btl_col],
                                                 df_temp_good['SSSCC'],
                                                 df_temp_good['btl_fire_num'],
                                                 'quest')
        df_ques_refc['Parameter'] = 'REF_COND'

        # Second Order Calibration
        if settings.do_primary == 1:
            coef_cond_1, df_ques_c1 = process_ctd.calibrate_param(
                df_cond_good[c1_btl_col],
                df_cond_good[cond_col],
                df_cond_good[p_btl_col],
                'CP',
                2,
                df_cond_good['SSSCC'],
                df_cond_good['btl_fire_num'],
                xRange='800:6000')
            btl_data_all[c1_btl_col], btl_data_all[
                sal_btl_col] = fit_ctd.conductivity_polyfit(
                    btl_data_all[c1_btl_col], btl_data_all[t1_btl_col],
                    btl_data_all[p_btl_col], coef_cond_1)
            time_data_all[c1_col], time_data_all[
                sal_col] = fit_ctd.conductivity_polyfit(
                    time_data_all[c1_col], time_data_all[t1_col],
                    time_data_all[p_col], coef_cond_1)

        elif settings.do_secondary == 1:
            coef_cond_2, df_ques_c2 = process_ctd.calibrate_param(
                df_cond_good[c2_btl_col],
                df_cond_good[cond_col],
                df_cond_good[p_btl_col],
                'CP',
                2,
                df_cond_good['SSSCC'],
                df_cond_good['btl_fire_num'],
                xRange='1500:6000')
            btl_data_all[c2_btl_col], sal_2 = fit_ctd.conductivity_polyfit(
                btl_data_all[c2_btl_col], btl_data_all[t2_btl_col],
                btl_data_all[p_btl_col], coef_cond_2)
            time_data_all[c2_btl_col], sal2 = fit_ctd.conductivity_polyfit(
                time_data_all[c2_col], time_data_all[t2_col],
                time_data_all[p_col], coef_cond_2)

        qual_flag_cond = process_ctd.combine_quality_flags(
            [df_ques_c1, df_ques_c2, df_ques_refc])

        btl_data_all[cond_col] = fit_ctd.CR_to_cond(btl_data_all[cr_avg],
                                                    btl_data_all[bath_temp],
                                                    btl_data_all[t1_btl_col],
                                                    btl_data_all[p_btl_col])
        df_cond_good = process_ctd.prepare_fit_data(btl_data_all, cond_col)

        if settings.do_primary == 1:
            coef_cond_prim, df_ques_c1 = process_ctd.calibrate_param(
                df_cond_good[c1_btl_col], df_cond_good[cond_col],
                df_cond_good[p_btl_col], 'C', 2, df_cond_good['SSSCC'],
                df_cond_good['btl_fire_num'])
            btl_data_all[c1_btl_col], btl_data_all[
                sal_btl_col] = fit_ctd.conductivity_polyfit(
                    btl_data_all[c1_btl_col], btl_data_all[t1_btl_col],
                    btl_data_all[p_btl_col], coef_cond_prim)
            time_data_all[c1_col], time_data_all[
                sal_col] = fit_ctd.conductivity_polyfit(
                    time_data_all[c1_col], time_data_all[t1_col],
                    time_data_all[p_col], coef_cond_prim)

        elif settings.do_secondary == 1:
            coef_cond_sec, df_ques_c2 = process_ctd.calibrate_param(
                df_cond_good.CTDCOND2, df_cond_good.BTLCOND,
                df_cond_good.CTDPRS, 'C', 2, df_cond_good.SSSCC,
                df_cond_good.btl_fire_num)
            btl_data_all[c2_btl_col], sal_2 = fit_ctd.conductivity_polyfit(
                btl_data_all[c2_btl_col], btl_data_all[t2_btl_col],
                btl_data_all[p_btl_col], coef_cond_sec)
            time_data_all[c2_col], sal2 = fit_ctd.conductivity_polyfit(
                time_data_all[c2_col], time_data_all[t2_col],
                time_data_all[p_col], coef_cond_sec)

        qual_flag_cond = process_ctd.combine_quality_flags(
            [df_ques_c1, df_ques_c2, df_ques_refc])
    ###########################################################################
#
#    ## Oxygen Calibration

# Calculate Sigma
    btl_data_all['sigma_btl'] = oxy_fitting.sigma_from_CTD(
        btl_data_all[sal_btl_col], btl_data_all[t_btl_col],
        btl_data_all[p_btl_col], btl_data_all[lon_btl_col],
        btl_data_all[lat_btl_col])
    time_data_all['sigma_ctd'] = oxy_fitting.sigma_from_CTD(
        time_data_all[sal_col], time_data_all[t_col], time_data_all[p_col],
        time_data_all[lon_col], time_data_all[lat_col])

    btl_data_all[oxy_btl_col] = oxy_fitting.calculate_bottle_oxygen(
        ssscc, btl_data_all['SSSCC'], btl_data_all['TITR_VOL'],
        btl_data_all['TITR_TEMP'], btl_data_all['FLASKNO'])
    btl_data_all[oxy_btl_col] = oxy_fitting.oxy_ml_to_umolkg(
        btl_data_all[oxy_btl_col], btl_data_all['sigma_btl'])

    # Calculate SA and PT
    btl_data_all['SA'] = gsw.SA_from_SP(btl_data_all[sal_btl_col],
                                        btl_data_all[p_btl_col],
                                        btl_data_all[lon_btl_col],
                                        btl_data_all[lat_btl_col])
    btl_data_all['PT'] = gsw.pt0_from_t(btl_data_all['SA'],
                                        btl_data_all[t_btl_col],
                                        btl_data_all[p_btl_col])

    time_data_all['SA'] = gsw.SA_from_SP(time_data_all[sal_col],
                                         time_data_all[p_col],
                                         time_data_all[lon_col],
                                         time_data_all[lat_col])
    time_data_all['PT'] = gsw.pt0_from_t(time_data_all['SA'],
                                         time_data_all[t_col],
                                         time_data_all[p_col])

    # Calculate OS in µmol/kg

    btl_data_all['OS_btl'] = oxy_fitting.os_umol_kg(btl_data_all['SA'],
                                                    btl_data_all['PT'])
    time_data_all['OS_ctd'] = oxy_fitting.os_umol_kg(time_data_all['SA'],
                                                     time_data_all['PT'])

    oxy_df = pd.DataFrame()
    coef_dict = {}
    for station in ssscc:
        btl_data = btl_data_all[btl_data_all['SSSCC'] == station]
        time_data = time_data_all[time_data_all['SSSCC'] == station]

        hex_file = hex_prefix + station + hex_postfix
        xml_file = xml_prefix + station + xml_postfix
        coef0 = oxy_fitting.get_SB_coef(hex_file, xml_file)
        cfw_coef, df = oxy_fitting.oxy_fit(
            btl_data[p_btl_col], btl_data[oxy_btl_col], btl_data['sigma_btl'],
            time_data['sigma_ctd'], time_data['OS_ctd'], time_data[p_col],
            time_data[t_col], time_data[dov_col], time_data[time_col], coef0)
        df['SSSCC'] = station
        coef_dict[station] = cfw_coef
        oxy_df = pd.concat([oxy_df, df])

        print(station, ' Completed')

    coef_df = oxy_fitting.create_coef_df(coef_dict)
    oxy_df = oxy_fitting.flag_oxy_data(oxy_df)

    # Merge oxygen fitting DF to btl_data_all

    btl_data_all = oxy_fitting.merge_oxy_df(btl_data_all, oxy_df)

    # Apply coef to Time Data

    time_data_all = oxy_fitting.apply_oxygen_coef_ctd(time_data_all, coef_df,
                                                      ssscc)

    ################ Clean and export data #######################
    btl_data_all = process_ctd.merge_cond_flags(btl_data_all, qual_flag_cond)
    btl_data_all = process_ctd.merge_refcond_flags(btl_data_all,
                                                   qual_flag_cond)
    btl_data_all = process_ctd.merged_reftemp_flags(btl_data_all,
                                                    qual_flag_temp)
    ### Export Quality Flags

    qual_flag_temp.to_csv('data/logs/qual_flag_temp_new.csv', index=False)
    qual_flag_cond.to_csv('data/logs/qual_flag_cond_new.csv', index=False)

    ### Clean up Bottle Data by removing rows with no ctd data

    btl_data_all = btl_data_all.dropna(subset=btl_cols)

    ### Add DATE and TIME

    btl_data_all['DATE'] = ''
    btl_data_all['TIME'] = ''
    for station in ssscc:
        df = btl_data_all.loc[btl_data_all['SSSCC'] == station].copy()
        btl_data_all.loc[btl_data_all['SSSCC'] ==
                         station] = process_ctd.get_btl_time(
                             df, 'btl_fire_num', time_col)


### Create CT Files and HY files

    process_ctd.export_btl_data(btl_data_all, expocode, sectionID, expocode)
    process_ctd.export_time_data(time_data_all, ssscc, int(sample_rate),
                                 int(search_time), expocode, sectionID, ctd,
                                 p_column_names, p_column_units)
Example #11
0
def extract_sbe43(netCDFfile):
    ds = Dataset(netCDFfile, 'r')
    ds.set_auto_mask(False)

    var_temp = ds.variables["TEMP"]
    var_psal = ds.variables["PSAL"]
    var_pres = ds.variables["PRES"]

    # the SBE43 voltage
    var_v0 = ds.variables["V0"]

    dep_code = ds.deployment_code

    print('deployment', dep_code)

    out_file = dep_code + "-SBE43.nc"
    ds_out = Dataset(out_file, 'w', data_model='NETCDF4_CLASSIC')

    ds_out.createDimension("TIME", len(ds.variables['TIME']))
    ncVarIn = ds.variables['TIME']
    ncTimesOut = ds_out.createVariable('TIME', "f8", ("TIME", ), zlib=True)
    for a in ncVarIn.ncattrs():
        if a != '_FillValue':
            ncTimesOut.setncattr(a, ncVarIn.getncattr(a))
    ncTimesOut[:] = ds.variables['TIME'][:]

    # copy old variables into new file
    in_vars = set([x for x in ds.variables])

    z = in_vars.intersection([
        'TEMP', 'PSAL', 'PRES', 'V0', 'TEMP_quality_control',
        'PSAL_quality_control', 'PRES_quality_control', 'V0_quality_control',
        'LATITUDE', 'LONGITUDE', 'NOMINAL_DEPTH'
    ])

    for v in z:
        print('copying', v, 'dimensions', ncVarIn.dimensions)
        ncVarIn = ds.variables[v]
        if '_FillValue' in ncVarIn.ncattrs():
            fill = ncVarIn._FillValue
        else:
            fill = None

        ncVarOut = ds_out.createVariable(
            v, ncVarIn.dtype, ncVarIn.dimensions, fill_value=fill,
            zlib=True)  # fill_value=nan otherwise defaults to max
        for a in ncVarIn.ncattrs():
            if a != '_FillValue':
                if a == 'ancillary_variables':
                    ncVarOut.setncattr(
                        a, v + '_quality_control'
                    )  # only copying main quality control, not all individual flags
                else:
                    ncVarOut.setncattr(a, ncVarIn.getncattr(a))
        ncVarOut[:] = ncVarIn[:]

    if 'DOX2' in ds.variables:
        ncVarIn = ds.variables['DOX2']
        ncVarOut = ds_out.createVariable(
            'DOX2_SBE', "f4", ("TIME", ), fill_value=np.nan,
            zlib=True)  # fill_value=nan otherwise defaults to max
        for a in ncVarIn.ncattrs():
            if a not in ['_FillValue', 'ancillary_variables']:
                ncVarOut.setncattr(a, ncVarIn.getncattr(a))
        ncVarOut[:] = ncVarIn[:]

    T = var_temp[:]
    calibration_Soc = float(var_v0.calibration_Soc)
    calibration_offset = float(var_v0.calibration_offset)
    calibration_A = float(var_v0.calibration_A)
    calibration_B = float(var_v0.calibration_B)
    calibration_C = float(var_v0.calibration_C)
    calibration_E = float(var_v0.calibration_E)
    slope_correction = 1.0
    if 'oxygen_correction_slope' in var_v0.ncattrs():
        slope_correction = float(var_v0.oxygen_correction_slope)

    lat = -47
    lon = 142
    try:
        lat = ds.variables["LATITUDE"][0]
        lon = ds.variables["LONGITUDE"][0]
    except:
        pass

    SP = var_psal[:]
    p = var_pres[:]
    SA = gsw.SA_from_SP(SP, p, lon, lat)
    pt = gsw.pt0_from_t(SA, T, p)
    CT = gsw.CT_from_t(SA, T, p)
    sigma_t0 = gsw.sigma0(SA, CT)

    # calc oxygen solubility
    # 0.01 % difference to sea bird calculation
    #oxsol = gsw.O2sol_SP_pt(SP, pt) # umol/kg returned

    # calc OXSOL in ml/l as per seabird application note 64
    # this method gives a 0.2 % difference to what is calculated by sea bird (and what is calculated by TEOS-10)
    A0 = 2.00907
    A1 = 3.22014
    A2 = 4.0501
    A3 = 4.94457
    A4 = -0.256847
    A5 = 3.88767
    B0 = -0.00624523
    B1 = -0.00737614
    B2 = -0.010341
    B3 = -0.00817083
    C0 = -0.000000488682
    ts = np.log((298.15 - T) / (273.15 + T))

    oxsol = np.exp(A0 + A1 * ts + A2 * (ts**2) + A3 * (ts**3) + A4 * (ts**4) +
                   A5 * (ts**5) +
                   SP * [B0 + B1 * (ts) + B2 * (ts**2) + B3 *
                         (ts**3)] + C0 * (SP**2))
    #
    # # calculate oxygen from V0
    dox = slope_correction * calibration_Soc * (
        var_v0[:] + calibration_offset) * oxsol * (
            1 + calibration_A * T + calibration_B * T**2 +
            calibration_C * T**3) * np.exp(calibration_E * p / (T + 273.15))
    #
    # # create SBE43 oxygen ml/l
    # # ncVarOut = ds_out.createVariable("DOX", "f4", ("TIME",), fill_value=np.nan, zlib=True)  # fill_value=nan otherwise defaults to max
    # #
    # # ncVarOut[:] = dox
    # # ncVarOut.long_name = "volume_concentration_of_dissolved_molecular_oxygen_in_sea_water"
    # # ncVarOut.valid_min = 0
    # # ncVarOut.valid_max = 40
    # # ncVarOut.units = "ml/l"
    # # ncVarOut.equation_1 = "Ox(ml/l)=Soc.(V+Voffset).(1+A.T+B.T^2+V.T^3).OxSOL(T,S).exp(E.P/K) ... SeaBird (AN64-2)"

    # create SBE43 oxygen in umol/kg
    ncVarOut = ds_out.createVariable(
        "DOX2", "f4", ("TIME", ), fill_value=np.nan,
        zlib=True)  # fill_value=nan otherwise defaults to max

    ncVarOut[:] = dox * 44600 / (1000 + sigma_t0)

    #ncVarOut[:] = dox * 44.6

    ncVarOut.standard_name = "moles_of_oxygen_per_unit_mass_in_sea_water"
    ncVarOut.long_name = "moles_of_oxygen_per_unit_mass_in_sea_water"
    ncVarOut.coordinates = 'TIME LATITUDE LONGITUDE NOMINAL_DEPTH'
    ncVarOut.valid_min = 0
    ncVarOut.valid_max = 400
    ncVarOut.units = "umol/kg"
    ncVarOut.equation_1 = "Ox[ml/l]=Soc.(V+Voffset).(1+A.T+B.T^2+C.T^3).OxSOL(T,S)[ml/l].exp(E.P/K) ... SeaBird (AN64)"
    ncVarOut.equation_2 = "Ox[umol/kg]=Ox[ml/l].44660/(sigma-theta(P=0,Theta,S)+1000)"
    #ncVarOut.equation_1 = "Ox[umol/kg]=Soc.(V+Voffset).(1+A.T+B.T^2+C.T^3).OxSOL(T,S)[umol/kg].exp(E.P/K) ... SeaBird (AN64)"
    #ncVarOut.comment = 'OxSOL in umol/kg'
    ncVarOut.ancillary_variables = "DOX2_quality_control DOX2_quality_control_in"

    # quality flags
    ncVarOut_qc = ds_out.createVariable(
        "DOX2_quality_control", "i1", ("TIME", ), fill_value=99, zlib=True
    )  # fill_value=99 otherwise defaults to max, imos-toolbox uses 99
    ncVarOut_qc[:] = np.zeros(ncVarOut_qc.shape)
    if 'V0_quality_control' in ds.variables:
        mx = np.max([ncVarOut_qc[:], ds.variables['V0_quality_control'][:]],
                    axis=0)
        ncVarOut_qc[:] = mx
    if 'TEMP_quality_control' in ds.variables:
        mx = np.max([ncVarOut_qc[:], ds.variables['TEMP_quality_control'][:]],
                    axis=0)
        print('TEMP max', mx)
        ncVarOut_qc[:] = mx
    if 'PSAL_quality_control' in ds.variables:
        mx = np.max([ncVarOut_qc[:], ds.variables['PSAL_quality_control'][:]],
                    axis=0)
        print('PSAL max', mx)
        ncVarOut_qc[:] = mx
    if 'PRES_quality_control' in ds.variables:
        mx = np.max([ncVarOut_qc[:], ds.variables['PRES_quality_control'][:]],
                    axis=0)
        print('PRES max', mx)
        ncVarOut_qc[:] = mx

    ncVarOut_qc.standard_name = ncVarOut.standard_name + " status_flag"
    ncVarOut_qc.quality_control_conventions = "IMOS standard flags"
    ncVarOut_qc.flag_values = np.array([0, 1, 2, 3, 4, 6, 7, 9], dtype=np.int8)
    ncVarOut_qc.flag_meanings = 'unknown good_data probably_good_data probably_bad_data bad_data not_deployed interpolated missing_value'
    ncVarOut_qc.comment = 'maximum of all flags'

    # create a QC flag variable for the input data
    ncVarOut_qc = ds_out.createVariable(
        "DOX2_quality_control_in", "i1", ("TIME", ), fill_value=99, zlib=True
    )  # fill_value=99 otherwise defaults to max, imos-toolbox uses 99
    ncVarOut_qc[:] = mx
    ncVarOut_qc.long_name = "input data flag for moles_of_oxygen_per_unit_mass_in_sea_water"
    ncVarOut_qc.units = "1"
    ncVarOut_qc.comment = "data flagged from input variables TEMP, PSAL, PRES"

    # save the OxSOL
    if 'OXSOL' in ds_out.variables:
        ncVarOut = ds_out.variables['OXSOL']
    else:
        ncVarOut = ds_out.createVariable(
            "OXSOL", "f4", ("TIME", ), fill_value=np.nan,
            zlib=True)  # fill_value=nan otherwise defaults to max

    #ncVarOut[:] = oxsol * 44600 / (1000+sigma_t0)
    ncVarOut[:] = oxsol
    ncVarOut.units = "umol/kg"
    ncVarOut.comment = "calculated using gsw-python https://teos-10.github.io/GSW-Python/index.html function gsw.O2sol_SP_pt"
    ncVarOut.long_name = "moles_of_oxygen_per_unit_mass_in_sea_water_at_saturation"
    ncVarOut.coordinates = 'TIME LATITUDE LONGITUDE NOMINAL_DEPTH'

    for v in ds.ncattrs():
        if not v.startswith('sea_bird'):
            ds_out.setncattr(v, ds.getncattr(v))

    ds_out.instrument = 'Sea-Bird Electronics ; SBE43'
    ds_out.instrument_model = 'SBE43'
    ds_out.instrument_serial_number = '43' + var_v0.calibration_SerialNumber

    ncTimeFormat = "%Y-%m-%dT%H:%M:%SZ"

    attrs = ds.ncattrs()
    for at in attrs:
        if at not in [
                'title', 'instrument', 'instrument_model',
                'instrument_serial_number', 'history', 'date_created', 'title'
        ]:
            #print('copy att', at)
            ds_out.setncattr(at, ds.getncattr(at))

    ds_out.deployment_code = ds.deployment_code
    ds_out.instrument = 'SeaBird Electronics ; SBE43'
    ds_out.instrument_model = 'SBE43'
    ds_out.instrument_serial_number = ds.variables[
        'V0'].calibration_SerialNumber
    ds_out.title = 'Oceanographic mooring data deployment of {platform_code} at latitude {geospatial_lat_max:3.1f} longitude {geospatial_lon_max:3.1f} depth {geospatial_vertical_max:3.0f} (m) instrument {instrument} serial {instrument_serial_number}'

    # add creating and history entry
    ds_out.setncattr("date_created", datetime.utcnow().strftime(ncTimeFormat))

    # update the history attribute
    try:
        hist = ds.history + "\n"
    except AttributeError:
        hist = ""

    # keep the history so we know where it came from
    ds_out.setncattr(
        'history', hist + datetime.utcnow().strftime("%Y-%m-%d") +
        " calculate DOX2 from file " + os.path.basename(netCDFfile))

    ds.close()
    ds_out.close()

    return out_file
Example #12
0
def add_optode_oxygen(netCDFfile):
    ds = Dataset(netCDFfile, 'a')

    var_temp = ds.variables["TEMP"]
    var_psal = ds.variables["PSAL"]
    var_bphase = ds.variables["BPHASE"]
    var_otemp = ds.variables["OTEMP"]
    #var_otemp = ds.variables["TEMP"]

    t = var_temp[:]
    SP = var_psal[:]
    phase = var_bphase[:]
    otemp = var_otemp[:]

    try:
        var_pres = ds.variables["PRES"]
        p = var_pres[:]
    except:
        p = 0

    lat = -47
    lon = 142
    try:
        lat = ds.variables["LATITUDE"][0]
        lon = ds.variables["LONGITUDE"][0]
    except:
        pass

    SA = gsw.SA_from_SP(SP, p, lon, lat)
    pt = gsw.pt0_from_t(SA, t, p)
    sigmat = gsw.sigma0(SA, t)

    oxsol = gsw.O2sol_SP_pt(SP, pt)

    if 'OXSOL' in ds.variables:
        out_oxsol_var = ds.variables['OXSOL']
    else:
        out_oxsol_var = ds.createVariable(
            "OXSOL", "f4", ("TIME", ), fill_value=np.nan,
            zlib=True)  # fill_value=nan otherwise defaults to max

    out_oxsol_var[:] = oxsol
    out_oxsol_var.units = "umol/kg"

    out_oxsol_var.comment = "calculated using gsw-python https://teos-10.github.io/GSW-Python/index.html function gsw.O2sol_SP_pt"

    C0 = var_bphase.calibration_C0
    C1 = var_bphase.calibration_C1
    C2 = var_bphase.calibration_C2
    A0 = var_bphase.calibration_A0
    A1 = var_bphase.calibration_A1
    B0 = var_bphase.calibration_B0
    B1 = var_bphase.calibration_B1

    if 'DOX2_RAW' in ds.variables:
        out_ox_var = ds.variables['DOX2_RAW']
    else:
        out_ox_var = ds.createVariable(
            "DOX2_RAW", "f4", ("TIME", ), fill_value=np.nan,
            zlib=True)  # fill_value=nan otherwise defaults to max

    oxygen = (
        (A0 + A1 * otemp) /
        (B0 + B1 * phase) - 1) / (C0 + C1 * otemp + C2 * np.power(otemp, 2))

    out_ox_var[:] = oxygen

    out_ox_var.comment_calc1 = 'calculated using ((A0 + A1 * otemp)/(B0 + B1 * phase) - 1)/(C0 + C1 * otemp + C2 * otemp * otemp)'
    out_ox_var.units = "umol"
    out_ox_var.long_name = "mole_concentration_of_dissolved_molecular_oxygen_in_sea_water (not salinity or pressure corrected)"
    out_ox_var.valid_max = np.float32(400)
    out_ox_var.valid_min = np.float32(0)

    out_ox_var.coordinates = "TIME LATITUDE LONGITUDE NOMINAL_DEPTH"

    # update the history attribute
    try:
        hist = ds.history + "\n"
    except AttributeError:
        hist = ""

    ds.setncattr(
        'history', hist + datetime.utcnow().strftime("%Y-%m-%d") +
        " : calculated optode oxygen and oxygen solubility")

    ds.close()