Пример #1
0
def test():
    # Regression test: make sure neutron sld is an isotope property
    # Note: it is important that this test be run separately
    D2O = periodictable.formula('D2O',density=20./18)
    D2O_coh,D2O_abs,D2O_inc = periodictable.neutron_sld(D2O)
    D2O_coh2,D2O_abs2,D2O_inc2 = periodictable.neutron_sld(D2O)
    H2O = periodictable.formula('H2O',density=1)
    H2O_coh,H2O_abs,H2O_inc = periodictable.neutron_sld(H2O)
    assert D2O_coh == D2O_coh2
    assert D2O_coh != H2O_coh
Пример #2
0
def get_formula(data,scale=False):
    """
    recursivily create formula
    
    Parameters
    ----------
    data : list, dict, or string
     if string, get formula of string.
     if list, of form [(formula,mass_frac),...]
     if dict, of form {formula:mass_frac,...}
     
    scale : bool
     if false, don't scale mix (default)
     if true, scale mix
     
    Returns
    -------
    formula : periodic.table.Formula
    """
    if isinstance(data,PTFormula):
        return data
    elif isinstance(data,Compound):
        return data.formula
    elif _is_string_like(data):
        return PT.formula(data)
    elif _is_list_like(data):
        pairs = data[:]
    elif _is_dict_like(data):
        pairs = list(data.iteritems())
    
    else:
        raise ValueError('bad formula',data)


    pairs = [(get_formula(f),m) for f,m in pairs if m>0]

    result = PT.formula()
    if len(pairs) > 0:
        # cell mass = mass
        # target mass = q
        # cell mass * n = target mass
        #   => n = target mass / cell mass
        #        = q / mass
        if scale: 
            scale = min(q/f.mass for f,q in pairs)
        else:
            scale = 1.0
        for f,q in pairs:
            result += ((q/f.mass)/scale) * f
        if all(f.density for f,_ in pairs):
            volume = sum(q/f.density for f,q in pairs)/scale
            result.density = result.mass/volume
    return result
def simple_oxides(cation, output='formula'):
    """
    Creates a list of oxides for a cationic element
    (oxide of ions with c=1+ and above).
    """
    if not isinstance(cation, pt.core.Element):
        catstr = titlecase(cation)  # edge case of lowercase str such as 'cs'
        cation = getattr(pt, catstr)

    ions = [c for c in cation.ions if c > 0]  # Use only positive charges
    oxides = [pt.formula(f'{cation}{1}O{c//2}') if not c%2
              else pt.formula(f'{cation}{2}O{c}') for c in ions]
    if not output == 'formula':
        oxides = [ox.__str__() for ox in oxides]
    return oxides
Пример #4
0
 def setUp(self):
     """Inititialze variables"""
     # the calculator default value for wavelength is 6
     self.compound = "Cd"
     self.density = 4.0
     self.wavelength = 6.0
     self.sld_formula = formula(self.compound, density=self.density)
def get_cations(oxide, exclude=['O']):
    """
    Returns the principal cations in an oxide component.
    """
    atms = pt.formula(oxide).atoms
    cations = [el for el in atms.keys() if not el.__str__() in exclude]
    return cations
Пример #6
0
    def calculate_xray_sld(self, element):
        """
        Get an element and compute the corresponding SLD for a given formula

        :param element:  elements a string of existing atom

        """
        myformula = formula(str(element))
        if len(myformula.atoms) != 1:
            return
        element = myformula.atoms.keys()[0]
        energy = xray_energy(element.K_alpha)

        self.sld_formula = formula(str(self.compound), density=self.density)
        atom = self.sld_formula.atoms
        return xray_sld_from_atoms(atom, density=self.density, energy=energy)
Пример #7
0
    def retrieving_molecular_mass_and_number_of_atoms_worked(self, chemical_formula):
        '''this method will parse the formula to go from Nantid format to periodictable library format, in order
        to calculate the molecular mass

        return: True if the string has been correctly formatted
        False if something went wrong

        '''
        list_element = chemical_formula.split(" ")
        periodictable_list_element_format = []
        total_number_of_atoms = 0.
        try:
            for _element in list_element:
                [formated_element, number_of_atoms] = self.get_periodictable_formatted_element_and_number_of_atoms(_element)
                periodictable_list_element_format.append(formated_element)
                total_number_of_atoms += number_of_atoms

            periodictable_format = " ".join(periodictable_list_element_format)
            periodictable_formula = formula(periodictable_format)
            self.molecular_mass = periodictable_formula.mass
            self.total_number_of_atoms = total_number_of_atoms
            return True

        except:
            return False
Пример #8
0
 def setUp(self):
     """Inititialze variables"""
     
     self.compound = "D2O"
     self.density = 1.1
     self.wavelength = 6.0
     self.sld_formula = formula(self.compound, density=self.density)
Пример #9
0
def test_formula():
    M = formula('B4C', density=2.52)
    sld,xs,depth = neutron_scattering(M,wavelength=4.75)
    # Compare to Alan Munter's numbers:
    #   SLD=7.65e-6 - 2.34e-7i /A^2
    #   inc,abs XS = 0.193, 222.4 / cm
    #   1/e = 0.004483 cm
    #   Cu/Mo K-alpha = 2.02e-5 + 1.93e-8i / 2.01e-5 + 4.64e-9i
    # Using lambda=1.798 rather than 1.8
    #   abs XS => 222.6
    #   1/e => 0.004478
    assert abs(sld[0]-7.649)<0.001
    assert abs(sld[1]-0.234)<0.001
    assert abs(xs[1]-222.6)<0.1
    #assert abs(xs[2]-0.193)<0.001   # TODO: fix test
    #assert abs(depth-0.004478)<0.000001 # TODO: fix test
    # Check that sld_inc and coh_xs are consistent
    #   cell_volume = (molar_mass/density) / N_A * 1e24
    #   number_density = num_atoms/cell_volume
    #   sigma_i = inc_xs/number_density
    #   sld_inc = number_density * sqrt ( 100/(4*pi) * sigma_i ) * 10
    #   sld_re = number_density * b_c * 10
    #   sigma_c = 4*pi/100*b_c**2
    #   coh_xs = sigma_c * number_density
    Nb = 0.13732585020640778
    sld_inc = Nb*sqrt(100/(4*pi)*xs[2]/Nb)*10
    coh_xs = Nb*4*pi/100*(sld[0]/(10*Nb))**2
    assert abs(sld[2] - sld_inc) < 1e-14
    assert abs(xs[0] - coh_xs) < 1e-14
Пример #10
0
def isotope_substitution(formula, source, target, portion=1):
    """
    Substitute one atom/isotope in a formula with another in some proportion.

    *formula* is the formula being updated.

    *source* is the isotope/element to be substituted.

    *target* is the replacement isotope/element.

    *portion* is the proportion of source which is substituted for target.
    """
    atoms = formula.atoms
    if source in atoms:
        mass = formula.mass
        mass_reduction = atoms[source]*portion*(source.mass - target.mass)
        density = formula.density * (mass - mass_reduction)/mass
        atoms[target] = atoms.get(target, 0) + atoms[source]*portion
        if portion == 1:
            del atoms[source]
        else:
            atoms[source] *= 1-portion
    else:
        density = formula.density
    return pt.formula(atoms, density=density)
Пример #11
0
 def __init__(self, formula=None, name=None, use_incoherent=False,
              density=None, natural_density=None,
              fitby='bulk_density', value=None):
     self.formula = periodictable.formula(formula, density=density,
                                          natural_density=natural_density)
     self.name = name if name is not None else str(self.formula)
     self.use_incoherent = use_incoherent
     self.fitby(type=fitby, value=value)
Пример #12
0
def molecule_table():
    # Table of scattering length densities for various molecules
    print("SLDS for some molecules")
    for molecule,density in [('SiO2',2.2),('B4C',2.52)]:
        atoms = formula(molecule).atoms
        rho,mu,inc = neutron_sld(atoms,density,wavelength=4.75)
        print("%s(%g g/cm**3)  rho=%.4g mu=%.4g inc=%.4g"
              %(molecule,density,rho,mu,inc))
Пример #13
0
def test_composite():
    from periodictable.nsf import neutron_composite_sld
    calc = neutron_composite_sld([formula(s) for s in ('HSO4','H2O','CCl4')],
                                 wavelength=4.75)
    sld = calc(numpy.array([3,1,2]),density=1.2)
    sld2 = neutron_sld('3HSO4+1H2O+2CCl4',density=1.2,wavelength=4.75)
    #print(sld)
    #print(sld2)
    assert all(abs(v-w)<1e-14 for v,w in zip(sld,sld2))
Пример #14
0
 def calculateSld(self, event):
     """
         Calculate the neutron scattering density length of a molecule
     """
     self.clear_outputs()
     try:
         #Check validity user inputs
         flag, msg = self.check_inputs()
         if self.base is not None and msg.lstrip().rstrip() != "":
             msg = "SLD Calculator: %s" % str(msg)
             wx.PostEvent(self.base, StatusEvent(status=msg))
         if not flag:
            return
         #get ready to compute
         self.sld_formula = formula(self.compound,
                                         density=self.density)
         (sld_real, sld_im, _), (_, absorp, incoh), \
                     length = neutron_scattering(compound=self.compound,
                                density=self.density,
                                wavelength=self.neutron_wavelength)
         if self.xray_source == "[A]":
             energy = xray_energy(self.xray_source_input)
             xray_real, xray_im = xray_sld_from_atoms(self.sld_formula.atoms,
                                                      density=self.density,
                                                      energy=energy)
         elif self.xray_source == "[keV]":
             xray_real, xray_im = xray_sld_from_atoms(self.sld_formula.atoms,
                                                      density=self.density,
                                                      energy=self.xray_source_input)
         elif self.xray_source == "Element":
             xray_real, xray_im = self.calculate_sld_helper(element=self.xray_source_input,
                                                            density=self.density,
                                                            molecule_formula=self.sld_formula)
         # set neutron sld values
         val = format_number(sld_real * _SCALE)
         self.neutron_sld_real_ctl.SetValue(val)
         val = format_number(math.fabs(sld_im) * _SCALE)
         self.neutron_sld_im_ctl.SetValue(val)
         # Compute the Cu SLD
         self.xray_sld_real_ctl.SetValue(format_number(xray_real * _SCALE))
         val = format_number(math.fabs(xray_im) * _SCALE)
         self.xray_sld_im_ctl.SetValue(val)
         # set incoherence and absorption
         self.neutron_inc_ctl.SetValue(format_number(incoh))
         self.neutron_abs_ctl.SetValue(format_number(absorp))
         # Neutron length
         self.neutron_length_ctl.SetValue(format_number(length))
         # display wavelength
         #self.wavelength_ctl.SetValue(str(self.wavelength))
         #self.wavelength_ctl.SetValue(str(self.wavelength))
     except:
         if self.base is not None:
             msg = "SLD Calculator: %s" % (sys.exc_value)
             wx.PostEvent(self.base, StatusEvent(status=msg))
     if event is not None:
         event.Skip()
def aggregate_cation(df, cation, form='oxide', unit_scale=10000):
    """
    Aggregates cation information from oxide and elemental components to a single series.
    Allows scaling (e.g. from ppm to wt% - a factor of 10,000).
    """
    elstr = cation.__str__()
    oxstr = [o for o in df.columns if o in simple_oxides(elstr, output='str')][0]
    el, ox = pt.formula(elstr), pt.formula(oxstr)
    
    if form == 'oxide':
        convert_function = swap_simple_oxide(ox, el)
        df.loc[:, oxstr] += convert_function(df.loc[:, elstr]) * unit_scale
        df = df.loc[:, [i for i in df.columns if not i == elstr]]
    elif form == 'element':
        convert_function = swap_simple_oxide(el, ox)
        df.loc[:, elstr] += convert_function(df.loc[:, oxstr]) * unit_scale
        df = df.loc[:, [i for i in df.columns if not i == oxstr]]
    
    return df
Пример #16
0
def time_composite():
    from periodictable.nsf import neutron_composite_sld
    import time
    calc = neutron_composite_sld([formula(s) for s in ('HSO4','H2O','CCl4')],
                                 wavelength=4.75)
    q = numpy.array([3,1,2])
    N = 1000
    bits = [formula(s) for s in ('HSO4','H2O','CCl4')]
    tic = time.time()
    for i in range(N):
        sld = calc(q,density=1.2)
    toc = time.time()-tic
    print("composite %.1f us"%(toc/N*1e6))
    tic = time.time()
    for i in range(N):
        sld = neutron_sld(q[0]*bits[0]+q[1]*bits[1]+q[2]*bits[2],
                          density=1.2,wavelength=4.75)
    toc = time.time()-tic
    print("direct %.1f us"%(toc/N*1e6))
Пример #17
0
 def __init__(self, parts=None):
     # Split [M1, N1, M2, N2, ...] into [M1, M2, ...], [N1, N2, ...]
     formula = [parts[i] for i in range(0, len(parts), 2)]
     count = [parts[i] for i in range(1, len(parts), 2)]
     # Convert M1, M2, ... to materials if necessary
     formula = [periodictable.formula(p) for p in formula]
     count = [Par.default(w, limits=(0, inf), name=str(f)+" count")
              for w, f in zip(count, formula)]
     self.parts = formula
     self.count = count
Пример #18
0
    def check_inputs(self):
        """Check validity user inputs"""
        flag = True
        msg = ""
        if check_float(self.density_ctl):
            self.density = float(self.density_ctl.GetValue())
        else:
            flag = False
            msg += "Error for Density value :expect float"

        self.wavelength = self.wavelength_ctl.GetValue()
        if str(self.wavelength).lstrip().rstrip() == "":
            self.wavelength = WAVELENGTH
            self.wavelength_ctl.SetValue(str(WAVELENGTH))
            self.wavelength_ctl.SetBackgroundColour(wx.WHITE)
            self.wavelength_ctl.Refresh()
            msg += "Default value for wavelength is 6.0"
        else:
            if check_float(self.wavelength_ctl):
                self.wavelength = float(self.wavelength)
            else:
                flag = False
                msg += "Error for wavelength value :expect float"

        self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
        if self.compound != "":
            try :
                formula(self.compound)
                self.compound_ctl.SetBackgroundColour(wx.WHITE)
                self.compound_ctl.Refresh()
            except:
                self.compound_ctl.SetBackgroundColour("pink")
                self.compound_ctl.Refresh()
                flag = False
                msg += "Enter correct formula"
        else:
            self.compound_ctl.SetBackgroundColour("pink")
            self.compound_ctl.Refresh()
            flag = False
            msg += "Enter a formula"
        return flag, msg
