Exemplo n.º 1
0
        def pcomp(par, opar):
            diffs = []
            Ks = MyAMI_K_calc(param_dict=par)
            oKs = MyAMI_K_calc(param_dict=opar)

            for k in Ks.keys():
                diffs.append(Ks[k] - oKs[k])
            return all(abs(np.array(diffs)) < 1e-6)
Exemplo n.º 2
0
    def test_CompareToDickson2007(self):
        # Check params @ 25ºC and 35 PSU

        # Parameters are from Dickson, Sabine & Christian
        # (Guide to best practises for ocean CO2 measurements,
        # PICES Special Publication, 2007), Chapter 5.7.2 (seawater).

        # Except KspC and KspA, which are from from Zeebe &
        # Wolf-Gladrow, 2001, Appendix A.10

        K_ckeck = {
            'K0': np.exp(-3.5617),
            'K1': 10**(-5.8472),
            'K2': 10**(-8.9660),
            'KB': np.exp(-19.7964),
            # 'KW': np.exp(-30.434),
            'KSO4': np.exp(-2.30),
            'KspC': 10**-6.3693,
            'KspA': 10**-6.1883
        }

        Ks = MyAMI_K_calc()

        for k, p in K_ckeck.items():
            self.assertAlmostEqual(Ks[k] / p,
                                   1,
                                   places=3,
                                   msg='failed on ' + k)
        return
Exemplo n.º 3
0
def calc_Ks_TS(T, S, P, Ks={}):
    """
    Helper function to calculate Ks given only T(C), S and P.

    If Ks is a dict, the Ks provided in the dict are used
    transparrently (i.e. no pressure modification).
    """
    Mg = 0.0528171
    Ca = 0.0102821

    if isinstance(Ks, dict):
        given_Ks = Ks

    Ks = MyAMI_K_calc(TempC=T, Sal=S, P=P, Mg=Mg, Ca=Ca)

    # non-MyAMI Constants
    Ks.update(calc_KPs(T, S, P))
    Ks.update(calc_KF(T, S, P))
    Ks.update(calc_KSi(T, S, P))

    # pH conversions to total scale.
    #   - KP1, KP2, KP3 are all on SWS
    #   - KSi is on SWS
    #   - MyAMI KW is on SWS... DOES THIS MATTER?

    TS = calc_TS(S)
    TF = calc_TF(S)
    SWStoTOT = (1 + TS / Ks.KSO4) / (1 + TS / Ks.KSO4 + TF / Ks.KF)
    # FREEtoTOT = 1 + 'T_' + mode]S / Ks.KSO4
    conv = ["KP1", "KP2", "KP3", "KSi", "KW"]
    for c in conv:
        Ks[c] *= SWStoTOT

    Ks.update(given_Ks)

    return Ks
Exemplo n.º 4
0
def get_Ks(ps):
    """
    Helper function to calculate Ks.

    If ps.Ks is a dict, those Ks are used
    transparrently, with no pressure modification.
    """
    if isinstance(ps.Ks, dict):
        Ks = Bunch(ps.Ks)
    else:
        if maxL(ps.Mg, ps.Ca) == 1:
            if ps.Mg is None:
                ps.Mg = 0.0528171
            if ps.Ca is None:
                ps.Ca = 0.0102821
            Ks = MyAMI_K_calc(TempC=ps.T, Sal=ps.S, Mg=ps.Mg, Ca=ps.Ca, P=ps.P)
        else:
            # if only Ca or Mg provided, fill in other with modern
            if ps.Mg is None:
                ps.Mg = 0.0528171
            if ps.Ca is None:
                ps.Ca = 0.0102821
            # calculate Ca and Mg specific Ks
            Ks = MyAMI_K_calc_multi(TempC=ps.T,
                                    Sal=ps.S,
                                    Ca=ps.Ca,
                                    Mg=ps.Mg,
                                    P=ps.P)

    # non-MyAMI Constants
    Ks.update(calc_KPs(ps.T, ps.S, ps.P))
    Ks.update(calc_KF(ps.T, ps.S, ps.P))
    Ks.update(calc_KSi(ps.T, ps.S, ps.P))

    # pH conversions to total scale.
    #   - KPn are all on SWS
    #   - KSi is on SWS
    #   - MyAMI KW is on SWS... DOES THIS MATTER?

    SWStoTOT = (1 + ps.TS / Ks.KSO4) / (1 + ps.TS / Ks.KSO4 + ps.TF / Ks.KF)
    # FREEtoTOT = 1 + ps.TS / Ks.KSO4
    conv = ['KP1', 'KP2', 'KP3', 'KSi', 'KW']
    for c in conv:
        Ks[c] *= SWStoTOT

    return Ks
