Esempio n. 1
0
def Csys(pHtot=None,
         DIC=None,
         CO2=None,
         HCO3=None,
         CO3=None,
         TA=None,
         fCO2=None,
         pCO2=None,
         BT=None,
         Ca=None,
         Mg=None,
         T=25.,
         S=35.,
         P=None,
         TP=0.,
         TSi=0.,
         pHsws=None,
         pHfree=None,
         Ks=None,
         pdict=None,
         unit='umol'):
    """
    Calculate the carbon chemistry of seawater from a minimal parameter set.

    Constants calculated by MyAMI model (Hain et al, 2015; doi:10.1002/2014GB004986).
    Speciation calculations from Zeebe & Wolf-Gladrow (2001; ISBN:9780444509468) Appendix B

    pH is Total scale.

    Inputs must either be single values, arrays of equal length or a mixture of both.
    If you use arrays of unequal length, it won't work.

    Error propagation:
    If inputs are ufloat or uarray (from uncertainties package) errors will
    be propagated through all calculations, but:

    **WARNING** Error propagation NOT IMPLEMENTED for carbon system calculations
    with zero-finders (i.e. when pH is not given; cases 2-5 and 10-15).

    Concentration Units
    +++++++++++++++++++
    * Ca and Mg must be in molar units.
    * All other units must be the same, and can be specified in the 'unit' variable. Defaults to umolar.

    Parameters
    ----------
    pH, DIC, CO2, HCO3, CO3, TA : array-like
        Carbon system parameters. Two of these must be provided.
    BT : array-like
        Total B at Salinity = 35, used in Alkalinity calculations.
    Ca, Mg : arra-like
        The [Ca] and [Mg] of the seawater, in mol / kg.
        Used in calculating MyAMI constants.
    T, S : array-like
        Temperature in Celcius and Salinity in PSU.
        Used in calculating MyAMI constants.
    P : array-like
        Pressure in Bar.
        Used in calculating MyAMI constants.
    unit : str
        Concentration units of C and B parameters (all must be in
        the same units).
        Can be 'mol', 'mmol', 'umol', 'nmol', 'pmol' or 'fmol'.
        Used in calculating Alkalinity. Default is 'umol'.
    Ks : dict
        A dictionary of constants. Must contain keys
        'K1', 'K2', 'KB' and 'KW'.
        If None, Ks are calculated using MyAMI model.
    pdict : dict
        Optionally, you can provide some or all parameters as a dict,
        with keys the same as the parameter names above. Any parameters
        included in the dict will overwrite manually specified
        parameters. This is particularly useful if you're including
        this in other code.

    Returns
    -------
    dict(/Bunch) containing all calculated parameters.
    """

    # Bunch inputs
    ps = Bunch(locals())
    if isinstance(pdict, dict):
        ps.update(pdict)

    # convert unit to multiplier
    udict = {
        'mol': 1.,
        'mmol': 1.e3,
        'umol': 1.e6,
        'nmol': 1.e9,
        'pmol': 1.e12,
        'fmol': 1.e15
    }
    if isinstance(ps.unit, str):
        ps.unit = udict[ps.unit]
    # elif isinstance(ps.unit, (int, float)):
    #     ps.unit = ps.unit

    if ps.unit != 1:
        upar = [
            'DIC', 'TA', 'CO2', 'HCO3', 'CO3', 'BT', 'fCO2', 'pCO2', 'TP',
            'TSi'
        ]
        for p in upar:
            if ps[p] is not None:
                ps[p] = np.divide(ps[p], ps.unit)  # convert to molar

    # Conserved seawater chemistry
    if 'TS' not in ps:
        ps.TS = calc_TS(ps.S)
    if 'TF' not in ps:
        ps.TF = calc_TF(ps.S)
    if ps.BT is None:
        ps.BT = calc_TB(ps.S)
    elif isinstance(BT, (int, float)):
        ps.BT = ps.BT * ps.S / 35.

    # Calculate Ks
    ps.Ks = get_Ks(ps)

    # Calculate pH scales (does nothing if no pH given)
    ps.update(
        calc_pH_scales(ps.pHtot, ps.pHfree, ps.pHsws, ps.TS, ps.TF, ps.Ks))

    # if fCO2 is given but CO2 is not, calculate CO2
    if ps.CO2 is None:
        if ps.fCO2 is not None:
            ps.CO2 = fCO2_to_CO2(ps.fCO2, ps.Ks)
        elif ps.pCO2 is not None:
            ps.CO2 = fCO2_to_CO2(pCO2_to_fCO2(ps.pCO2, ps.T), ps.Ks)

    # Carbon System Calculations (from Zeebe & Wolf-Gladrow, Appendix B)
    # 1. CO2 and pH
    if ps.CO2 is not None and ps.pHtot is not None:
        ps.H = ch(ps.pHtot)
        ps.DIC = CO2_pH(ps.CO2, ps.pHtot, ps.Ks)
    # 2. ps.CO2 and ps.HCO3
    elif ps.CO2 is not None and ps.HCO3 is not None:
        ps.H = CO2_HCO3(ps.CO2, ps.HCO3, ps.Ks)
        ps.DIC = CO2_pH(ps.CO2, cp(ps.H), ps.Ks)
    # 3. ps.CO2 and ps.CO3
    elif ps.CO2 is not None and ps.CO3 is not None:
        ps.H = CO2_CO3(ps.CO2, ps.CO3, ps.Ks)
        ps.DIC = CO2_pH(ps.CO2, cp(ps.H), ps.Ks)
    # 4. ps.CO2 and ps.TA
    elif ps.CO2 is not None and ps.TA is not None:
        # unit conversion because OH and H wrapped
        # up in TA fns - all need to be in same units.
        ps.pHtot = CO2_TA(CO2=ps.CO2,
                          TA=ps.TA,
                          BT=ps.BT,
                          TP=ps.TP,
                          TSi=ps.TSi,
                          TS=ps.TS,
                          TF=ps.TF,
                          Ks=ps.Ks)
        ps.H = ch(ps.pHtot)
        ps.DIC = CO2_pH(ps.CO2, ps.pHtot, ps.Ks)
    # 5. ps.CO2 and ps.DIC
    elif ps.CO2 is not None and ps.DIC is not None:
        ps.H = CO2_DIC(ps.CO2, ps.DIC, ps.Ks)
    # 6. ps.pHtot and ps.HCO3
    elif ps.pHtot is not None and ps.HCO3 is not None:
        ps.H = ch(ps.pHtot)
        ps.DIC = pH_HCO3(ps.pHtot, ps.HCO3, ps.Ks)
    # 7. ps.pHtot and ps.CO3
    elif ps.pHtot is not None and ps.CO3 is not None:
        ps.H = ch(ps.pHtot)
        ps.DIC = pH_CO3(ps.pHtot, ps.CO3, ps.Ks)
    # 8. ps.pHtot and ps.TA
    elif ps.pHtot is not None and ps.TA is not None:
        ps.H = ch(ps.pHtot)
        ps.DIC = pH_TA(pH=ps.pHtot,
                       TA=ps.TA,
                       BT=ps.BT,
                       TP=ps.TP,
                       TSi=ps.TSi,
                       TS=ps.TS,
                       TF=ps.TF,
                       Ks=ps.Ks)
    # 9. ps.pHtot and ps.DIC
    elif ps.pHtot is not None and ps.DIC is not None:
        ps.H = ch(ps.pHtot)
    # 10. ps.HCO3 and ps.CO3
    elif ps.HCO3 is not None and ps.CO3 is not None:
        ps.H = HCO3_CO3(ps.HCO3, ps.CO3, ps.Ks)
        ps.DIC = pH_CO3(cp(ps.H), ps.CO3, ps.Ks)
    # 11. ps.HCO3 and ps.TA
    elif ps.HCO3 is not None and ps.TA is not None:
        Warning(
            'Nutrient alkalinity not implemented for this input combination.\nCalculations use only C and B alkalinity.'
        )
        ps.H = HCO3_TA(ps.HCO3, ps.TA, ps.BT, ps.Ks)
        ps.DIC = pH_HCO3(cp(ps.H), ps.HCO3, ps.Ks)
    # 12. ps.HCO3 amd ps.DIC
    elif ps.HCO3 is not None and ps.DIC is not None:
        ps.H = HCO3_DIC(ps.HCO3, ps.DIC, ps.Ks)
    # 13. ps.CO3 and ps.TA
    elif ps.CO3 is not None and ps.TA is not None:
        Warning(
            'Nutrient alkalinity not implemented for this input combination.\nCalculations use only C and B alkalinity.'
        )
        ps.H = CO3_TA(ps.CO3, ps.TA, ps.BT, ps.Ks)
        ps.DIC = pH_CO3(cp(ps.H), ps.CO3, ps.Ks)
    # 14. ps.CO3 and ps.DIC
    elif ps.CO3 is not None and ps.DIC is not None:
        ps.H = CO3_DIC(ps.CO3, ps.DIC, ps.Ks)
    # 15. ps.TA and ps.DIC
    elif ps.TA is not None and ps.DIC is not None:
        ps.pHtot = TA_DIC(TA=ps.TA,
                          DIC=ps.DIC,
                          BT=ps.BT,
                          TP=ps.TP,
                          TSi=ps.TSi,
                          TS=ps.TS,
                          TF=ps.TF,
                          Ks=ps.Ks)
        ps.H = ch(ps.pHtot)

    # The above makes sure that DIC and H are known,
    # this next bit calculates all the missing species
    # from DIC and H.
    if ps.CO2 is None:
        ps.CO2 = cCO2(ps.H, ps.DIC, ps.Ks)
    if ps.fCO2 is None:
        ps.fCO2 = CO2_to_fCO2(ps.CO2, ps.Ks)
    if ps.pCO2 is None:
        ps.pCO2 = fCO2_to_pCO2(ps.fCO2, ps.T)
    if ps.HCO3 is None:
        ps.HCO3 = cHCO3(ps.H, ps.DIC, ps.Ks)
    if ps.CO3 is None:
        ps.CO3 = cCO3(ps.H, ps.DIC, ps.Ks)
    # Always calculate elements of alkalinity
    try:
        # necessary for use with CBsyst in special cases
        # where BT is not known before Csys is run.
        (ps.TA, ps.CAlk, ps.BAlk, ps.PAlk, ps.SiAlk, ps.OH, ps.Hfree, ps.HSO4,
         ps.HF) = cTA(H=ps.H,
                      DIC=ps.DIC,
                      BT=ps.BT,
                      TP=ps.TP,
                      TSi=ps.TSi,
                      TS=ps.TS,
                      TF=ps.TF,
                      Ks=ps.Ks,
                      mode='multi')
    except TypeError:
        pass
    if ps.pHtot is None:
        ps.pHtot = np.array(cp(ps.H), ndmin=1)
        # Calculate other pH scales
        ps.update(
            calc_pH_scales(ps.pHtot, ps.pHfree, ps.pHsws, ps.TS, ps.TF, ps.Ks))

    # clean up for output
    for k in [
            'BT', 'CO2', 'CO3', 'Ca', 'DIC', 'H', 'HCO3', 'Mg', 'S', 'T', 'TA',
            'CAlk', 'PAlk', 'SiAlk', 'OH'
    ]:
        if not isinstance(ps[k], np.ndarray):
            # convert all outputs to (min) 1D numpy arrays.
            ps[k] = np.array(ps[k], ndmin=1)
    if ps.unit != 1:
        for p in upar + [
                'CAlk', 'BAlk', 'PAlk', 'SiAlk', 'OH', 'HSO4', 'HF', 'Hfree'
        ]:
            ps[p] *= ps.unit  # convert back to input units

    # remove some superfluous outputs
    rem = ['pdict']
    for r in rem:
        if r in ps:
            del ps[r]

    return ps