Пример #19
0
def calculate_xray_sld(element, density, molecule_formula):
    """
    Get an element and compute the corresponding SLD for a given formula
    :param element:  elements a string of existing atom
    """
    element_formula = formula(str(element))
    if len(element_formula.atoms) != 1:
        return 
    element = element_formula.atoms.keys()[0] 
    energy = xray_energy(element.K_alpha)
    atom = molecule_formula.atoms
    return xray_sld_from_atoms(atom, density=density, energy=energy)
Пример #20
0
def _nucleic_acid_average(bases, code_table):
    """
    Compute average over possible nucleotides, assuming equal weight if
    precise nucleotide is not known
    """
    n = len(bases)
    D, cell_volume = pt.formula(), 0
    for c in bases:
        D += code_table[c].formula
        cell_volume += code_table[c].cell_volume
    if n > 0: D, cell_volume = (1/n) * D, cell_volume/n
    return D, cell_volume
def to_molecular(df: pd.DataFrame, renorm=True):
    """
    Converts mass quantities to molar quantities of the same order.
    E.g.:
    mass% --> mol%
    mass-ppm --> mol-ppm
    """
    MWs = [pt.formula(c).mass for c in df.columns]
    if renorm:
         return renormalise(df.div(MWs))
    else:
        return df.div(MWs)
def to_weight(df: pd.DataFrame, renorm=True):
    """
    Converts molar quantities to mass quantities of the same order.
    E.g.:
    mol% --> mass%
    mol-ppm --> mass-ppm
    """
    MWs = [pt.formula(c).mass for c in df.columns]
    if renorm:
        return renormalise(df.multiply(MWs))
    else:
        return df.multiply(MWs)
Пример #23
0
def test():
    # Create private table
    private = PeriodicTable("mine")
    mass.init(private)
    density.init(private)
    xsf.init(private)
    nsf.init(private)
    crystal_structure.init(private)
    covalent_radius.init(private)

    # Test that it matches public table
    assert elements.Cm.mass == private.Cm.mass
    assert elements.Cm.density == private.Cm.density
    assert elements.Cm.crystal_structure == private.Cm.crystal_structure
    assert elements.Cm.covalent_radius == private.Cm.covalent_radius
    slde,abse = elements.Cm.xray.sld(energy=8)
    sldp,absp = private.Cm.xray.sld(energy=8)
    assert slde == sldp
    assert abse == absp

    # Check that modifications to private table don't change public table.
    private.Cm._mass = elements.Cm.mass+1
    assert elements.Cm.mass != private.Cm.mass
    private.Cm._density = elements.Cm.density+1
    assert elements.Cm.density != private.Cm.density
    private.Cm.covalent_radius = elements.Cm.covalent_radius+1
    assert elements.Cm.covalent_radius != private.Cm.covalent_radius
    private.Cm.xray.newfield = 5
    assert not hasattr(elements.Cm.xray,'newfield')

    # Check that the formula parser can use a private table
    privateH2O = formula('H2O', table=private)
    publicH2O = formula('H2O', table=elements)
    for el in privateH2O.atoms.keys():
        assert id(el) == id(private[el.number])
    assert privateH2O != publicH2O
    assert str(privateH2O) == str(publicH2O)
    assert privateH2O == publicH2O.change_table(private)
    private.H._mass = 1
    assert formula('H2',table=private).mass == 2
def recalculate_redox(df: pd.DataFrame,
                      to_oxidised=False,
                      renorm=True,
                      total_suffix='T'):
    """
    Recalculates abundances of redox-sensitive components (particularly Fe),
    and normalises a dataframe to contain only one oxide species for a given
    element.
    """
    # Assuming either (a single column) or (FeO + Fe2O3) are reported
    # Fe columns - FeO, Fe2O3, FeOT, Fe2O3T
    FeO = pt.formula("FeO")
    Fe2O3 = pt.formula("Fe2O3")
    dfc = df.copy()
    ox_species = ['Fe2O3', f"Fe2O3{total_suffix}"]
    ox_in_df = [i for i in ox_species if i in dfc.columns]
    red_species = ['FeO', f"FeO{total_suffix}"]
    red_in_df = [i for i in red_species if i in dfc.columns]
    if to_oxidised:
        oxFe = swap_simple_oxide(FeO, Fe2O3)
        Fe2O3T = dfc.loc[:, ox_in_df].fillna(0).sum(axis=1) + \
                 oxFe(dfc.loc[:, red_in_df].fillna(0)).sum(axis=1)
        dfc.loc[:, 'Fe2O3T'] = Fe2O3T
        to_drop = red_in_df + \
                  [i for i in ox_in_df if not i.endswith(total_suffix)]
    else:
        reduceFe = swap_simple_oxide(Fe2O3, FeO)
        FeOT = dfc.loc[:, red_in_df].fillna(0).sum(axis=1) + \
               reduceFe(dfc.loc[:, ox_in_df].fillna(0)).sum(axis=1)
        dfc.loc[:, 'FeOT'] = FeOT
        to_drop = ox_in_df + \
                  [i for i in red_in_df if not i.endswith(total_suffix)]

    dfc = dfc.drop(columns=to_drop)

    if renorm:
        return renormalise(dfc)
    else:
        return dfc
Пример #25
0
    def __init__(self, name, sequence, type='aa'):

        codes = _CODE_TABLES[type]
        parts = tuple(codes[c] for c in sequence)
        cell_volume = sum(p.cell_volume for p in parts)
        charge = sum(p.charge for p in parts)
        structure = []
        for p in parts: structure.extend(list(p.formula.structure))
        formula = pt.formula(structure).hill

        Molecule.__init__(self, name, formula, 
                          cell_volume=cell_volume, charge=charge)
        self.sequence = sequence
Пример #26
0
    def __init__(self, name, sequence, type='aa'):
        codes = CODE_TABLES[type]
        sequence = sequence.split('*', 1)[0]  # stop at first '*'
        sequence = sequence.replace(' ', '')  # ignore spaces
        parts = tuple(codes[c] for c in sequence)
        cell_volume = sum(p.cell_volume for p in parts)
        charge = sum(p.charge for p in parts)
        structure = []
        for p in parts:
            structure.extend(list(p.formula.structure))
        formula = pt.formula(structure).hill

        Molecule.__init__(self, name, formula,
                          cell_volume=cell_volume, charge=charge)
        self.sequence = sequence
Пример #27
0
def _code_average(bases, code_table):
    """
    Compute average over possible nucleotides, assuming equal weight if
    precise nucleotide is not known
    """
    n = len(bases)
    formula, cell_volume, charge = pt.formula(), 0, 0
    for c in bases:
        base = code_table[c]
        formula += base.formula
        cell_volume += base.cell_volume
        charge += base.charge
    if n > 0:
        formula, cell_volume, charge = (1/n) * formula, cell_volume/n, charge/n
    return formula, cell_volume, charge
Пример #28
0
    def calculate(self):
        try:
            formula = pt.formula(self.ui.chemical_formula.text(),)

        except (pyparsing.ParseException, TypeError, ValueError):
            return

        density = self.ui.mass_density.value()
        molecular_volume = self.ui.molecular_volume.value()
        neutron_wavelength = self.ui.neutron_wavelength.value()
        xray_energy = self.ui.xray_energy.value()

        if self.ui.use_volume.isChecked():
            density = formula.molecular_mass / formula.volume(
                a=molecular_volume,
                b=1,
                c=1)
            self.ui.mass_density.setValue(density)

        elif self.ui.use_density.isChecked():
            volume = formula.mass / density / \
                pt.constants.avogadro_number * 1e24
            self.ui.molecular_volume.setValue(volume)

        real, imag, mu = pt.neutron_sld(formula,
                                        density=density,
                                        wavelength=neutron_wavelength)

        self.ui.neutron_SLD.setText(
            '%.6g' %
            real +
            ' + ' +
            '%.6g' %
            imag +
            'j')

        real, imag = pt.xray_sld(formula,
                                 density=density,
                                 energy=xray_energy)

        self.ui.xray_SLD.setText('%.6g' % real + ' + ' + '%.6g' % imag + 'j')
Пример #29
0
    def __init__(self, name, formula, cell_volume=None, density=None, charge=0):
        # Fill in density or cell_volume
        M = pt.formula(formula, natural_density=density)
        if cell_volume != None:
            M.density = 1e24*M.molecular_mass/cell_volume if cell_volume>0 else 0
            #print name, M.molecular_mass, cell_volume, M.density
        else:
            cell_volume = 1e24*M.molecular_mass/M.density

        Hnatural = isotope_substitution(M, pt.T, pt.H)
        H = isotope_substitution(M, pt.T, pt.H[1])
        D = isotope_substitution(M, pt.T, pt.D)

        self.name = name
        self.formula = M
        self.cell_volume = cell_volume
        self.sld = pt.neutron_sld(Hnatural, wavelength=5)[0]
        self.Hsld = pt.neutron_sld(H, wavelength=5)[0]
        self.Dsld = pt.neutron_sld(D, wavelength=5)[0]
        self.mass, self.Hmass, self.Dmass = Hnatural.mass, H.mass, D.mass
        self.D2Omatch = D2Omatch(self.Hsld, self.Dsld)
        self.charge = charge
Пример #30
0
 def addElement(self, elementName, elementMols):
   """Add an element to the glass"""
   
   # raise exceptions
   if (elementMols <= 0):
     raise RuntimeError("elementMols must be positive")
   atoms = PT.formula(elementName).atoms
   if (len(atoms) != 1):
     raise RuntimeError("elementName must have only one atom")
   for i in atoms:
     if (atoms[i] != 1):
       raise RuntimeError("elementName must have only one atom")
   
   # determine if added element is new or already exists
   nameList = self._data["elements"]["name"]
   inList,index = F.findInList(elementName, nameList)
   if (inList):
     self._data["elements"]["mols"][index] += elementMols
   else:
     molecularWeight = PT.elements.symbol(elementName).mass
     self._data["elements"]["name"].append(elementName)
     self._data["elements"]["mols"].append(float(elementMols))
     self._data["elements"]["MW"].append(molecularWeight)
   self._checkSizes()
Пример #31
0
def endmember_decompose(composition,
                        endmembers=[],
                        drop_zeros=True,
                        molecular=True,
                        ord=1,
                        det_lim=0.0001):
    """
    Decompose a given mineral composition to given endmembers.

    Parameters
    -----------
    composition : :class:`~pandas.DataFrame` | :class:`~pandas.Series` | :class:`~periodictable.formulas.Formula` | :class:`str`
        Composition to decompose into endmember components.
    endmembers : :class:`str` | :class:`list` | :class:`dict`

    drop_zeros : :class:`bool`, :code:`True`
        Whether to omit components with zero estimated abundance.
    molecular : :class:`bool`, :code:`True`
        Whether to *convert* the chemistry to molecular before calculating the
        decomposition.
    ord : :class:`int`
        Order of regularization passed to :func:`unmix`, defaults to L1 for sparsity.
    det_lim : :class:`float`
        Detection limit, below which minor components will be omitted for sparsity.

    Returns
    ---------
    :class:`pandas.DataFrame`
    """
    # parse composition ----------------------------------------------------------------
    assert isinstance(composition,
                      (pd.DataFrame, pd.Series, pt.formulas.Formula, str))
    if not isinstance(composition,
                      pd.DataFrame):  # convert to a dataframe representation
        if isinstance(composition, pd.Series):
            # convert to frame
            composition = to_frame(composition)
        elif isinstance(composition, (pt.formulas.Formula, str)):
            formula = composition
            if isinstance(composition, str):
                formula = pt.formula(formula)

    # parse endmember compositions -----------------------------------------------------
    aliases = None
    if not endmembers:
        logger.warning(
            "No endmembers specified, using all minerals. Expect non-uniqueness."
        )
        # try a decomposition with all the minerals; this will be non-unique
        endmembers = list_minerals()

    if isinstance(endmembers, str):  # mineral group
        Y = get_mineral_group(endmembers).set_index("name")
    elif isinstance(endmembers, (list, set, dict, tuple)):
        if isinstance(endmembers, dict):
            aliases, endmembers = list(endmembers.keys()), list(
                endmembers.values())
        Y = pd.DataFrame([parse_composition(em) for em in endmembers],
                         index=aliases or endmembers)
    else:
        raise NotImplementedError("Unknown endmember specification format.")

    # calculate the decomposition ------------------------------------------------------
    X = renormalise(composition, scale=1.0)
    Y = renormalise(
        convert_chemistry(
            Y, to=composition.columns).loc[:, composition.columns].fillna(0),
        scale=1.0,
    )
    if molecular:
        X, Y = to_molecular(X), to_molecular(Y)
    # optimise decomposition into endmember components
    modal = pd.DataFrame(
        unmix(X.fillna(0).values, Y.fillna(0).values, ord=ord,
              det_lim=det_lim),
        index=X.index,
        columns=Y.index,
    )
    if drop_zeros:
        modal = modal.loc[:, modal.sum(axis=0) > 0.0]

    modal = renormalise(modal)
    return modal
Пример #32
0
    def __init__(self, name, sequence, type='aa'):

        codes = _CODE_TABLES[type]
        parts = tuple(codes[c] for c in sequence)
        cell_volume = sum(p.cell_volume for p in parts)
        charge = sum(p.charge for p in parts)
        structure = []
        for p in parts: structure.extend(list(p.formula.structure))
        formula = pt.formula(structure).hill

        Molecule.__init__(self, name, formula, 
                          cell_volume=cell_volume, charge=charge)
        self.sequence = sequence

# Water density at 20C; neutron wavelength doesn't matter (use 5 A).
H2O_SLD = pt.neutron_sld(pt.formula("[email protected]"),wavelength=5)[0]
D2O_SLD = pt.neutron_sld(pt.formula("[email protected]"),wavelength=5)[0]

