Пример #1
0
 def _formula_parse_iso(self):
     'Parse chemical formula of the salt and get list of all isotopes'
     tot_moles: float = 0.0  # Total molar fraction, should add to 1
     for meltpart in self.formula.split('+'):  # Separate melt components
         mfract, comp = meltpart.split(
             '%')  # Separate component pct. fractions
         mfract = float(mfract) / 100.0  # Molar % -> fraction
         tot_moles += mfract  # Add molar fractions of compositions
         comp_f = molmass.Formula(
             comp)  # Turn component into a molmass formula
         for symbol in comp_f._elements:  # Elements in a component
             ele = self.ELEMENTS[symbol]  # Get the element object
             for m, n_atoms in comp_f._elements[symbol].items(
             ):  # Number of atoms in a component
                 if (m != 0):  # This should be zero per molmass
                     raise Exception("Error in parsing")
                 for A in ele.isotopes.keys():  # Get data for each isotope
                     Z = ele.protons
                     amass = ele.isotopes[A].mass
                     wfrac = ele.isotopes[A].abundance
                     if wfrac > 0.0:
                         isotuple = self.SaltIso(Z, A, n_atoms, amass,
                                                 wfrac, mfract)
                         self.isolist.append(isotuple)
     self.isolist.sort()  # Looks nicer sorted
     if abs(tot_moles - 1.0) > 1e-5:  # Sanity check
         raise ValueError("User Error: Formula " + self.formula +
                          " molar fractions do not add to 1.0!")
Пример #2
0
 def formula(self):
     """
 >>> a = InChI('InChI=1S/C4H6O4.2Na/c5-3(6)1-2-4(7)8;;/h1-2H2,(H,5,6)(H,7,8);;/q;2*+1/p-2')
 >>> print a.formula
 C4H4Na2O4
 >>> a = InChI('InChI=1S/C4H6O4.2Na/c5-3(6)1-2-4(7)8;;/h1-2H2,(H,5,6)(H,7,8);;/q;2*+1/p-2', 'H2O')
 >>> print a.formula
 H2O
 """
     if self.__formula is None:
         self.__formula = convert_inchi_to_formula(self.__inchi)
     return molmass.Formula(self.__formula)
Пример #3
0
def ppm_to_ugm3(da, da_T2, da_PSFC):

    name = da.name
    new_attrs = da.attrs

    # get variables needed
    chem = da.name.upper()
    M = molmass.Formula(chem).mass
    R = 8.3145

    # convert unit ppmv -> µg/m³
    da = (M * da_PSFC * da) / (R * da_T2)

    # update attributes with new units
    new_attrs['units'] = 'ug m^-3'
    new_attrs['description'] = chem + \
                               ' mixing ratio converted to mass concentration'
    da.attrs = new_attrs
    da.name = name

    return (da)