Esempio n. 2
0
def Bsys(
    pHtot=None,
    BT=None,
    BO3=None,
    BO4=None,
    ABT=None,
    ABO3=None,
    ABO4=None,
    dBT=None,
    dBO3=None,
    dBO4=None,
    alphaB=None,
    T_in=25.0,
    S_in=35.0,
    P_in=None,
    T_out=None,
    S_out=None,
    P_out=None,
    Ca=None,
    Mg=None,
    TS=None,
    TF=None,
    pHsws=None,
    pHfree=None,
    pHNBS=None,
    Ks=None,
    pdict=None,
):
    """
    Calculate the boron chemistry of seawater from a minimal parameter set.

    Constants calculated by MyAMI model (Hain et al, 2015; doi:10.1002/2014GB004986).
    Speciation calculations from Zeebe & Wolf-Gladrow (2001; ISBN:9780444509468).

    pH is Total scale.

    Inputs must either be single values, arrays of equal length or a mixture of both.
    If you use arrays of unequal length, it won't work.

    Error propagation:
    If inputs are ufloat or uarray (from uncertainties package) errors will
    be propagated through all calculations.

    Concentration Units
    +++++++++++++++++++
    * All concentrations must be in the same units. Returned in the same units as inputs.

    Parameters
    ----------
    pH, BT, BO3, BO4 : array-like
        Boron system parameters. Two of these must be provided.
    dBT, dBO3, dBO4, ABT, ABO3, ABO4 : array-like
        delta (d) or fractional abundance (A) values for the Boron
        isotope system. One of these must be provided.
    alphaB : array-like
        The alpha value for BO3-BO4 isotope fractionation.
    T, S : array-like
        Temperature in Celcius and Salinity in PSU.
        Used in calculating MyAMI constants.
    P : array-like
        Pressure in Bar.
        Used in calculating MyAMI constants.
    Ca, Mg : arra-like
        The [Ca] and [Mg] of the seawater, in mol / kg.
        Used in calculating MyAMI constants.
    Ks : dict
        A dictionary of constants. Must contain keys
        'K1', 'K2', 'KB' and 'KW'.
        If None, Ks are calculated using MyAMI model.
    pdict : dict
        Optionally, you can provide some or all parameters as a dict,
        with keys the same as the parameter names above. Any parameters
        included in the dict will overwrite manually specified
        parameters. This is particularly useful if you're including
        this in other code.

    Returns
    -------
    dict(/Bunch) containing all calculated parameters.
    """
    # input checks
    if NnotNone(BT, BO3, BO4) < 1:
        raise ValueError("Must provide at least one of BT, BO3 or BO4")
    if NnotNone(dBT, dBO3, dBO4, ABT, ABO3, ABO4) < 1:
        raise ValueError(
            "Must provide one of dBT, dBO3, dBO4, ABT, ABO3 or ABO4")

    # Bunch inputs
    ps = Bunch(locals())
    if isinstance(pdict, dict):
        ps.update(pdict)

    # Conserved seawater chemistry
    if ps.TS is None:
        ps.TS = calc_TS(ps.S_in)
    if ps.TF is None:
        ps.TF = calc_TF(ps.S_in)

    # Calculate Ks
    ps.Ks = calc_Ks(ps.T_in, ps.S_in, ps.P_in, ps.Mg, ps.Ca, ps.TS, ps.TF,
                    ps.Ks)

    # Calculate pH scales (does nothing if none pH given)
    ps.update(
        calc_pH_scales(
            ps.pHtot,
            ps.pHfree,
            ps.pHsws,
            ps.pHNBS,
            ps.TS,
            ps.TF,
            ps.T_in + 273.15,
            ps.S_in,
            ps.Ks,
        ))

    ps.update(
        calc_B_species(pHtot=ps.pHtot,
                       BT=ps.BT,
                       BO3=ps.BO3,
                       BO4=ps.BO4,
                       Ks=ps.Ks))

    # If pH not calced yet, calculate on all scales
    if ps.pHtot is None:
        ps.pHtot = np.array(cp(ps.H), ndmin=1)
        # Calculate other pH scales
        ps.update(
            calc_pH_scales(
                ps.pHtot,
                ps.pHfree,
                ps.pHsws,
                ps.pHNBS,
                ps.TS,
                ps.TF,
                ps.T_in + 273.15,
                ps.S_in,
                ps.Ks,
            ))

    # If any isotope parameter specified, calculate the isotope systen.
    if NnotNone(ps.ABT, ps.ABO3, ps.ABO4, ps.dBT, ps.dBO3, ps.dBO4) != 0:
        ps.update(ABsys(pdict=ps))

    for k in ["BT", "H", "BO3", "BO4", "Ca", "Mg", "S_in", "T_in"]:
        # convert all outputs to (min) 1D numpy arrays.
        if not isinstance(ps[k], np.ndarray):
            # convert all outputs to (min) 1D numpy arrays.
            ps[k] = np.array(ps[k], ndmin=1)

    # remove some superfluous outputs
    rem = ["pdict"]
    for r in rem:
        if r in ps:
            del ps[r]

    return ps
