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
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
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
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)
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
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)
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
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)
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)
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))
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))
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
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))
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
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
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)
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)
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
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
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
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
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')
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
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()
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
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. """
# 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)
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
def hf(self): return pt.formula(self.head_formula)
def formula(self): return pt.formula(self.head_formula) + pt.formula(self.tail_formula)
}, "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.
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
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__
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
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))
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]
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
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)
def tf(self): return pt.formula(self.tail_formula)
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)
def convert_atoms_to_formula(atoms): s = [] for k, v in atoms.items(): s.append([v, k]) return pt.formula(s)
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))])
def get_mass(self, elements): mass = [] for atom in elements: mass.append(periodictable.formula(atom).mass) mass = np.array(mass, dtype=float) return mass
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
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
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)),
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')
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'))
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
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"
def formula(self): if _is_list_like(self._formula): return get_formula(self._formula) else: return PT.formula(self._formula)
def chemicalformula2exactmass(chemicalformula): """ calculate exact mass from chemical formula with periodictable """ chemformula = periodictable.formula(chemicalformula) return chemformula.mass