def D2Omatch(H_sld, D_sld):
    """
    Find the D2O% concentration of solvent such that neutron SLD of the
    material matches the neutron SLD of the solvent.

    *H_sld*, *D_sld* are the SLDs for the hydrogenated and deuterated forms 
    of the material respectively, where *D* includes all the labile protons 
    swapped for deuterons.  Water SLD is calculated at 20 C.

    Note that the resulting percentage is only meaningful between 
    0% to 100%.  Beyond 100% you will need an additional constrast agent 
    in the 100% D2O solvent to increase the SLD enough to match.
    """
Пример #33
0
# Sample stack
sample = (glass(0, 7.460)
          | seed(22.9417, 8.817)
          | FePt(146.576, 8.604)
          | NiFe(508.784, 12.736)
          | cap(31.8477, 10.715)
          | air)

# Layers from the stack
Lglass, Lseed, LFePt, LNiFe, Lcap, Lair = sample

# grower values
if search == "grower":
    # Materials
    fPt = formula("Pt")
    fNiFe = formula("Ni80Fe20", density=0.8 * Ni.density + 0.2 * Fe.density)
    fFePt = formula("Fe55Pt45", density=0.55 * Fe.density + 0.45 * Pt.density)
    # Note: we have been given the Cu K-alpha SLD of the glass substrate
    # but the formula itself was not provided.  The common glass
    # preparations below do not come close to matching the given SLD
    # unless density is lowered to about 1.85.  Since most glass has
    # a density in [2.2, 2.5], none of these formulas can be used, and we
    # will restrict ourselves to an approximate SLD provided by the grower.
    #fglass = formula("SiO2",density=2.2)
    #fglass = mix_by_weight('SiO2',75,'Na2O',15,'CaO',10,density=2.52)
    #fglass = mix_by_weight('SiO2',73,'B2O3',10,'Na2O',8,'K2O',8,'CaO',1,density=2.2)
    glass_sld = 15, 0.5

    # Bulk SLD
    cap.rho.value, cap.irho.value = xray_sld(fPt, wavelength=Cu.K_alpha)
Пример #34
0
def test():
    H, He, D, O = elements.H, elements.He, elements.D, elements.O
    assert H.neutron.absorption == 0.3326
    assert H.neutron.total == 82.02
    assert H.neutron.incoherent == 80.26
    assert H.neutron.coherent == 1.7568
    assert elements.Ru[101].neutron.bp == None
    assert H[1].nuclear_spin == '1/2'
    assert H[2].nuclear_spin == '1'
    assert not H[6].neutron.has_sld()

    assert He[3].neutron.b_c_i == -1.48
    assert He[3].neutron.bm_i == -5.925

    Nb = elements.Nb
    assert Nb.neutron.absorption == Nb[93].neutron.absorption

    # Check that b_c values match abundance-weighted values
    # Note: Currently they do not for match within 5% for Ar,V,Sm or Gd
    for el in elements:
        if not hasattr(el, 'neutron'): continue
        b_c = 0
        complete = True
        for iso in el:
            if iso.neutron != None:
                if iso.neutron.b_c == None:
                    complete = False
                else:
                    b_c += iso.neutron.b_c * iso.neutron.abundance / 100.
        if complete and b_c != 0 and abs((b_c - el.neutron.b_c) / b_c) > 0.05:
            err = abs((b_c - el.neutron.b_c) / b_c)
            ## Printing suppressed for the release version
            #print "%2s %.3f % 7.3f % 7.3f"%(el.symbol,err,b_c,el.neutron.b_c)

    # Check neutron_sld and neutron_xs against NIST calculator
    # Note that we are using different tables, so a general comparison with
    # NIST numbers is not possible, but ^30Si and ^18O are the same in both.
    M = formula('Si[30]O[18]2', density=2.2)
    sld, xs, depth = neutron_scattering(M, wavelength=4.75)
    sld2 = neutron_sld(M, wavelength=4.75)
    assert all(abs(v - w) < 1e-10 for v, w in zip(sld, sld2))
    #_summarize(M)
    #_summarize(formula('O2',density=1.14))
    # Alan's numbers:
    assert abs(sld[0] - 3.27) < 0.01
    assert abs(sld[1] - 0) < 0.01
    assert abs(xs[2] - 0.00292) < 0.00001
    assert abs(xs[1] - 0.00569) < 0.00001
    assert abs(1 / sum(xs) - 4.329) < 0.001

    # Cu/Mo K-alpha = 1.89e-5 + 2.45e-7i / 1.87e-5 + 5.16e-8i

    Ni, Si = elements.Ni, elements.Si

    # Make sure molecular calculation corresponds to direct calculation
    sld = neutron_sld('Si', density=Si.density, wavelength=4.75)
    sld2 = Si.neutron.sld(wavelength=4.75)
    assert all(abs(v - w) < 1e-10 for v, w in zip(sld, sld2))

    sld, _, _ = Si.neutron.scattering(wavelength=4.75)
    sld2 = Si.neutron.sld(wavelength=4.75)
    assert all(abs(v - w) < 1e-10 for v, w in zip(sld, sld2))

    sld, xs, depth = neutron_scattering('Si',
                                        density=Si.density,
                                        wavelength=4.75)
    sld2, xs2, depth2 = Si.neutron.scattering(wavelength=4.75)
    assert all(abs(v - w) < 1e-10 for v, w in zip(sld, sld2))
    assert all(abs(v - w) < 1e-10 for v, w in zip(xs, xs2))
    assert abs(depth - depth2) < 1e-14

    # incoherent cross sections for Ni[62] used to be negative
    sld, xs, depth = neutron_scattering('Ni[62]',
                                        density=Ni[62].density,
                                        wavelength=4.75)
    assert sld[2] == 0 and xs[2] == 0
    sld, xs, depth = Ni[62].neutron.scattering(wavelength=4.75)
    assert sld[2] == 0 and xs[2] == 0
    assert Ni[62].neutron.sld()[2] == 0

    # Test call from periodictable
    sld, xs, depth = periodictable.neutron_scattering('H2O',
                                                      density=1,
                                                      wavelength=4.75)
    sld2, xs2, depth2 = neutron_scattering('H2O', density=1, wavelength=4.75)
    assert all(abs(v - w) < 1e-10 for v, w in zip(sld, sld2))
    assert all(abs(v - w) < 1e-10 for v, w in zip(xs, xs2))
    assert depth == depth2
    sld = periodictable.neutron_sld('H2O', density=1, wavelength=4.75)
    assert all(abs(v - w) < 1e-10 for v, w in zip(sld, sld2))

    # Check empty formula
    sld, xs, depth = neutron_scattering('', density=0, wavelength=4.75)
    assert all(v == 0 for v in sld)
    assert all(v == 0 for v in xs)
    assert numpy.isinf(depth)

    # Check density == 0 works
    sld, xs, depth = neutron_scattering('Si', density=0, wavelength=4.75)
    assert all(v == 0 for v in sld)
    assert all(v == 0 for v in xs)
    assert numpy.isinf(depth)

    # Test natural density
    D2O_density = (2 * D.mass + O.mass) / (2 * H.mass + O.mass)
    sld, xs, depth = neutron_scattering('D2O',
                                        natural_density=1,
                                        wavelength=4.75)
    sld2, xs2, depth2 = neutron_scattering('D2O',
                                           density=D2O_density,
                                           wavelength=4.75)
    assert all(abs(v - w) < 1e-14 for v, w in zip(sld, sld2))
    assert all(abs(v - w) < 1e-14 for v, w in zip(xs, xs2))
    assert abs(depth - depth2) < 1e-14

    # Test that sld depends on density not on the size of the unit cell
    D2O_density = (2 * D.mass + O.mass) / (2 * H.mass + O.mass)
    sld, xs, depth = neutron_scattering('D2O',
                                        natural_density=1,
                                        wavelength=4.75)
    sld2, xs2, depth2 = neutron_scattering('2D2O',
                                           natural_density=1,
                                           wavelength=4.75)
    assert all(abs(v - w) < 1e-14 for v, w in zip(sld, sld2))
    assert all(abs(v - w) < 1e-14 for v, w in zip(xs, xs2))
    assert abs(depth - depth2) < 1e-14

    # Test energy <=> velocity <=> wavelength
    assert abs(
        nsf.neutron_wavelength_from_velocity(2200) -
        1.7981972618436388) < 1e-14
    assert abs(nsf.neutron_wavelength(25) - 1.8) < 0.1
    assert abs(nsf.neutron_energy(nsf.neutron_wavelength(25)) - 25) < 1e-14

    # Confirm scattering functions accept energy and wavelength
    sld, xs, depth = neutron_scattering('H2O', density=1, wavelength=4.75)
    sld2, xs2, depth2 = neutron_scattering('H2O',
                                           density=1,
                                           energy=nsf.neutron_energy(4.75))
    assert all(abs(v - w) < 1e-14 for v, w in zip(sld, sld2))
    assert all(abs(v - w) < 1e-14 for v, w in zip(xs, xs2))
    assert abs(depth - depth2) < 1e-14
Пример #35
0
 def hf(self):
     return pt.formula(self.head_formula)
Пример #36
0
 def formula(self):
     return pt.formula(self.head_formula) + pt.formula(self.tail_formula)
Пример #37
0
    },
    "Fe-Hy": {"name": "ferrosilite", "formulae": "FeO SiO2", "SINCLAS_abbrv": "HYF"},
    "Mg-Hy": {"name": "enstatite", "formulae": "MgO SiO2", "SINCLAS_abbrv": "HYM"},
    # additions
    "Tn": {"name": "titanite", "formulae": "CaO TiO2 SiO2", "SINCLAS_abbrv": "SPH"},
    "Wo": {"name": "wollastonite", "formulae": "CaO SiO2"},
    "Di": {"name": "diopside", "formulae": "CaO MgO 2SiO2"},
    "Hy": {"name": "hypersthene", "formulae": "MgO SiO2"},
    "Ol": {"name": "olivine", "formulae": "2MgO SiO2"},
    "Hl": {"name": "halite", "formulae": "NaCl", "SINCLAS_abbrv": "HL"},
    "Nc": {"name": "cancrinite", "formulae": "Na2O CO2", "SINCLAS_abbrv": "CAN"},
}

# Add standard masses to minerals
for mineral in NORM_MINERALS.keys():
    NORM_MINERALS[mineral]["mass"] = pt.formula(NORM_MINERALS[mineral]["formulae"])