Exemplo n.º 5
0
def calc_Ks(T, S, P, Mg, Ca, TS, TF, Ks=None):
    """
    Helper function to calculate Ks.

    If Ks is a dict, those Ks are used
    transparrently (i.e. no pressure modification).
    """
    if isinstance(Ks, dict):
        Ks = Bunch(Ks)
    else:
        if maxL(Mg, Ca) == 1:
            if Mg is None:
                Mg = 0.0528171
            if Ca is None:
                Ca = 0.0102821
            Ks = MyAMI_K_calc(TempC=T, Sal=S, P=P, Mg=Mg, Ca=Ca)
        else:
            # if only Ca or Mg provided, fill in other with modern
            if Mg is None:
                Mg = 0.0528171
            if Ca is None:
                Ca = 0.0102821
            # calculate Ca and Mg specific Ks
            Ks = MyAMI_K_calc_multi(TempC=T, Sal=S, P=P, Ca=Ca, Mg=Mg)

        # non-MyAMI Constants
        Ks.update(calc_KPs(T, S, P))
        Ks.update(calc_KF(T, S, P))
        Ks.update(calc_KSi(T, S, P))

        # pH conversions to total scale.
        #   - KP1, KP2, KP3 are all on SWS
        #   - KSi is on SWS
        #   - MyAMI KW is on SWS... DOES THIS MATTER?

        SWStoTOT = (1 + TS / Ks.KSO4) / (1 + TS / Ks.KSO4 + TF / Ks.KF)
        # FREEtoTOT = 1 + 'T_' + mode]S / Ks.KSO4
        conv = ["KP1", "KP2", "KP3", "KSi", "KW"]
        for c in conv:
            Ks[c] *= SWStoTOT

    return Ks
Exemplo n.º 6
0
    def test_CompareToMehrbachData(self):
        """
        Compares pK1 and pK2 calcualted by MyAMI_V2 to data from
        Mehrbach et al (1973), as per Lueker et al (2000).

        Test data on Total pH scale taken from Table 2 of Lueker et al (2000)
        """
        # read data
        lk = pd.read_csv(
            "cbsyst/test_data/Lueker2000/Lueker2000_Table2.csv", comment="#"
        )

        # calculate MyAMI Ks
        mKs = MyAMI_K_calc(lk.TempC, lk.Sal)

        # calculate pK1 and pK2 2 residuals
        rpK1 = lk.pK1 - -np.log10(mKs.K1)
        rpK2 = lk.pK2 - -np.log10(mKs.K2)

        # calculate median and 95% CI of residuals
        rpK1_median = rpK1.median()
        rpK1_95ci = np.percentile(rpK1[~np.isnan(rpK1)], (2.5, 97.5))
        self.assertLessEqual(
            abs(rpK1_median), 0.005, msg="Median offset from Mehrbach (1973) pK1."
        )
        self.assertTrue(
            all(abs(rpK1_95ci) <= 0.02),
            msg="95% CI of difference from Mehrbach pK1 <= 0.02",
        )

        rpK2_median = rpK1.median()
        rpK2_95ci = np.percentile(rpK2[~np.isnan(rpK2)], (2.5, 97.5))
        self.assertLessEqual(
            abs(rpK2_median), 0.005, msg="Median offset from Mehrbach (1973) pK2."
        )
        self.assertTrue(
            all(abs(rpK2_95ci) <= 0.02),
            msg="95% CI of difference from Mehrbach pK2 <= 0.02",
        )

        return