Esempio n. 3
0
def Bsys(pHtot=None,
         BT=None,
         BO3=None,
         BO4=None,
         ABT=None,
         ABO3=None,
         ABO4=None,
         dBT=None,
         dBO3=None,
         dBO4=None,
         alphaB=None,
         T=25.,
         S=35.,
         P=None,
         Ca=None,
         Mg=None,
         pHsws=None,
         pHfree=None,
         Ks=None,
         pdict=None):
    """
    Calculate the boron chemistry of seawater from a minimal parameter set.

    Constants calculated by MyAMI model (Hain et al, 2015; doi:10.1002/2014GB004986).
    Speciation calculations from Zeebe & Wolf-Gladrow (2001; ISBN:9780444509468).

    pH is Total scale.

    Inputs must either be single values, arrays of equal length or a mixture of both.
    If you use arrays of unequal length, it won't work.

    Error propagation:
    If inputs are ufloat or uarray (from uncertainties package) errors will
    be propagated through all calculations.

    Concentration Units
    +++++++++++++++++++
    * All concentrations must be in the same units. Returned in the same units as inputs.

    Parameters
    ----------
    pH, BT, BO3, BO4 : array-like
        Boron system parameters. Two of these must be provided.
    T, S : array-like
        Temperature in Celcius and Salinity in PSU.
        Used in calculating MyAMI constants.
    P : array-like
        Pressure in Bar.
        Used in calculating MyAMI constants.
    Ca, Mg : arra-like
        The [Ca] and [Mg] of the seawater, in mol / kg.
        Used in calculating MyAMI constants.
    Ks : dict
        A dictionary of constants. Must contain keys
        'K1', 'K2', 'KB' and 'KW'.
        If None, Ks are calculated using MyAMI model.
    pdict : dict
        Optionally, you can provide some or all parameters as a dict,
        with keys the same as the parameter names above. Any parameters
        included in the dict will overwrite manually specified
        parameters. This is particularly useful if you're including
        this in other code.

    Returns
    -------
    dict(/Bunch) containing all calculated parameters.
    """

    # Bunch inputs
    ps = Bunch(locals())
    if isinstance(pdict, dict):
        ps.update(pdict)

    # Conserved seawater chemistry
    if 'TS' not in ps:
        ps.TS = calc_TS(ps.S)
    if 'TF' not in ps:
        ps.TF = calc_TF(ps.S)

    # if neither Ca nor Mg provided, use default Ks
    ps.Ks = get_Ks(ps)

    # Calculate pH scales (does nothing if none pH given)
    ps.update(
        calc_pH_scales(ps.pHtot, ps.pHfree, ps.pHsws, ps.TS, ps.TF, ps.Ks))

    # B system calculations
    if ps.pHtot is not None and ps.BT is not None:
        ps.H = ch(ps.pHtot)
    elif ps.BT is not None and ps.BO3 is not None:
        ps.H = BT_BO3(ps.BT, ps.BO3, ps.Ks)
    elif ps.BT is not None and ps.BO4 is not None:
        ps.H = BT_BO4(ps.BT, ps.BO4, ps.Ks)
    elif ps.BO3 is not None and ps.BO4 is not None:
        ps.BT = ps.BO3 + ps.BO3
        ps.H = BT_BO3(ps.BT, ps.BO3, ps.Ks)
    elif ps.pHtot is not None and ps.BO3 is not None:
        ps.H = ch(ps.pHtot)
        ps.BT = pH_BO3(ps.pHtot, ps.BO3, ps.Ks)
    elif ps.pHtot is not None and ps.BO4 is not None:
        ps.H = ch(ps.pHtot)
        ps.BT = pH_BO4(ps.pHtot, ps.BO4, ps.Ks)

    # The above makes sure that BT and H are known,
    # this next bit calculates all the missing species
    # from BT and H.
    if ps.BO3 is None:
        ps.BO3 = cBO3(ps.BT, ps.H, ps.Ks)
    if ps.BO4 is None:
        ps.BO4 = cBO4(ps.BT, ps.H, ps.Ks)
    if ps.pHtot is None:
        ps.pHtot = np.array(cp(ps.H), ndmin=1)
        # Calculate other pH scales
        ps.update(
            calc_pH_scales(ps.pHtot, ps.pHfree, ps.pHsws, ps.TS, ps.TF, ps.Ks))

    if NnotNone(ps.ABT, ps.ABO3, ps.ABO4, ps.dBT, ps.dBO3, ps.dBO4) != 0:
        ps.update(ABsys(pdict=ps))

    for k in ['BT', 'H', 'BO3', 'BO4', 'Ca', 'Mg', 'S', 'T']:
        # convert all outputs to (min) 1D numpy arrays.
        if not isinstance(ps[k], np.ndarray):
            # convert all outputs to (min) 1D numpy arrays.
            ps[k] = np.array(ps[k], ndmin=1)

    # remove some superfluous outputs
    rem = ['pdict']
    for r in rem:
        if r in ps:
            del ps[r]

    return ps