Пример #4
0
def analyze(formula, maxatoms=250):
    """Return analysis of formula as HTML string."""
    def html(formula):
        """Return formula as HTML string."""
        formula = re.sub(r'\[(\d+)([A-Za-z]{1,2})\]', r'<sup>\1</sup>\2',
                         formula)
        formula = re.sub(r'([A-Za-z]{1,2})(\d+)', r'\1<sub>\2</sub>', formula)
        return formula

    result = []
    try:
        f = molmass.Formula(formula)
        result.append(
            f'<p><strong>Hill notation</strong>: {html(f.formula)}</p>')
        if f.formula != f.empirical:
            result.append(f'<p><strong>Empirical formula</strong>:'
                          f' {html(f.empirical)}</p>')

        prec = molmass.precision_digits(f.mass, 8)
        if f.mass != f.isotope.mass:
            result.append(
                f'<p><strong>Average mass</strong>: {f.mass:.{prec}f}</p>')
        result.extend((
            f'<p><strong>Monoisotopic mass</strong>:'
            f' {f.isotope.mass:.{prec}f}</p>',
            f'<p><strong>Nominal mass</strong>:'
            f' {f.isotope.massnumber}</p>',
        ))

        c = f.composition()
        if len(c) > 1:
            result.extend((
                '<h3>Elemental Composition</h3>'
                '<table border="0" cellpadding="2">',
                '<tr>',
                '<th scope="col" align="left">Element</th>',
                '<th scope="col" align="right">Number</th>',
                '<th scope="col" align="right">Relative mass</th>',
                '<th scope="col" align="right">Fraction %</th>',
                '</tr>',
            ))

            for symbol, count, mass, fraction in c:
                symbol = re.sub(r'^(\d+)(.+)', r'<sup>\1</sup>\2', symbol)
                result.extend((
                    f'<tr><td>{symbol}</td>',
                    f'<td align="center">{count}</td>',
                    f'<td align="right">{mass:.{prec}f}</td>',
                    f'<td align="right">{fraction * 100:.4f}</td></tr>',
                ))

            count, mass, fraction = c.total
            result.extend((
                '<tr><td><em>Total</em></td>',
                f'<td align="center"><em>{count}</em></td>',
                f'<td align="right"><em>{mass:.{prec}f}</em></td>',
                f'<td align="right"><em>{fraction * 100:.4f}</em></td>',
                '</tr>',
                '</table>',
            ))

        if f.atoms < maxatoms:
            s = f.spectrum()
            if len(s) > 1:
                norm = 100.0 / s.peak[1]
                result.extend((
                    '<h3>Mass Distribution</h3>',
                    '<p><strong>Most abundant mass</strong>: ',
                    f'{s.peak[0]:.{prec}f} ({s.peak[1] * 100:.3f}%)</p>',
                    f'<p><strong>Mean mass</strong>: {s.mean:.{prec}}</p>',
                    '<table border="0" cellpadding="2">',
                    '<tr>',
                    '<th scope="col" align="left">Relative mass</th>',
                    '<th scope="col" align="right">Fraction %</th>',
                    '<th scope="col" align="right">Intensity</th>',
                    '</tr>',
                ))
                for mass, fraction in s.values():
                    result.extend((
                        f'<tr><td>{mass:.{prec}f}</td>',
                        f'<td align="right">{fraction*100.:.6}</td>',
                        f'<td align="right">{fraction*norm:.6}</td></tr>',
                    ))
                result.append('</table>')

    except Exception as exc:
        exc = str(exc).splitlines()
        text = exc[0][0].upper() + exc[0][1:]
        details = '\n'.join(exc[1:])
        result.append('<h2>Error</h2><p>{}</p><pre>{}</pre>'.format(
            escape(text, True), escape(details, True)))

    return '\n'.join(result)
Пример #5
0
 def formula(self):
     return molmass.Formula(self.__formula)
Пример #6
0
def _weight(x):
    return molmass.Formula(x).mass * si.gram / si.mole