def unmix(comp, parts, ord=1, det_lim=0.0001):
    """
    From a composition and endmember components, find a set of weights which best
    approximate the composition as a weighted sum of components.

    Parameters
    --------------
    comp : :class:`numpy.ndarray`
        Array of compositions (shape :math:`n_S, n_C`).
    parts : :class:`numpy.ndarray`
        Array of endmembers (shape :math:`n_E, n_C`).
    ord : :class:`int`
        Order of regularization, defaults to L1 for sparsity.
Пример #38
0
def SCSS(df, T, P, kelvin=False, grid=None, outunit="wt%"):
    r"""
    Obtain the sulfur content at sulfate and sulfide saturation [#ref_1]_ [#ref_2]_.

    Parameters
    -------------
    df : :class:`pandas.DataFrame`
        Dataframe of compositions.
    T : :class:`float` | :class:`numpy.ndarray`
        Temperature
    P : :class:`float` | :class:`numpy.ndarray`
        Pressure (kbar)
    kelvin : :class:`bool`
        Whether temperature values are in kelvin (:code:`True`) or celsuis (:code:`False`)
    grid : :code:`None`, :code:`'geotherm'`, :code:`'grid'`
        Whether to consider temperature and pressure as a geotherm (:code:`geotherm`),
        or independently (as a grid, :code:`grid`).

    Returns
    -------
    sulfate, sulfide : :class:`numpy.ndarray`, :class:`numpy.ndarray`
        Arrays of mass fraction sulfate and sulfide abundances at saturation.

    Notes
    ------

    For anhydrite-saturated systems, the sulfur content at sulfate saturation is given
    by the following:

    .. math::

        \begin{align}
        ln(X_S) = &10.07
        - 1.151 \cdot (10^4 / T_K)
        + 0.104 \cdot P_{kbar}\\
        &- 7.1 \cdot X_{SiO_2}
        - 14.02 \cdot X_{MgO}
        - 14.164 \cdot X_{Al_2O_3}\\
        \end{align}

    For sulfide-liquid saturated systems, the sulfur content at sulfide saturation is
    given by the following:

    .. math::

        \begin{align}
        ln(X_S) = &{-1.76}
        - 0.474 \cdot (10^4 / T_K)
        + 0.021 \cdot P_{kbar}\\
        &+ 5.559 \cdot X_{FeO}
        + 2.565 \cdot X_{TiO_2}
        + 2.709 \cdot X_{CaO}\\
        &- 3.192 \cdot X_{SiO_2}
        - 3.049 \cdot X_{H_2O}\\
        \end{align}

    References
    -----------
    .. [#ref_1] Li, C., and Ripley, E.M. (2009).
        Sulfur Contents at Sulfide-Liquid or Anhydrite Saturation in Silicate Melts:
        Empirical Equations and Example Applications. Economic Geology 104, 405–412.
        doi: `gsecongeo.104.3.405 <https://doi.org/10.2113/gsecongeo.104.3.405>`__

    .. [#ref_2] Smythe, D.J., Wood, B.J., and Kiseeva, E.S. (2017).
        The S content of silicate melts at sulfide saturation:
        New experiments and a model incorporating the effects of sulfide composition.
        American Mineralogist 102, 795–803.
        doi: `10.2138/am-2017-5800CCBY <https://doi.org/10.2138/am-2017-5800CCBY>`__

    Todo
    -----
    * Produce an updated version based on log-regressions?
    * Add updates from Smythe et al. (2017)?
    """
    T, P = np.array(T), np.array(P)
    if not kelvin:
        T = T + 273.15

    C = np.ones(df.index.size)
    assert grid in [None, "geotherm", "grid"]
    if grid == "grid":
        cc, tt, pp = np.meshgrid(C, T, P, indexing="ij")
    elif grid == "geotherm":
        assert T.shape == P.shape
        cc = C[:, np.newaxis]
        tt = T[np.newaxis, :]
        pp = P[np.newaxis, :]
    elif grid is None:
        _dims = C.size, T.size, P.size
        maxdim = max(_dims)
        assert all([x == maxdim or x == 1 for x in _dims])
        cc, tt, pp = C, T, P

    comp = set(df.columns) & (__common_elements__ | __common_oxides__)
    moldf = to_molecular(df.loc[:, comp], renorm=True) / 100  # mole-fraction
    molsum = to_molecular(df.loc[:, comp], renorm=False).sum(axis=1)

    def gridify(ser):
        arr = ser.replace(np.nan, 0).values
        if grid == "grid":
            return arr[:, np.newaxis, np.newaxis]
        elif grid == "geotherm":
            return arr[:, np.newaxis]
        elif grid is None:
            return arr

    ln_sulfate = 10.07 * cc - 1.151 * 10**4 / tt + 0.104 * pp
    for x, D in [("SiO2", -7.1), ("MgO", -14.02), ("Al2O3", -14.164)]:
        if x in moldf:
            ln_sulfate += gridify(moldf[x]) * D * cc

    ln_sulfide = -1.76 * cc - 0.474 * 10**4 / tt + 0.021 * pp

    for x, D in [
        ("FeO", 5.559),
        ("TiO2", 2.565),
        ("CaO", 2.709),
        ("SiO2", -3.192),
        ("H2O", -3.049),
    ]:
        if x in moldf:
            ln_sulfide += gridify(moldf[x]) * D * cc

    sulfate, sulfide = np.exp(ln_sulfate), np.exp(ln_sulfide)

    _s = gridify(molsum * pt.S.mass) * scale("wt%", outunit)
    _so4 = gridify(molsum * pt.formula("SO4").mass) * scale("wt%", outunit)
    sulfide *= _s
    sulfate *= _so4

    if sulfate.size == 1:  # 0D
        return sulfate.flatten()[0], sulfide.flatten()[0]
    else:  # 2D
        return sulfate, sulfide
Пример #39
0
def test_xsf():

    # Check some K_alpha and K_beta1 values
    assert Cu.K_alpha == 1.5418
    assert Cu.K_beta1 == 1.3922

    # Check scalar scattering factor lookup
    f1, f2 = Ni.xray.scattering_factors(energy=xray_energy(Cu.K_alpha))
    assert abs(f1 - 25.0229) < 0.0001
    assert abs(f2 - 0.5249) < 0.0001

    # Check array scattering factor lookup
    f1, f2 = Ni.xray.scattering_factors(wavelength=Cu.K_alpha)
    m1, m2 = Ni.xray.scattering_factors(wavelength=Mo.K_alpha)
    B1, B2 = Ni.xray.scattering_factors(wavelength=[Cu.K_alpha, Mo.K_alpha])
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()

    # Check that we can lookup sld by wavelength and energy
    Fe_rho, Fe_mu = Fe.xray.sld(wavelength=Cu.K_alpha)
    assert abs(Fe_rho - 59.45) < 0.01
    Si_rho, Si_mu = Si.xray.sld(energy=8.050)
    assert abs(Si_rho - 20.0701) < 0.0001
    assert abs(Si_mu - 0.4572) < 0.0001

    # Check that wavelength is the default
    Fe_rho_default, Fe_mu_default = Fe.xray.sld(wavelength=Cu.K_alpha)
    assert Fe_rho == Fe_rho_default and Fe_mu == Fe_mu_default

    # Check array form of sld lookup
    f1, f2 = Si.xray.sld(wavelength=Cu.K_alpha)
    m1, m2 = Si.xray.sld(wavelength=Mo.K_alpha)
    B1, B2 = Si.xray.sld(wavelength=[Cu.K_alpha, Mo.K_alpha])
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()

    # Check energy conversion is consistent
    f1, f2 = Si.xray.sld(energy=xray_energy(Cu.K_alpha))
    m1, m2 = Si.xray.sld(energy=xray_energy(Mo.K_alpha))
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()
    B1, B2 = Si.xray.sld(energy=xray_energy([Cu.K_alpha, Mo.K_alpha]))
    assert (B1 == [f1, m1]).all() and (B2 == [f2, m2]).all()

    #print Cu.xray.sftable
    #plot_xsf(Cu)
    #emission_table()
    #sld_table(table,Cu.K_alpha)
    """
    # Table of scattering length densities for various molecules
    for molecule,density in [('SiO2',2.2),('B4C',2.52)]:
        atoms = formula(molecule).atoms
        rho,mu = xray_sld(atoms,density,wavelength=Cu.K_alpha)
        print "sld for %s(%g g/cm**3)  rho=%.4g mu=%.4g"\
            %(molecule,density,rho,mu)
    """

    # Cross check against mo
    rho, mu = xray_sld({Si: 1}, density=Si.density, wavelength=1.54)
    rhoSi, muSi = Si.xray.sld(wavelength=1.54)
    assert abs(rho - rhoSi) < 1e-14
    assert abs(mu - muSi) < 1e-14

    # Check that xray_sld works as expected
    atoms = formula('SiO2').atoms
    rho, mu = xray_sld(atoms, density=2.2, energy=xray_energy(Cu.K_alpha))
    assert abs(rho - 18.87) < 0.1
    atoms = formula('B4C').atoms
    rho, mu = xray_sld(atoms, density=2.52, energy=xray_energy(Cu.K_alpha))
    assert abs(rho - 20.17) < 0.1

    F = formula('', density=0)
    rho, mu = xray_sld('', density=0, wavelength=Cu.K_alpha)
    assert rho == mu == 0

    # Check natural density calculations
    D2O_density = (2 * D.mass + O.mass) / (2 * H.mass + O.mass)
    rho, mu = xray_sld('D2O', natural_density=1, wavelength=1.54)
    rho2, mu2 = xray_sld('D2O', density=D2O_density, wavelength=1.54)
    assert abs(rho - rho2) < 1e-14 and abs(mu - mu2) < 1e-14

    # Check f0 calculation for scalar, vector, array and empty
    Q1, Q2 = 4 * pi / Cu.K_alpha, 4 * pi / Mo.K_alpha
    f0 = Ni.xray.f0(Q=Q1)
    assert abs(f0 - 10.11303) < 0.00001
    assert isnan(Ni.xray.f0(Q=7 * 4 * pi))

    f0 = Ni.xray.f0(Q=Q1)
    m0 = Ni.xray.f0(Q=Q2)
    B0 = Ni.xray.f0(Q=[Q1, Q2])
    assert (B0 == [f0, m0]).all()

    f0 = Ni.xray.f0(Q=[])
    assert len(f0) == 0

    f0 = Ni.xray.f0(Q=[[1, 2], [3, 4]])
    assert f0[0, 0] == Ni.xray.f0(1)
    assert f0[0, 1] == Ni.xray.f0(2)
    assert f0[1, 0] == Ni.xray.f0(3)
    assert f0[1, 1] == Ni.xray.f0(4)

    # Check f0 calculation for ion
    Ni_2p_f0 = Ni.ion[2].xray.f0(Q=Q1)
    assert abs(Ni_2p_f0 - 10.09535) < 0.00001
    Ni58_2p_f0 = Ni[58].ion[2].xray.f0(Q=Q1)
    assert Ni_2p_f0 == Ni58_2p_f0

    # The following test is implementation specific, and is not guaranteed
    # to succeed if the extension interface changes.
    assert '_xray' not in Ni[58].__dict__
Пример #40
0
 def eval_formula(self):
     current_formula = "".join(
         [calc.formula for index, calc in self.calculations.items()])
     current_formula = periodictable.formula(current_formula).atoms
     return current_formula
Пример #41
0
from collections import OrderedDict
import uncertainties as uct
from scipy import constants
import periodictable as ptable
from ..conversion import vol_uc2mol
from .objs import MGEOS, JHEOS
from ..conversion import vol_mol2uc

v_ref = 3.9231**3  # default v0
n = 1.
z = 4.
ef_v = 0.001
ef_temp = 0.05
mass = ptable.formula("Pt").mass * 1.e-3
v0_mol = vol_uc2mol(v_ref, z)
rho0 = mass / v0_mol  # kg/m^3


class Fei2004(MGEOS):
    """
    Fei et al. 2004 PEPI 143-144, 515+
    """
    def __init__(self, v0=v_ref):
        params_st = OrderedDict([('v0', uct.ufloat(v0, ef_v)),
                                 ('k0', uct.ufloat(273., 3.0)),
                                 ('k0p', uct.ufloat(4.8, 0.03))])
        params_th = OrderedDict([('v0', uct.ufloat(v0, ef_v)),
                                 ('gamma0', uct.ufloat(2.69, 0.03)),
                                 ('q', uct.ufloat(0.5, 0.5)),
                                 ('theta0', uct.ufloat(230., 0.0))])
        reference = 'Fei et al. 2004 PEPI 143-144, 515+'
import numpy as np
import periodictable as ptable

# Possible additions include a better input system

initial_amount = float(input('Input the initial amount '))
initial_units = str(input('Input the initial units '))
initial_formula = str(input('Input the initial compound '))

mole_ratio = float(input('Input the mole ratio '))

final_units = str(input('Input the final units '))
final_formula = str(input('Input the final compound '))

if initial_units == 'g':
    final_amount = initial_amount / ptable.formula(initial_formula).mass
else:
    final_amount = initial_amount

final_amount *= mole_ratio

if final_units == 'g':
    final_amount *= ptable.formula(final_formula).mass

print('{} {} {}'.format(final_amount, final_units, final_formula))
Пример #43
0
    def read(self, path):
        """
        Load data file

        :param path: file path
        :return: MagSLD
        :raise RuntimeError: when the file can't be opened
        """
        pos_x = np.zeros(0)
        pos_y = np.zeros(0)
        pos_z = np.zeros(0)
        sld_n = np.zeros(0)
        sld_mx = np.zeros(0)
        sld_my = np.zeros(0)
        sld_mz = np.zeros(0)
        vol_pix = np.zeros(0)
        pix_symbol = np.zeros(0)
        x_line = []
        y_line = []
        z_line = []
        x_lines = []
        y_lines = []
        z_lines = []
        try:
            input_f = open(path, 'rb')
            buff = decode(input_f.read())
            lines = buff.split('\n')
            input_f.close()
            num = 0
            for line in lines:
                try:
                    # check if line starts with "ATOM"
                    if line[0:6].strip().count('ATM') > 0 or \
                                line[0:6].strip() == 'ATOM':
                        # define fields of interest
                        atom_name = line[12:16].strip()
                        try:
                            float(line[12])
                            atom_name = atom_name[1].upper()
                        except Exception:
                            if len(atom_name) == 4:
                                atom_name = atom_name[0].upper()
                            elif line[12] != ' ':
                                atom_name = atom_name[0].upper() + \
                                        atom_name[1].lower()
                            else:
                                atom_name = atom_name[0].upper()
                        _pos_x = float(line[30:38].strip())
                        _pos_y = float(line[38:46].strip())
                        _pos_z = float(line[46:54].strip())
                        pos_x = np.append(pos_x, _pos_x)
                        pos_y = np.append(pos_y, _pos_y)
                        pos_z = np.append(pos_z, _pos_z)
                        try:
                            val = nsf.neutron_sld(atom_name)[0]
                            # sld in Ang^-2 unit
                            val *= 1.0e-6
                            sld_n = np.append(sld_n, val)
                            atom = formula(atom_name)
                            # cm to A units
                            vol = 1.0e+24 * atom.mass / atom.density / NA
                            vol_pix = np.append(vol_pix, vol)
                        except Exception:
                            logger.error("Error: set the sld of %s to zero" %
                                         atom_name)
                            sld_n = np.append(sld_n, 0.0)
                        sld_mx = np.append(sld_mx, 0)
                        sld_my = np.append(sld_my, 0)
                        sld_mz = np.append(sld_mz, 0)
                        pix_symbol = np.append(pix_symbol, atom_name)
                    elif line[0:6].strip().count('CONECT') > 0:
                        toks = line.split()
                        num = int(toks[1]) - 1
                        val_list = []
                        for val in toks[2:]:
                            try:
                                int_val = int(val)
                            except Exception:
                                break
                            if int_val == 0:
                                break
                            val_list.append(int_val)
                        #need val_list ordered
                        for val in val_list:
                            index = val - 1
                            if (pos_x[index], pos_x[num]) in x_line and \
                               (pos_y[index], pos_y[num]) in y_line and \
                               (pos_z[index], pos_z[num]) in z_line:
                                continue
                            x_line.append((pos_x[num], pos_x[index]))
                            y_line.append((pos_y[num], pos_y[index]))
                            z_line.append((pos_z[num], pos_z[index]))
                    if len(x_line) > 0:
                        x_lines.append(x_line)
                        y_lines.append(y_line)
                        z_lines.append(z_line)
                except Exception as exc:
                    logger.error(exc)

            output = MagSLD(pos_x, pos_y, pos_z, sld_n, sld_mx, sld_my, sld_mz)
            output.set_conect_lines(x_line, y_line, z_line)
            output.filename = os.path.basename(path)
            output.set_pix_type('atom')
            output.set_pixel_symbols(pix_symbol)
            output.set_nodes()
            output.set_pixel_volumes(vol_pix)
            output.sld_unit = '1/A^(2)'
            return output
        except Exception:
            raise RuntimeError("%s is not a sld file" % path)
# This code does combustion analysis for MOST CH and CHO fuels provided the fuel mass, CO2 mass, and H2O mass

# Import numpy and periodictable to do the chemistry
import numpy as np
import periodictable as ptable

# User input for necessary masses (initial fuel, CO2, and H2O)
fuel_mass = float(input('Input the mass of compound combusted '))
CO2_mass = float(input('Input the mass of CO2 produced '))
H2O_mass = float(input('Input the mass of H2O produced '))

# Calling ptable to convert CO2 mass to C mass to C mol
C_mass = CO2_mass * ptable.C.mass / ptable.formula('CO2').mass
C_mol = C_mass / ptable.C.mass

# Same for H2O to H mass to H mol
H_mass = H2O_mass * 2 * ptable.H.mass / ptable.formula('H2O').mass
H_mol = H_mass / ptable.H.mass

# O mass is the remaining mass in the fuel, convert to moles
O_mass = fuel_mass - H_mass - C_mass
O_mol = O_mass / ptable.O.mass

# A list of valid mole values
mol_values = [C_mol, H_mol]

# If the O_mass is valid, then O_mol is added to the moles list. If not, ignore it
if O_mass < 0.01:
    O_mol = 0
else:
    mol_values = mol_values + [O_mol]
Пример #45
0
    def check_inputs(self):
        """Check validity user inputs"""
        flag = True
        msg = ""
        if check_float(self.density_ctl):
            self.density = float(self.density_ctl.GetValue())
        else:
            flag = False
            msg += "Error for Density value :expect float"

        self.neutron_wavelength = self.neutron_wavelength_ctl.GetValue()
        self.xray_source_input = self.xray_source_input_ctl.GetValue()

        if str(self.neutron_wavelength).lstrip().rstrip() == "":
            self.neutron_wavelength = WAVELENGTH
            self.neutron_wavelength_ctl.SetValue(str(WAVELENGTH))
            self.neutron_wavelength_ctl.SetBackgroundColour(wx.WHITE)
            self.neutron_wavelength_ctl.Refresh()
            msg += "Default value for wavelength is 6.0"
        else:
            if check_float(self.neutron_wavelength_ctl):
                self.neutron_wavelength = float(self.neutron_wavelength)
            else:
                flag = False
                msg += "Error for wavelength value :expect float"

        if str(self.xray_source_input).lstrip().rstrip() == "":
            self.xray_source_input = WAVELENGTH
            self.xray_source_input_ctl.SetValue(str(WAVELENGTH))
            self.xray_source_input_ctl.SetBackgroundColour(wx.WHITE)
            self.xray_source_input_ctl.Refresh()
            msg += "Default value for wavelength is 6.0"
        else:
            if (self.xray_source == '[A]') or (self.xray_source == '[keV]'):
                if check_float(self.xray_source_input_ctl):
                    self.xray_source_input = float(self.xray_source_input)
                else:
                    flag = False
                    msg += "Error for wavelength value :expect float"
            elif (self.xray_source == 'Element'):
                try:
                    import periodictable
                    exec("periodictable." + self.xray_source_input)
                except AttributeError:
                    flag = False
                    msg += "X-ray element supplied isn't in the database"

        self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
        if self.compound != "":
            try:
                formula(self.compound)
                self.compound_ctl.SetBackgroundColour(wx.WHITE)
                self.compound_ctl.Refresh()
            except:
                self.compound_ctl.SetBackgroundColour("pink")
                self.compound_ctl.Refresh()
                flag = False
                msg += "Enter correct formula"
        else:
            self.compound_ctl.SetBackgroundColour("pink")
            self.compound_ctl.Refresh()
            flag = False
            msg += "Enter a formula"
        return flag, msg
Пример #46
0
def recalc_cations(
    df,
    ideal_cations=4,
    ideal_oxygens=6,
    Fe_species=["FeO", "Fe", "Fe2O3"],
    oxygen_constrained=False,
):
    """
    Recalculate a composition to a.p.f.u.
    """
    assert ideal_cations is not None or ideal_oxygens is not None
    # if Fe2O3 and FeO are specified, calculate based on oxygen
    moles = to_frame(df)
    moles = moles.div([pt.formula(c).mass for c in moles.columns])
    moles = moles.where(~np.isclose(moles, 0.0), np.nan)

    # determine whether oxygen is an open or closed system
    Fe_species = [i for i in moles
                  if i in Fe_species]  # keep dataframe ordering
    count_iron_species = len(Fe_species)
    oxygen_constrained = oxygen_constrained
    if not oxygen_constrained:
        if count_iron_species > 1:  # check that only one is defined
            oxygen_constrained = (count_iron_species - pd.isnull(
                moles.loc[:, Fe_species]).all(axis=1).sum()) > 1

            if oxygen_constrained:
                logger.info(
                    "Multiple iron species defined. Calculating using oxygen.")
            else:
                logger.info(
                    "Single iron species defined. Calculating using cations.")

    components = moles.columns
    as_oxides = len(list(pt.formula(components[0]).atoms)) > 1
    schema = []
    # if oxygen_constrained:  # need to specifically separate Fe2 and Fe3
    if as_oxides:
        parts = [pt.formula(c).atoms for c in components]
        for p in parts:
            oxygens = p[pt.O]
            other_components = [i for i in list(p) if not i == pt.O]
            assert len(other_components) == 1  # need to be simple oxides
            other = other_components[0]
            charge = oxygens * 2 / p[other]
            ion = other.ion[charge]
            schema.append({str(ion): p[other], "O": oxygens})
    else:
        # elemental composition
        parts = components
        for part in parts:
            p = list(pt.formula(part).atoms)[0]
            if p.charge != 0:
                charge = p.charge
            else:
                charge = p.default_charge
            schema.append({p.ion[charge]: 1})

    ref = pd.DataFrame(data=schema)
    ref.columns = ref.columns.map(str)
    ref.index = components

    cation_masses = {c: pt.formula(c).mass for c in ref.columns}
    oxygen_index = [i for i in ref.columns if "O" in i][0]
    ref = ref.loc[:, [i for i in ref.columns if not i == oxygen_index] +
                  [oxygen_index]]
    moles_ref = ref.copy(deep=True)
    moles_ref.loc[:, :] = (ref.values * moles.T.values
                           )  # this works for series, not for frame

    moles_O = moles_ref[oxygen_index].sum()
    moles_cations = (
        moles_ref.loc[:,
                      [i for i in moles_ref.columns
                       if not i == oxygen_index]].sum().sum())
    if not oxygen_constrained:  # oxygen unquantified, try to calculate using cations
        scale = ideal_cations / moles_cations
    else:  # oxygen quantified, try to calculate using oxygen
        scale = ideal_oxygens / moles_O

    moles_ref *= scale
    return moles_ref.sum(axis=0)
Пример #47
0
 def tf(self):
     return pt.formula(self.tail_formula)
Пример #48
0
import numpy as np

from periodictable import formula

# Set Plot Stlye
plt.style.use('ggplot')

# Load Data and Create pypie.Pie object
data = 'sample_data' 
pie = pypie.Pie(data)

energy = 13.1

# Calibrate Mass Spectra
pie.ms_cursor()
m1, m2 = formula('He').mass, formula('O2').mass
t1, t2 =  825, 3201 
pie.ms_calibrate( m1, m2, t1, t2)  # terms[file_key] format is ((m1, m2), (t1, t2))

# Plot and save mass spectra
pie.ms_plot() 
save_path = 'sample_mass_spectrum.txt'
pie.ms_save(path=save_path)


# Slice multiple PIEs with given formulae
formulae = [ 'CH4','C2H2','C2H4','C3H6','C4H6','C5H10','C6H6','C7H8','C7H8','C8H10']
masses = [ formula(form).mass for form in formulae ]
for f, m in zip(formulae, masses):
        pie.pie_slice(m, 0.5, label=f)
Пример #49
0
def convert_atoms_to_formula(atoms):
    s = []
    for k, v in atoms.items():
        s.append([v, k])
    return pt.formula(s)
Пример #50
0
from collections import OrderedDict
import uncertainties as uct
from scipy import constants
import periodictable as ptable
from ..conversion import vol_uc2mol, vol_mol2uc
from .objs import MGEOS, JHEOS

v_ref = 4.07860**3  # default v0
n = 1.
z = 4.
ef_v = 0.001
ef_temp = 0.05
mass = ptable.formula("Au").mass * 1.e-3
v0_mol = vol_uc2mol(v_ref, z)
rho0 = mass / v0_mol  # kg/m^3


class Jamieson1982L(JHEOS):
    """
    Jamieson et al. 1982. High pressure research in geophysics.
    Fit C in table 2.
    """
    def __init__(self, v0=v_ref):
        mass_shock = mass * 1.e3  # to mass in g
        three_r = 0.12500 / (3. * n * constants.R / mass_shock) *\
            3. * constants.R
        rho0 = 19.2827
        params_hugoniot = OrderedDict([('rho0', uct.ufloat(rho0, 0.0)),
                                       ('a', uct.ufloat(2.975, 0.0)),
                                       ('b', uct.ufloat(1.896, 0.0)),
                                       ('c', uct.ufloat(-0.309, 0.0))])
Пример #51
0
 def get_mass(self, elements):
     mass = []
     for atom in elements:
         mass.append(periodictable.formula(atom).mass)
     mass = np.array(mass, dtype=float)
     return mass
Пример #52
0
def CIPW_norm(df, Fe_correction=None, Fe_correction_mode=None, adjust_all_Fe=False):
    """
    Standardised calcuation of estimated mineralogy from bulk rock chemistry.
    Takes a dataframe of chemistry & creates a dataframe of estimated mineralogy.

    This is the CIPW norm of Verma et al. (2003).  This version only uses major
    elements.

    Parameters
    -----------
    df : :class:`pandas.DataFrame`
        Dataframe containing compositions to transform.
    Fe_correction : :class:`str`
        Iron correction to apply, if any. Will default to 'LeMaitre'.
    Fe_correction_mode : :class:`str`
        Mode for the iron correction, where applicable.
    adjust_all_Fe : :class:`bool`
        Where correcting iron compositions, whether to adjust all iron
        compositions, or only those where singular components are specified.

    Returns
    --------
    :class:`pandas.DataFrame`

    References
    ----------

    Verma, Surendra P., Ignacio S. Torres-Alvarado, and Fernando Velasco-Tapia (2003).
    A Revised CIPW Norm. Swiss Bulletin of Mineralogy and Petrology 83, 2: 197–216.

    Verma, S. P., & Rivera-Gomez, M. A. (2013). Computer Programs for the
    Classification and Nomenclature of Igneous Rocks. Episodes, 36(2), 115–124.

    Todo
    ----
    * Note whether data needs to be normalised to 1 or 100?

    Notes
    -----
    The function expect oxide components to be in wt% and elemental data to be
    in ppm.
    """
    warnings.warn(
        "The current CIPW Norm implmentation is under continuting development, "
        "and does not yet return expected results."
    )

    noncrit = [
        "CO2",
        "SO3",
        "F",
        "Cl",
        "S",
        "Ni",
        "Co",
        "Sr",
        "Ba",
        "Rb",
        "Cs",
        "Li",
        "Zr",
        "Cr",
        "V",
    ]
    columns = (
        ["SiO2", "TiO2", "Al2O3", "Fe2O3", "FeO", "MnO", "MgO", "CaO"]
        + ["Na2O", "K2O", "P2O5"]
        + noncrit
    )

    # Check that all of the columns we'd like are present
    to_impute = []
    if not set(columns).issubset(set(df.columns.values)):
        to_impute += [c for c in columns if c not in df.columns]
        # raise warning for missing critical columns
        crit_miss = [c for c in to_impute if (c not in noncrit)]
        if crit_miss:
            logger.warning("Required columns missing: {}".format(", ".join(crit_miss)))

    # Reindex columns to be expected and fill missing ones with zeros
    if to_impute:  # Note that we're adding the columns with default values.
        logger.debug("Adding empty (0) columns: {}".format(", ".join(to_impute)))

    ############################################################################
    if Fe_correction is None:  # default to LeMaitre_Fe_correction
        Fe_correction = "LeMaitre"

    if adjust_all_Fe:
        logger.debug("Adjusting all Fe values.")
        fltr = np.ones(df.index.size, dtype="bool")  # use all samples
    else:
        # check where the iron speciation is already specified or there is no iron
        logger.debug("Adjusting Fe values where FeO-Fe2O3 speciation isn't given.")
        iron_specified = (
            (df.reindex(columns=["FeO", "Fe2O3"]) > 0).sum(axis=1) == 2
        ) | (
            np.isclose(
                df.reindex(columns=["FeO", "Fe2O3", "FeOT", "Fe2O3T"]).sum(axis=1), 0
            )
        )
        fltr = ~iron_specified  # Use samples where iron is not specified

    if Fe_correction.lower().startswith("lemait"):
        df.loc[fltr, ["FeO", "Fe2O3"]] = LeMaitre_Fe_correction(
            df.loc[fltr, :], mode=Fe_correction_mode
        )
    else:
        raise NotImplementedError(
            "Iron correction {} not recognised.".format(Fe_correction)
        )

    # select just the columns we'll use; remove e.g. FeOT, Fe2O3T which have been recalcuated
    df = df.reindex(columns=columns).fillna(0)

    majors = [
        "SiO2",
        "TiO2",
        "Al2O3",
        "Fe2O3",
        "FeO",
        "MnO",
        "MgO",
        "CaO",
        "Na2O",
        "K2O",
        "P2O5",
    ]

    trace = ["F", "Cl", "S", "Ni", "Co", "Sr", "Ba", "Rb", "Cs", "Li", "Zr", "Cr", "V"]

    # convert ppm traces to wt%
    df.loc[:, trace] *= scale("ppm", "wt%")

    # define the form which we want our minor and trace components to be in
    minors_trace = [
        "F",
        "Cl",
        "S",
        "CO2",
        "NiO",
        "CoO",
        "SrO",
        "BaO",
        "Rb2O",
        "Cs2O",
        "Li2O",
        "ZrO2",
        "Cr2O3",
        "V2O3",
    ]

    SO3 = df["SO3"]

    # convert to a single set of oxides and gas traces
    df = df.pyrochem.convert_chemistry(to=majors + minors_trace, renorm=False).fillna(0)

    df["SO3"] = SO3

    ############################################################################
    # Normalization
    # Adjust majors wt% to 100% then adjust again to account for trace components
    ############################################################################
    # Rounding to 3 dp
    df.loc[:, majors] = df.loc[:, majors].round(3)

    # First adjustment
    df["initial_sum"] = df.loc[:, majors].sum(axis=1)
    adjustment_factor = 100.0 / df["initial_sum"].values
    df.loc[:, majors] = df.loc[:, majors].mul(adjustment_factor, axis=0)

    # Second adjustment
    df["major_minor_sum"] = df.loc[:, majors].sum(axis=1) + df.loc[:, minors_trace].sum(
        axis=1
    )
    adjustment_factor = 100.0 / df["major_minor_sum"]

    df.loc[:, majors + minors_trace] = df.loc[:, majors + minors_trace].mul(
        adjustment_factor, axis=0
    )

    ############################################################################
    # Mole Calculations
    # TODO: update to use df.pyrochem.to_molecular()
    ############################################################################
    for component in majors + minors_trace:
        df.loc[:, component] /= pt.formula(component).mass

    ############################################################################
    # Combine minor components, compute minor component fractions and correct masses
    ############################################################################
    corrected_mass = pd.DataFrame()

    for major, minors in [
        ("FeO", ["MnO", "NiO", "CoO"]),
        ("CaO", ["SrO", "BaO"]),
        ("K2O", ["Rb2O", "Cs2O"]),
        ("Na2O", ["Li2O"]),
        ("Cr2O3", ["V2O3"]),
    ]:
        _aggregate_components(df, major, minors, corrected_mass)

    # Corrected molecular weight of Ca, Na and Fe
    corrected_mass["Ca"] = corrected_mass["CaO"] - pt.O.mass
    corrected_mass["Na"] = (corrected_mass["Na2O"] - pt.O.mass) / 2
    corrected_mass["Fe"] = corrected_mass["FeO"] - pt.O.mass

    # Get mineral data, update with corrected masses

    minerals = {
        k: {**v} for k, v in NORM_MINERALS.items()
    }  # copy the dictionary rather than edit it

    _update_molecular_masses(minerals, corrected_mass)

    df["Y"] = 0

    ############################################################################
    # Calculate normative components
    ############################################################################

    # Normative Zircon
    df["Z"] = df["ZrO2"]
    df["Y"] = df["Z"]

    # Normative apatite

    df["Ap"] = np.where(
        df["CaO"] >= (3 + 1 / 3) * df["P2O5"], df["P2O5"], df["CaO"] / (3 + 1 / 3)
    ).T

    df["CaO_"] = np.where(
        df["CaO"] >= (3 + 1 / 3) * df["P2O5"], df["CaO"] - (3 + 1 / 3) * df["Ap"], 0
    ).T

    df["P2O5_"] = np.where(
        df["CaO"] < (3 + 1 / 3) * df["P2O5"], df["P2O5"] - df["Ap"], 0
    ).T

    df["CaO"] = df["CaO_"]
    df["P2O5"] = df["P2O5_"]

    df["FREE_P2O5"] = df["P2O5"]

    # apatite options where F in present

    df["ap_option"] = np.where(df["F"] >= (2 / 3) * df["Ap"], 2, 3).T

    df["F"] = np.where(
        (df["ap_option"]) == 2 & (df["F"] > 0), df["F"] - (2 / 3 * df["Ap"]), df["F"]
    ).T

    df["CaF2-Ap"] = np.where((df["ap_option"]) == 3 & (df["F"] > 0), df["F"] * 1.5, 0).T

    df["CaO-Ap"] = np.where(
        (df["ap_option"]) == 3 & (df["F"] > 0), df["P2O5"] - (1.5 * df["F"]), 0
    ).T

    df["Ap"] = np.where(
        (df["ap_option"]) == 3 & (df["F"] > 0), df["CaF2-Ap"] + df["CaO-Ap"], df["Ap"]
    ).T

    df["FREEO_12b"] = np.where(df["ap_option"] == 2, 1 / 3 * df["Ap"], 0).T
    df["FREEO_12c"] = np.where(df["ap_option"] == 3, df["F"] / 2, 0).T

    # Normative Fluorite
    df["Fr"] = np.where(df["CaO"] >= df["F"] / 2, df["F"] / 2, df["CaO"]).T

    df["CaO"] = np.where(df["CaO"] >= df["F"] / 2, df["CaO"] - df["Fr"], 0).T

    df["F"] = np.where(df["CaO"] >= df["F"] / 2, df["F"], df["F"] - (2 * df["Fr"])).T

    df["FREEO_13"] = df["Fr"]
    df["FREE_F"] = df["F"]

    # Normative halite
    df["Hl"] = np.where(df["Na2O"] >= 2 * df["Cl"], df["Cl"], df["Na2O"] / 2).T

    df["Na2O"] = np.where(df["Na2O"] >= 2 * df["Cl"], df["Na2O"] - df["Hl"] / 2, 0).T

    df["Cl"] = np.where(df["Na2O"] >= 2 * df["Cl"], df["Cl"], df["Cl"] - df["Hl"]).T

    df["FREE_Cl"] = df["Cl"]
    df["FREEO_14"] = df["Hl"] / 2

    # Normative thenardite
    df["Th"] = np.where(df["Na2O"] >= df["SO3"], df["SO3"], df["Na2O"]).T

    df["Na2O"] = np.where(df["Na2O"] >= df["SO3"], df["Na2O"] - df["Th"], 0).T

    df["SO3"] = np.where(df["Na2O"] >= df["SO3"], df["SO3"], df["SO3"] - df["Th"]).T

    df["FREE_SO3"] = df["SO3"]

    # Normative Pyrite
    df["Pr"] = np.where(df["FeO"] >= 2 * df["S"], df["S"] / 2, df["FeO"]).T

    df["FeO"] = np.where(df["FeO"] >= 2 * df["S"], df["FeO"] - df["Pr"], 0).T

    df["FREE_S"] = np.where(df["FeO"] >= 2 * df["S"], 0, df["FeO"]).T

    df["FeO"] = df["FeO"] - df["FREE_S"]

    df["FREEO_16"] = df["Pr"]

    # Normative sodium carbonate (cancrinite) or calcite
    df["Nc"] = np.where(df["Na2O"] >= df["CO2"], df["CO2"], df["Na2O"]).T

    df["Na2O"] = np.where(df["Na2O"] >= df["CO2"], df["Na2O"] - df["Nc"], df["Na2O"]).T

    df["CO2"] = np.where(df["Na2O"] >= df["CO2"], df["CO2"], df["CO2"] - df["Nc"]).T

    df["Cc"] = np.where(df["CaO"] >= df["CO2"], df["CO2"], df["CaO"]).T

    df["CaO"] = np.where(df["Na2O"] >= df["CO2"], df["CaO"] - df["Cc"], df["CaO"]).T

    df["CO2"] = np.where(df["Na2O"] >= df["CO2"], df["CO2"], df["CO2"] - df["Cc"]).T

    df["FREECO2"] = df["CO2"]

    # Normative Chromite
    df["Cm"] = np.where(df["FeO"] >= df["Cr2O3"], df["Cr2O3"], df["FeO"]).T

    df["FeO"] = np.where(df["FeO"] >= df["Cr2O3"], df["FeO"] - df["Cm"], 0).T
    df["Cr2O3"] = np.where(
        df["FeO"] >= df["Cr2O3"], df["Cr2O3"] - df["Cm"], df["Cr2O3"]
    ).T

    df["FREE_CR2O3"] = df["Cm"]

    # Normative Ilmenite
    df["Il"] = np.where(df["FeO"] >= df["TiO2"], df["TiO2"], df["FeO"]).T

    df["FeO_"] = np.where(df["FeO"] >= df["TiO2"], df["FeO"] - df["Il"], 0).T

    df["TiO2_"] = np.where(df["FeO"] >= df["TiO2"], 0, df["TiO2"] - df["Il"]).T

    df["FeO"] = df["FeO_"]

    df["TiO2"] = df["TiO2_"]

    # Normative Orthoclase/potasium metasilicate

    df["Or_p"] = np.where(df["Al2O3"] >= df["K2O"], df["K2O"], df["Al2O3"]).T

    df["Al2O3_"] = np.where(df["Al2O3"] >= df["K2O"], df["Al2O3"] - df["Or_p"], 0).T

    df["K2O_"] = np.where(df["Al2O3"] >= df["K2O"], 0, df["K2O"] - df["Or_p"]).T

    df["Ks"] = df["K2O_"]

    df["Y"] = np.where(
        df["Al2O3"] >= df["K2O"],
        df["Y"] + (df["Or_p"] * 6),
        df["Y"] + (df["Or_p"] * 6 + df["Ks"]),
    ).T

    df["Al2O3"] = df["Al2O3_"]
    df["K2O"] = df["K2O_"]

    # Normative Albite (provisional)
    df["Ab_p"] = np.where(df["Al2O3"] >= df["Na2O"], df["Na2O"], df["Al2O3"]).T

    df["Al2O3_"] = np.where(df["Al2O3"] >= df["Na2O"], df["Al2O3"] - df["Ab_p"], 0).T

    df["Na2O_"] = np.where(df["Al2O3"] >= df["Na2O"], 0, df["Na2O"] - df["Ab_p"]).T

    df["Y"] = df["Y"] + (df["Ab_p"] * 6)

    df["Al2O3"] = df["Al2O3_"]
    df["Na2O"] = df["Na2O_"]

    # Normative Acmite / sodium metasilicate - 2(NaFe3+Si2O6), Na2SiO3
    df["Ac"] = np.where(df["Na2O"] >= df["Fe2O3"], df["Fe2O3"], df["Na2O"]).T

    df["Na2O_"] = np.where(df["Na2O"] >= df["Fe2O3"], df["Na2O"] - df["Ac"], 0).T

    df["Fe2O3_"] = np.where(df["Na2O"] >= df["Fe2O3"], 0, df["Fe2O3"] - df["Ac"]).T

    df["Ns"] = df["Na2O_"]

    df["Y"] = np.where(
        df["Na2O"] >= df["Fe2O3"],
        df["Y"] + (4 * df["Ac"] + df["Ns"]),
        df["Y"] + 4 * df["Ac"],
    ).T

    df["Na2O"] = df["Na2O_"]
    df["Fe2O3"] = df["Fe2O3_"]

    # Normative Anorthite / Corundum
    df["An"] = np.where(df["Al2O3"] >= df["CaO"], df["CaO"], df["Al2O3"]).T

    df["Al2O3_"] = np.where(df["Al2O3"] >= df["CaO"], df["Al2O3"] - df["An"], 0).T

    df["CaO_"] = np.where(df["Al2O3"] >= df["CaO"], 0, df["CaO"] - df["An"]).T

    df["C"] = df["Al2O3_"]

    df["Al2O3"] = df["Al2O3_"]

    df["CaO"] = df["CaO_"]

    df["Y"] = df["Y"] + 2 * df["An"]

    # Normative Sphene / Rutile
    df["Tn_p"] = np.where(df["CaO"] >= df["TiO2"], df["TiO2"], df["CaO"]).T

    df["CaO_"] = np.where(df["CaO"] >= df["TiO2"], df["CaO"] - df["Tn_p"], 0).T

    df["TiO2_"] = np.where(df["CaO"] >= df["TiO2"], 0, df["TiO2"] - df["Tn_p"]).T

    df["CaO"] = df["CaO_"]
    df["TiO2"] = df["TiO2_"]

    df["Ru"] = df["TiO2"]

    df["Y"] = df["Y"] + df["Tn_p"]

    # Normative Magnetite / Hematite
    df["Mt"] = np.where(df["Fe2O3"] >= df["FeO"], df["FeO"], df["Fe2O3"]).T

    df["Fe2O3_"] = np.where(df["Fe2O3"] >= df["FeO"], df["Fe2O3"] - df["Mt"], 0.0).T

    df["FeO_"] = np.where(df["Fe2O3"] >= df["FeO"], 0.0, df["FeO"] - df["Mt"]).T

    df["Fe2O3"] = df["Fe2O3_"]

    df["FeO"] = df["FeO_"]

    # remaining Fe2O3 goes into haematite
    df["Hm"] = df["Fe2O3"]

    # Subdivision of some normative minerals
    df["MgFe_O"] = df[["FeO", "MgO"]].sum(axis=1)

    df["MgO_ratio"] = df["MgO"] / df["MgFe_O"]
    df["FeO_ratio"] = df["FeO"] / df["MgFe_O"]

    # Provisional normative dioside, wollastonite / Hypersthene
    df["Di_p"] = np.where(df["CaO"] >= df["MgFe_O"], df["MgFe_O"], df["CaO"]).T

    df["CaO_"] = np.where(df["CaO"] >= df["MgFe_O"], df["CaO"] - df["Di_p"], 0).T

    df["MgFe_O_"] = np.where(df["CaO"] >= df["MgFe_O"], 0, df["MgFe_O"] - df["Di_p"]).T

    df["Hy_p"] = df["MgFe_O_"]

    df["Wo_p"] = np.where(df["CaO"] >= df["MgFe_O"], df["CaO_"], 0).T

    df["Y"] = np.where(
        df["CaO"] >= df["MgFe_O"],
        df["Y"] + (2 * df["Di_p"] + df["Wo_p"]),
        df["Y"] + (2 * df["Di_p"] + df["Hy_p"]),
    ).T

    df["CaO"] = df["CaO_"]
    df["MgFe_O"] = df["MgFe_O_"]

    # Normative quartz / undersaturated minerals
    df["Q"] = np.where(df["SiO2"] >= df["Y"], df["SiO2"] - df["Y"], 0).T

    df["D"] = np.where(df["SiO2"] < df["Y"], df["Y"] - df["SiO2"], 0).T

    df["deficit"] = df["D"] > 0

    # Normative Olivine / Hypersthene - Mg2SiO4, MgSiO3
    df["Ol_"] = np.where((df["D"] < df["Hy_p"] / 2), df["D"], df["Hy_p"] / 2).T

    df["Hy"] = np.where((df["D"] < df["Hy_p"] / 2), df["Hy_p"] - 2 * df["D"], 0).T

    df["D1"] = df["D"] - df["Hy_p"] / 2

    df["Ol"] = np.where((df["deficit"]), df["Ol_"], 0).T

    df["Hy"] = np.where((df["deficit"]), df["Hy"], df["Hy_p"]).T

    df["deficit"] = df["D1"] > 0

    # Normative Sphene / Perovskite - CaTiSiO5 / CaTiO3
    df["Tn"] = np.where((df["D1"] < df["Tn_p"]), df["Tn_p"] - df["D1"], 0).T

    df["Pf_"] = np.where((df["D1"] < df["Tn_p"]), df["D1"], df["Tn_p"]).T

    df["D2"] = df["D1"] - df["Tn_p"]

    df["Tn"] = np.where((df["deficit"]), df["Tn"], df["Tn_p"]).T
    df["Pf"] = np.where((df["deficit"]), df["Pf_"], 0).T

    df["deficit"] = df["D2"] > 0

    # Normative Nepheline / Albite - 2(NaAlSi3O8) / 2(NaAlSiO8)
    df["Ne_"] = np.where((df["D2"] < 4 * df["Ab_p"]), df["D2"] / 4, df["Ab_p"]).T

    df["Ab"] = np.where((df["D2"] < 4 * df["Ab_p"]), df["Ab_p"] - df["D2"] / 4, 0).T

    df["D3"] = df["D2"] - 4 * df["Ab_p"]

    df["Ne"] = np.where((df["deficit"]), df["Ne_"], 0).T
    df["Ab"] = np.where((df["deficit"]), df["Ab"], df["Ab_p"]).T

    df["deficit"] = df["D3"] > 0

    # Normative Leucite / Orthoclase
    df["Lc"] = np.where((df["D3"] < 2 * df["Or_p"]), df["D3"] / 2, df["Or_p"]).T

    df["Or"] = np.where((df["D3"] < 2 * df["Or_p"]), df["Or_p"] - df["D3"] / 2, 0).T

    df["D4"] = df["D3"] - 2 * df["Or_p"]

    df["Lc"] = np.where((df["deficit"]), df["Lc"], 0).T
    df["Or"] = np.where((df["deficit"]), df["Or"], df["Or_p"]).T

    df["deficit"] = df["D4"] > 0

    # Normative dicalcium silicate / wollastonite
    df["Cs"] = np.where((df["D4"] < df["Wo_p"] / 2), df["D4"], df["Wo_p"] / 2).T

    df["Wo"] = np.where((df["D4"] < df["Wo_p"] / 2), df["Wo_p"] - 2 * df["D4"], 0).T

    df["D5"] = df["D4"] - df["Wo_p"] / 2

    df["Cs"] = np.where((df["deficit"]), df["Cs"], 0).T
    df["Wo"] = np.where((df["deficit"]), df["Wo"], df["Wo_p"]).T

    df["deficit"] = df["D5"] > 0

    # Normative dicalcium silicate / Olivine Adjustment
    df["Cs_"] = np.where(
        (df["D5"] < df["Di_p"]), df["D5"] / 2 + df["Cs"], df["Di_p"] / 2 + df["Cs"]
    ).T

    df["Ol_"] = np.where(
        (df["D5"] < df["Di_p"]), df["D5"] / 2 + df["Ol"], df["Di_p"] / 2 + df["Ol"]
    ).T

    df["Di_"] = np.where((df["D5"] < df["Di_p"]), df["Di_p"] - df["D5"], 0).T

    df["D6"] = df["D5"] - df["Di_p"]

    df["Cs"] = np.where((df["deficit"]), df["Cs_"], df["Cs"]).T
    df["Ol"] = np.where((df["deficit"]), df["Ol_"], df["Ol"]).T
    df["Di"] = np.where((df["deficit"]), df["Di_"], df["Di_p"]).T

    df["deficit"] = df["D6"] > 0

    # Normative Kaliophilite / Leucite
    df["Kp"] = np.where((df["Lc"] >= df["D6"] / 2), df["D6"] / 2, df["Lc"]).T

    df["Lc_"] = np.where((df["Lc"] >= df["D6"] / 2), df["Lc"] - df["D6"] / 2, 0).T

    df["Kp"] = np.where((df["deficit"]), df["Kp"], 0).T
    df["Lc"] = np.where((df["deficit"]), df["Lc_"], df["Lc"]).T

    df["DEFSIO2"] = np.where(
        (df["Lc"] < df["D6"] / 2) & (df["deficit"]), df["D6"] - 2 * df["Kp"], 0
    ).T
    ############################################################################
    # Allocate definite mineral proportions
    # Subdivide Hypersthene, Diopside and Olivine into Mg- and Fe- varieties
    # TODO: Add option for subdivision?

    df["Fe-Hy"] = df["Hy"] * df["FeO_ratio"]
    df["Fe-Di"] = df["Di"] * df["FeO_ratio"]
    df["Fe-Ol"] = df["Ol"] * df["FeO_ratio"]

    df["Mg-Hy"] = df["Hy"] * df["MgO_ratio"]
    df["Mg-Di"] = df["Di"] * df["MgO_ratio"]
    df["Mg-Ol"] = df["Ol"] * df["MgO_ratio"]

    ############################################################################
    # calculate free component molecular abundances
    #
    # Note that this accounts for potential differnces between mass used in
    # Verma's implementation and that of periodictable
    ############################################################################
    FREE = pd.DataFrame()

    FREE["FREEO_12b"] = (
        (1 + ((0.1) * ((minerals["CaF2-Ap"]["mass"] / 328.86918) - 1)))
        * pt.O.mass
        * df["FREEO_12b"]
    )
    FREE["FREEO_12c"] = (
        (
            1
            + (
                (0.1)
                * (df["CaF2-Ap"] / df["Ap"])
                * ((minerals["CaF2-Ap"]["mass"] / 328.86918) - 1)
            )
        )
        * pt.O.mass
        * df["FREEO_12c"]
    )

    FREE["FREEO_13"] = (
        (1 + ((pt.formula("CaO").mass / 56.0774) - 1)) * pt.O.mass * df["FREEO_13"]
    )

    FREE["FREEO_14"] = (
        (1 + (0.5 * ((pt.formula("Na2O").mass / 61.9789) - 1)))
        * pt.O.mass
        * df["FREEO_14"]
    )

    FREE["FREEO_16"] = (
        (1 + ((pt.formula("FeO").mass / 71.8444) - 1)) * pt.O.mass * df["FREEO_16"]
    )

    FREE["O"] = FREE[
        ["FREEO_12b", "FREEO_12c", "FREEO_13", "FREEO_14", "FREEO_16"]
    ].sum(axis=1)

    ############################################################################
    # get masses of free components
    ############################################################################
    FREE["CO2"] = df["FREECO2"] * pt.formula("CO2").mass  # 44.0095

    FREE["P2O5"] = df["FREE_P2O5"] * pt.formula("P2O5").mass  # 141.94452
    FREE["F"] = df["FREE_F"] * pt.F.mass  # 18.9984032
    FREE["Cl"] = df["FREE_Cl"] * pt.Cl.mass  # 35.4527
    FREE["SO3"] = df["FREE_SO3"] * pt.formula("SO3").mass  # 80.0642
    FREE["S"] = df["FREE_S"] * pt.S.mass  # 32.066
    FREE["Cr2O3"] = df["FREE_CR2O3"] * pt.formula("Cr2O3").mass  # 151.990

    FREE["OXIDES"] = FREE[["P2O5", "F", "Cl", "SO3", "S", "Cr2O3"]].sum(axis=1)

    FREE["DEFSIO2"] = df["DEFSIO2"] * pt.formula("SiO2").mass  # 60.0843
    FREE.drop(["P2O5", "F", "Cl", "SO3", "S", "Cr2O3"], axis=1, inplace=True)

    ############################################################################
    # populate tables of molecular proportions and masses
    ############################################################################
    mineral_proportions = pd.DataFrame()
    mineral_pct_mm = pd.DataFrame()

    for mineral in minerals.keys():
        if mineral == ["Ap"]:
            # deal with the results of apatite options
            # get the abundance weighted total mass of apatite where split
            # otherwise just get the apatite mass
            mineral_pct_mm[mineral] = np.where(
                df["ap_option"] == 2,
                df[mineral] * minerals["Ap"]["mass"],
                (df["CaF2-Ap"] * minerals["CaF2-Ap"]["mass"])
                + (df["CaO-Ap"] * minerals["Ap"]["mass"]),
            )
        else:
            mineral_proportions[mineral] = df.loc[:, mineral]
            mineral_pct_mm[mineral] = df.loc[:, mineral] * minerals[mineral]["mass"]

    # rename columns with proper names rather than abbreviations
    mineral_pct_mm.columns = [
        minerals[mineral]["name"] for mineral in mineral_pct_mm.columns
    ]
    mineral_pct_mm.fillna(0, inplace=True)

    return mineral_pct_mm
Пример #53
0
total_compounds_int = len(total_compounds_dict)
total_symbols_list = []

# A list of symbols is a requirement for sp.linsolve to appropriately solve the system, and each one must be converted
# to sp.Symbol
for key in total_compounds_dict.keys():
    total_symbols_list.append(sp.Symbol(key))

# Checking if the system is balanced by calling the check_rxn_balance function from Chemistry
balance = check_rxn_balance(reactants, products)

# If the balance fails then the magic of sympy will solve it by setting up a system of linear equations and a matrix
if balance is False:
    # The total elements in the equation (H, C, O, etc) need to be obtained
    total_elements_list = list(
        ptable.formula(''.join(str(compound) for compound in reactants)).atoms)

    # The rows of the equation matrix is each element in the equation
    rows = len(total_elements_list)

    # The columns are the total compounds present in the equation
    cols = total_compounds_int

    # The equation matrix is defined using the zeros function, al slots are set to zero for easy manipulation
    equation_matrix = sp.zeros(rows, cols)

    # y is the counter variable for elements, it represents where the program is in the rows
    y = 0

    for compound in reactants:
        # x does the same thing as y, but for the columns
Пример #54
0
from collections import OrderedDict
import uncertainties as uct
import periodictable as ptable
import scipy.constants as constants
from ..conversion import vol_uc2mol, vol_mol2uc
from .objs import MGEOS, JHEOS

v_ref = 74.698  # 3.9231**3  # default v0
n = 2.
z = 4.
ef_v = 0.001
ef_temp = 0.05
mass = ptable.formula("MgO").mass * 1.e-3  # to kg
v0_mol = vol_uc2mol(v_ref, z)
rho0 = mass / v0_mol  # kg/m^3


class Jamieson1982(JHEOS):
    """
    Jamieson et al. 1982. High pressure research in geophysics.
    """
    def __init__(self, v0=v_ref):
        mass_shock = mass * 1.e3  # to mass in g
        three_r = 1.23754 / (3. * n * constants.R / mass_shock) * 3. *\
            constants.R
        rho0 = 3.585  # g/cm^3 from Jamieson
        params_hugoniot = OrderedDict([('rho0', uct.ufloat(rho0, 0.0)),
                                       ('c0', uct.ufloat(6.597, 0.0)),
                                       ('s', uct.ufloat(1.369, 0.0))])
        v0 = vol_mol2uc(mass / (rho0 * 1.e3), z)
        params_therm = OrderedDict([('v0', uct.ufloat(v0, ef_v)),
Пример #55
0
    H2O, D2O, DHO, Si, Al2O3, Au, Ni8Fe2

If you want to adjust the density you will need to make your own copy of
these materials.  For example, for permalloy::

    >>> NiFe=Material(permalloy.formula,density=permalloy.bulk_density)
    >>> NiFe.density.pmp(10)  # Let density vary by 10% from bulk value
    Parameter(permalloy density)
"""
import periodictable
from .material import Vacuum, Material

__all__ = [
    'air', 'water', 'H2O', 'heavywater', 'D2O', 'lightheavywater', 'DHO',
    'silicon', 'Si', 'sapphire', 'Al2O3', 'gold', 'Au', 'permalloy', 'Ni8Fe2'
]

# Set the bulk density of heavy water assuming it has the same packing
# fraction as water, but with heavier H[2] substituted for H[1].
rho_D2O = periodictable.formula('D2O').mass / periodictable.formula('H2O').mass
rho_DHO = periodictable.formula('DHO').mass / periodictable.formula('H2O').mass

air = Vacuum()
water = H2O = Material('H2O', density=1, name='water')
heavywater = D2O = Material('D2O', density=rho_D2O)
lightheavywater = DHO = Material('DHO', density=rho_DHO)
silicon = Si = Material('Si')
sapphire = Al2O3 = Material('Al2O3', density=3.965, name='sapphire')
gold = Au = Material('Au', name='gold')
permalloy = Ni8Fe2 = Material('Ni8Fe2', density=8.692, name='permalloy')
Пример #56
0
def test():
    ikaite = formula()
    # Note: this should be a tuple of tuples
    ikaite.structure = ((1, Ca), (1, C), (3, O), (6, ((2, H), (1, O))))

    # Test print
    assert str(ikaite) == "CaCO3(H2O)6"

    # Test constructors
    assert ikaite == formula([(1, Ca), (1, C), (3, O), (6, [(2, H), (1, O)])])
    assert ikaite == formula(ikaite)
    assert ikaite is not formula(ikaite)
    assert ikaite.structure is formula(ikaite).structure

    # Test parsers
    assert formula("Ca") == formula([(1, Ca)])
    assert formula("Ca") == formula(Ca)
    assert formula("CaCO3") == formula([(1, Ca), (1, C), (3, O)])
    assert ikaite == formula("CaCO3+6H2O")
    assert ikaite == formula("(CaCO3+6H2O)1")
    assert ikaite == formula("CaCO3 6H2O")
    assert ikaite == formula("CaCO3(H2O)6")
    assert ikaite == formula("(CaCO3(H2O)6)1")
    assert ikaite.hill == formula("CCaO3(H2O)6").hill
    assert str(ikaite.hill) == "CH12CaO9"
    assert formula([(0.75, Fe), (0.25, Ni)]) == formula("Fe0.75Ni0.25")

    # Test composition
    #print formula("CaCO3") + 6*formula("H2O")
    assert ikaite == formula("CaCO3") + 6 * formula("H2O")
    f = formula('')
    assert not (3 * f).structure
    f = formula('H2O')
    assert id((1 * f).structure) == id(f.structure)

    # Check atom count
    assert formula("Fe2O4+3H2O").atoms == {Fe: 2, O: 7, H: 6}

    # Check charge
    assert formula("P{5+}O{2-}4").charge == -3
    try:
        formula("P{18-}")
        raise Exception("No exception raised for invalid charge")
    except ValueError:
        pass
    assert formula("Na{+}Cl{-}").charge == 0
    Na_frac = Na.ion[1].mass / (Na.ion[1].mass + Cl.ion[-1].mass)
    assert abs(formula("Na{+}Cl{-}").mass_fraction[Na.ion[1]] -
               Na_frac) < 1e-14

    # Check the mass calculator
    assert formula('H2O').mass == 2 * H.mass + O.mass
    assert formula("Fe2O4+3H2O").mass == 2 * Fe.mass + 7 * O.mass + 6 * H.mass
    assert (formula("Fe2O[18]4+3H2O").mass == 2 * Fe.mass + 4 * O[18].mass +
            3 * O.mass + 6 * H.mass)

    # Check natural density support
    assert (formula('D2O',
                    natural_density=1).density == (2 * D.mass + O.mass) /
            (2 * H.mass + O.mass))
    D2O = formula('D2O', natural_density=1)
    D2Os = formula('D2O')
    D2Os.natural_density = 1
    assert abs(D2O.density - D2Os.density) < 1e-14
    assert abs(D2O.natural_density - 1) < 1e-14
    assert abs(D2Os.natural_density - 1) < 1e-14

    # Test isotopes; make sure this is last since it changes ikaite!
    assert ikaite != formula("CaCO[18]3+6H2O")
    assert formula("O[18]").mass == O[18].mass

    # Check x-ray and neutron sld
    rho, mu, inc = formula('Si', Si.density).neutron_sld(wavelength=4.5)
    rhoSi, muSi, incSi = Si.neutron.sld(wavelength=4.5)
    assert abs(rho - rhoSi) < 1e-14
    assert abs(mu - muSi) < 1e-14
    assert abs(inc - incSi) < 1e-14

    rho, mu = formula('Si', Si.density).xray_sld(wavelength=1.54)
    rhoSi, muSi = Si.xray.sld(wavelength=1.54)
    assert abs(rho - rhoSi) < 1e-14
    assert abs(mu - muSi) < 1e-14

    # Check that names work
    permalloy = formula('Ni8Fe2', 8.692, name='permalloy')
    assert str(permalloy) == 'permalloy'

    # Check that get/restore state works
    assert deepcopy(permalloy).__dict__ == permalloy.__dict__

    # Check that copy constructor works
    #print permalloy.__dict__
    #print formula(permalloy).__dict__
    assert formula(permalloy).__dict__ == permalloy.__dict__
    assert formula('Si', name='Silicon').__dict__ != formula('Si').__dict__

    H2O = formula('H2O', natural_density=1)
    D2O = formula('D2O', natural_density=1)
    fm = mix_by_weight(H2O, 3, D2O, 2)
    fv = mix_by_volume(H2O, 3, D2O, 2)
    # quantity of H+D should stay in 2:1 ratio with O
    assert abs(fv.atoms[H] + fv.atoms[D] - 2 * fv.atoms[O]) < 1e-14
    assert abs(fm.atoms[H] + fm.atoms[D] - 2 * fm.atoms[O]) < 1e-14
    # H:D ratio should match H2O:D2O ratio when mixing by volume, but should
    # be skewed toward the lighter H when mixing by mass.
    assert abs(fv.atoms[H] / fv.atoms[D] - 1.5) < 1e-14
    assert abs(fm.atoms[H] / fm.atoms[D] -
               1.5 * D2O.density / H2O.density) < 1e-14
    # Mass densities should average according to H2O:D2O ratio when
    # mixing by volume but be skewed toward toward the more plentiful
    # H2O when mixing by mass
    H2O_fraction = 0.6
    assert abs(fv.density - (H2O.density * H2O_fraction + D2O.density *
                             (1 - H2O_fraction))) < 1e-14
    H2O_fraction = (3 / H2O.density) / (3 / H2O.density + 2 / D2O.density)
    assert abs(fm.density - (H2O.density * H2O_fraction + D2O.density *
                             (1 - H2O_fraction))) < 1e-14

    # Make sure we are independent of unit cell size
    H2O = formula('3.2H2O', natural_density=1)
    D2O = formula('4.1D2O', natural_density=1)
    fm = mix_by_weight(H2O, 3, D2O, 2)
    fv = mix_by_volume(H2O, 3, D2O, 2)
    # quantity of H+D should stay in 2:1 ratio with O
    assert abs(fv.atoms[H] + fv.atoms[D] - 2 * fv.atoms[O]) < 1e-14
    assert abs(fm.atoms[H] + fm.atoms[D] - 2 * fm.atoms[O]) < 1e-14
    # H:D ratio should match H2O:D2O ratio when mixing by volume, but should
    # be skewed toward the lighter H when mixing by mass.
    assert abs(fv.atoms[H] / fv.atoms[D] - 1.5) < 1e-14
    assert abs(fm.atoms[H] / fm.atoms[D] -
               1.5 * D2O.density / H2O.density) < 1e-14
    # Mass densities should average according to H2O:D2O ratio when
    # mixing by volume but be skewed toward toward the more plentiful
    # H2O when mixing by mass
    H2O_fraction = 0.6
    assert abs(fv.density - (H2O.density * H2O_fraction + D2O.density *
                             (1 - H2O_fraction))) < 1e-14
    H2O_fraction = (3 / H2O.density) / (3 / H2O.density + 2 / D2O.density)
    assert abs(fm.density - (H2O.density * H2O_fraction + D2O.density *
                             (1 - H2O_fraction))) < 1e-14

    # Pickle test
    assert loads(dumps(fm)) == fm
    ion = Fe[56].ion[2]
    assert id(loads(dumps(ion))) == id(ion)

    # zero quantities tests in mixtures
    f = mix_by_weight(H2O, 0, D2O, 2)
    assert f == D2O
    f = mix_by_weight(H2O, 2, D2O, 0)
    assert f == H2O
    f = mix_by_weight(H2O, 0, D2O, 0)
    assert f == formula()
    f = mix_by_volume(H2O, 0, D2O, 2)
    assert f == D2O
    f = mix_by_volume(H2O, 2, D2O, 0)
    assert f == H2O
    f = mix_by_volume(H2O, 0, D2O, 0)
    assert f == formula()

    # mix by weight with unknown component density
    # can't do mix by volume without component densities
    glass = mix_by_weight('SiO2', 75, 'Na2O', 15, 'CaO', 10, density=2.52)

    # layers and mixtures
    check_formula(formula('1mm Fe // 1mm Ni'), formula('50%vol Fe // Ni'))
    check_formula(formula('50%vol Co // Ti'), formula('2mL Co // 2mL Ti'))
    check_formula(formula('50%wt Co // Ti'), formula('2g Co // 2g Ti'))
    check_formula(formula('2mL Co // 2mL Ti'),
                  formula(((1.5922466356368357, Co), (1, Ti))))
    check_formula(formula('2g Co // 2g Ti'),
                  formula(((1, Co), (1.231186412350889, Ti))))
    check_formula(formula('5g NaCl // 50mL H2O@1'),
                  formula('5g NaCl // 50g H2O'))
    check_formula(formula('5g NaCl // 50mL H2O@1'),
                  formula(((1, Na), (1, Cl), (32.4407, ((2, H), (1, O))))),
                  tol=1e-5)
    assert abs(formula('1mm Fe // 1mm Ni').thickness - 0.002) < 0.002 * 1e014
    assert abs(formula('2g Co // 2g Ti').total_mass - 4) < 4 * 1e-14
    check_mass(formula('2mL Co // 2mL Ti'), mass=2 * (Co.density + Ti.density))
    check_mass(formula("50 g (49 mL H2O@1 // 1 g NaCl) // 20 mL D2O@1n"),
               mass=50 + 20 * D2O.density)
    check_mass(
        formula("50 mL (45 mL H2O@1 // 5 g NaCl)@1.0707 // 20 mL D2O@1n"),
        mass=50 * 1.0707 + 20 * D2O.density)

    # fasta
    check_formula(formula('aa:A'), formula('C3H4H[1]NO'))
Пример #57
0
    def __init__(self):
        self.exp_props = {
            'Fe': {
                'a': 2.87,
                'Ec': 4.28,
                'Evf': 1.79,
                'B': 170,
                'cijexp': {
                    'C11': 226,
                    'C12': 140,
                    'C44': 116
                }
            },
            'V': {
                'a': 3.03,
                'Ec': 5.31,
                'B': 47,
                'cijexp': {
                    'C11': 229,
                    'C12': 140,
                    'C44': 116
                },
                'Evf': 2.2
            },
            'Mo': {
                'a': 3.1472,
                'Ec': 6.82,
                'Evf': 3.10,
                'B': 230,
                'cijexp': {
                    'C11': 463.7,
                    'C12': 157.8,
                    'C44': 109.2
                }
            },
            'Nb': {
                'a': 3.3,
                'Ec': 7.57,
                'Evf': 2.75,
                'B': 170,
                'cijexp': {
                    'C11': 247,
                    'C12': 135,
                    'C44': 28.7
                }
            },
            'Ta': {
                'a': 3.3,
                'Ec': 8.1,
                'Evf': 2.18,
                'B': 200,
                'cijexp': {
                    'C11': 266.3,
                    'C12': 158.2,
                    'C44': 87.4
                }
            },
            'W': {
                'a': 3.16,
                'Ec': 8.9,
                'Evf': 3.95,
                'B': 310,
                'cijexp': {
                    'C11': 532,
                    'C12': 204.9,
                    'C44': 163.1
                }
            },
            'Cu': {
                'a': 3.61,
                'Ec': 3.49,
                'Evf': 1.28,
                'B': 140,
                'cijexp': {
                    'C11': 168.4,
                    'C12': 121.4,
                    'C44': 75.4
                }
            },
            'Ag': {
                'a': 4.09,
                'Ec': 2.95,
                'Evf': 1.1,
                'B': 100,
                'cijexp': {
                    'C11': 124,
                    'C12': 93.7,
                    'C44': 46.1
                }
            },
            'Au': {
                'a': 4.08,
                'Ec': 3.81,
                'Evf': 0.9,
                'B': 220,
                'cijexp': {
                    'C11': 192.3,
                    'C12': 163.1,
                    'C44': 42.0
                }
            },
            'Ni': {
                'a': 3.52,
                'Ec': 4.44,
                'Evf': 1.6,
                'B': 180,
                'cijexp': {
                    'C11': 245,
                    'C12': 140,
                    'C44': 125
                }
            },
            'Pd': {
                'a': 3.89,
                'Ec': 3.89,
                'Evf': 1.4,
                'B': 180,
                'cijexp': {
                    'C11': 227.1,
                    'C12': 176.1,
                    'C44': 71.7
                }
            },
            'Pt': {
                'a': 3.92,
                'Ec': 5.84,
                'Evf': 1.5,
                'B': 230,
                'cijexp': {
                    'C11': 347.0,
                    'C12': 251,
                    'C44': 76.5
                }
            },
            'Al': {
                'a': 4.05,
                'Ec': 3.34,
                'Sh': 26,
                'B': 76,
                'Pr': 0.35,
                'E': 70,
                'cijcalc': {
                    'fcc': {
                        'C11': 101.0,
                        'C12': 61,
                        'C44': 25.4
                    }
                },
                'cijexp': {
                    'C11': 114.0,
                    'C12': 61.9,
                    'C44': 31.6
                }
            },
            'Mg': {
                'Ec': 1.53,
                'B': 45,
                'cijexp': {
                    'C11': 59.3,
                    'C33': 61.5,
                    'C44': 16.4,
                    'C12': 25.7,
                    'C13': 21.4
                }
            },
            'Ti': {
                'Ec': 1.87,
                'B': 116,
                'cijexp': {
                    'C11': 160,
                    'C33': 181,
                    'C44': 46.5,
                    'C12': 90,
                    'C13': 66
                }
            },
            'Zr': {
                'Ec': 6.136,
                'B': 'nd',
                'cijexp': {
                    'C11': 144,
                    'C33': 166,
                    'C44': 33.4,
                    'C12': 74,
                    'C13': 67
                }
            },
            'Co': {
                'Ec': 4.387,
                'B': 180,
                'cijexp': {
                    'C11': 295,
                    'C33': 335,
                    'C44': 71,
                    'C12': 159,
                    'C13': 111
                }
            },
            'Pb': {
                'Ec': 2.04,
                'B': 46,
                'cijexp': {
                    'C11': 55.5,
                    'C12': 45.4,
                    'C44': 19.4
                }
            },
            'Cr': {
                'Ec': 4.1,
                'B': 279,
                'a': 2.91,
                'cijexp': {
                    'C11': 391,
                    'C12': 90.0,
                    'C44': 103.2
                }
            },
            'Y': {
                'Ec': 4.387,
                'B': 41,
                'cijexp': {
                    'C11': 77.9,
                    'C33': 76.9,
                    'C44': 24.3,
                    'C12': 29.2,
                    'C13': 20
                }
            },
            'Si': {
                'a': 5.430099,
                'Ec': 4.64,
                'Sh': 'no-data',
                'B': 100,
                'Pr': 'no-data',
                'E': 47,
                'cijcalc': {
                    'fcc': {
                        'C11': 64.4,
                        'C12': 87.2,
                        'C44': 4.7
                    }
                },
                'cijexp': {
                    'C11': 166.0,
                    'C12': 63.9,
                    'C44': 79.6
                }
            },
            'U': {
                'Ec': 5.405,
                'B': 100,
                'cijexp': {
                    'C11': 13.6,
                    'C44': 165.6,
                    'C12': 20.2
                },
                'cijcalc': {
                    'fcc': {
                        'C11': 13.6,
                        'C44': 165.6,
                        'C12': 20.2
                    }
                }
            }
        }

        for e in self.exp_props:
            #print e, exp_props[e].keys()
            form = pt.formula(e)
            a = form.structure[0][1].crystal_structure
            self.exp_props[e]['crystal_structure'] = a
Пример #58
0
from periodictable import elements
from uncertainties import ufloat
from sqlalchemy.dialects.postgresql import JSON
from sqlalchemy.ext.hybrid import hybrid_property
from flask_sqlalchemy import BaseQuery
from geoalchemy2.types import Geometry
from slugify import slugify
from collections import defaultdict

from .image import ProbeImage
from ..converter import Converter
from .compute import oxygen_basis, compute_mineral
from ...config import OXIDES, MINERALS, MINERAL_SYSTEMS
from ...core.models import BaseModel, db

FORMULAE = {k: pt.formula(k) for k in OXIDES}

tags = db.Table(
    'tag_manager',
    db.Column('tag_name', db.String(64), db.ForeignKey('tag.name')),
    db.Column('page_id', db.Integer, db.ForeignKey('probe_measurement.id')))


class Tag(BaseModel):
    name = db.Column(db.String(64), primary_key=True)
    __str__ = lambda self: self.name
    __repr__ = lambda self: "Tag {0}".format(self)


class ProbeSession(BaseModel):
    __tablename__ = "probe_session"
Пример #59
0
 def formula(self):
     if _is_list_like(self._formula):
         return get_formula(self._formula)
     else:
         return PT.formula(self._formula)
Пример #60
0
def chemicalformula2exactmass(chemicalformula):
    """ calculate exact mass from chemical formula with periodictable """
    chemformula = periodictable.formula(chemicalformula)
    return chemformula.mass