Пример #7
0
def unit_conversion_ratio(df,
                          unit_conversion_factor={},
                          feature_units={},
                          **kwargs):
    """Compute conversion factor between original units and new units (used by hgc)."""
    # generate a temporary dataframe to compute ratios
    df2 = pd.DataFrame()

    # split units into inidivual symbols (incl. prefix) and fill NaN
    df2[['orig1', 'orig2', 'orig3']] = df['Unit_orig0'].fillna('').str.split(
        r"/| ", expand=True, n=2).reindex(columns=range(3)).copy()
    df2[['new1', 'new2', 'new3']] = df['Unit'].fillna('').str.split(
        r"/| ", expand=True, n=2).reindex(columns=range(3)).copy()
    df2.loc[:, 'unit_conversion_correct'] = True

    for orig, new in {'orig1': 'new1', 'orig2': 'new2'}.items():
        # force column to string (for example 1/m --> '1', 'm')
        df2[orig] = df2[orig].fillna('').astype(str)
        df2[new] = df2[new].fillna('').astype(str)

        # replace non-dimensional units by "1"
        df2[orig] = df2[orig].replace(['n', '-', '', ' '], '1').astype(str)
        df2[new] = df2[new].replace(['n', '-', '', ' '], '1').astype(str)

        # find where to correct for "mol"
        maska = df2[orig].str.contains("mol")
        maskb = df2[new].str.contains("mol")
        mask = maska | maskb

        # compute ratio mol --> gram
        features = df['Feature'][mask].unique()
        map_molwt = {}
        for feature in features:
            try:
                map_molwt[feature] = molmass.Formula(feature).mass
            except:  # in case feature is not a chemical formula
                map_molwt[feature] = np.nan

        df2[orig + 'ratio'] = np.where(maska, df['Feature'].map(map_molwt), 1.)
        df2[new + 'ratio'] = np.where(maskb, df['Feature'].map(map_molwt), 1.)

        # log errors
        df2.loc[df2[orig + 'ratio'].isnull(),
                'unit_conversion_correct'] = False
        df2.loc[df2[new + 'ratio'].isnull(), 'unit_conversion_correct'] = False

        # replace mol by gram (to prevent error in next step) and remove N, P, S
        df2[orig] = df2[orig].str.replace('mol', 'g')
        df2[new] = df2[new].str.replace('mol', 'g')
        df2.loc[maska, 'orig3'] = ''
        df2.loc[maskb, 'new3'] = ''

        # compute unit conversion ratio
        df2[orig +
            'ratio'] = df2[orig +
                           'ratio'] * df2[orig].map(unit_conversion_factor)
        df2[new +
            'ratio'] = df2[new +
                           'ratio'] * df2[new].map(unit_conversion_factor)

        # log errors. If orig and new both np.nan --> replace ratio's by 1
        df2.loc[df2[orig + 'ratio'].isnull() | df2[new + 'ratio'].isnull(),
                'unit_conversion_correct'] = False
        df2.loc[(df2[orig] == '') & (df2[new] == ''),
                [orig + 'ratio', new + 'ratio']] = 1.

        # there is no error if the units are on purpose empty (eg ph)
        df2.loc[(df['Unit'] == '1') & (df['Unit_orig0'] == '1'),
                'unit_conversion_correct'] = True

    # force column to string
    df2['orig3'] = df2['orig3'].fillna('').astype(str)
    df2['new3'] = df2['new3'].fillna('').astype(str)

    # find where to compute N, P, S, correction factor (for example mg/L N --> mg/L)
    mask3a = df2['orig3'] != ''
    mask3b = df2['new3'] != ''
    mask3 = mask3a | mask3b

    df2.loc[mask3 & ~mask3a, 'orig3'] = df['Feature']
    df2.loc[mask3 & ~mask3b, 'new3'] = df['Feature']

    # compute weight of atoms/ features
    atoms = pd.unique(df2[['orig3', 'new3']][mask3].values.ravel())
    map_molwt3 = {}
    for atom in atoms:
        if atom == 'PO4_ortho':
            atom = 'PO4'
        try:
            map_molwt3[atom] = molmass.Formula(atom).mass
        except:  # in case atom is not a chemical formula
            map_molwt3[atom] = np.nan

    df2['orig3ratio'] = np.where(mask3, df2['orig3'].map(map_molwt3), 1.)
    df2['new3ratio'] = np.where(mask3, df2['new3'].map(map_molwt3), 1.)

    # log errors
    df2.loc[df2['orig3ratio'].isnull(), 'unit_conversion_correct'] = False
    df2.loc[df2['new3ratio'].isnull(), 'unit_conversion_correct'] = False

    # Compute ratio, set ratio to 1 if original and desired unit are equal
    df['Ratio'] = ((df2['orig1ratio'] / df2['new1ratio']) *
                   (df2['new2ratio'] / df2['orig2ratio']) *
                   (df2['new3ratio'] / df2['orig3ratio']))
    df['Ratio'] = np.where(
        (df['Unit_orig'] == df['Unit']) | (df['Unit_orig0'] == df['Unit']), 1.,
        df['Ratio'])

    return df