def _calculate_factor(self, z): fluorescence = FluorescenceFactor(self._config_filepath, self._characteristic_model, self._bremsstrahlung_model) energy_keV = self._measurement.options.beam.energy_eV / 1000.0 fluorescence.setIncidentEnergy_keV(energy_keV) toa_deg = self._measurement.detector.takeoffangle_deg fluorescence.setTakeoffAngle_deg(toa_deg) elements = [] material = self._measurement.unknown_body.material for atomicnumber, wf in material.composition.iteritems(): elements.append(Element(atomicnumber, weightFraction=wf)) region = SampleRegion(elements) fluorescence.setSpecimenBulk(region) elements = [] material = self._measurement.get_standards()[z].material for atomicnumber, wf in material.composition.iteritems(): elements.append(Element(atomicnumber, weightFraction=wf)) region = SampleRegion(elements) fluorescence.setStandardBulk(region) transitions = self._measurement.get_transitions() transition = [t for t in transitions if t.z == z][0] element = ep.symbol(transition.z) if hasattr(transition, '__iter__'): line = transition.name else: line = transition.siegbahn_nogreek return fluorescence.getFactor(element, line)
def add_kratio(self, transition, val, unc=0.0, standard=None): """ Adds a k-ratio to this measurement. :arg transition: transition or set of transition for this k-ratio :type transition: :class:`.Transition` or :class:`.transitionset` :arg val: k-ratio value :type val: :class:`float` :arg unc: uncertainty on the k-ratio value (default: 0.0) :type unc: :class:`float` :arg standard: geometry of the standard. Although standard are usually bulk sample, it may occur that the standard geometry is not a substrate. Specifying a geometry also allows to define exact simulation parameters for the standard. If ``None``, a substrate geometry is created. The standard is assumed to be a pure (100% of the element in the specified transition) :type standard: instance of :class:`._Geometry` :raise: :exc:`ValueError` if a k-ratio or rule is already defined for the atomic number of the specified transition """ z = transition.z if z in self._transitions: raise ValueError, 'A k-ratio is already defined for element: %s' % ep.symbol( z) if z in self._rules: raise ValueError, 'A rule is already defined for element: %s' % ep.symbol( z) if val < 0.0: raise ValueError, 'k-ratio value must be greater than 0.0' if unc < 0.0: raise ValueError, 'k-ratio uncertainty must be greater than 0.0' if standard is None: standard = Substrate(pure(z)) self._transitions[z] = transition self._kratios[z] = (val, unc) self._standards[z] = standard
def selectionSymbol(self): selection = self.selection() if self.isMultipleSelection(): return frozenset(map(ep.symbol, selection)) else: if selection is None: return None else: return ep.symbol(selection)
def add_kratio(self, transition, val, unc=0.0, standard=None): """ Adds a k-ratio to this measurement. :arg transition: transition or set of transition for this k-ratio :type transition: :class:`.Transition` or :class:`.transitionset` :arg val: k-ratio value :type val: :class:`float` :arg unc: uncertainty on the k-ratio value (default: 0.0) :type unc: :class:`float` :arg standard: geometry of the standard. Although standard are usually bulk sample, it may occur that the standard geometry is not a substrate. Specifying a geometry also allows to define exact simulation parameters for the standard. If ``None``, a substrate geometry is created. The standard is assumed to be a pure (100% of the element in the specified transition) :type standard: instance of :class:`._Geometry` :raise: :exc:`ValueError` if a k-ratio or rule is already defined for the atomic number of the specified transition """ z = transition.z if z in self._transitions: raise ValueError, 'A k-ratio is already defined for element: %s' % ep.symbol(z) if z in self._rules: raise ValueError, 'A rule is already defined for element: %s' % ep.symbol(z) if val < 0.0: raise ValueError, 'k-ratio value must be greater than 0.0' if unc < 0.0: raise ValueError, 'k-ratio uncertainty must be greater than 0.0' if standard is None: standard = Substrate(pure(z)) self._transitions[z] = transition self._kratios[z] = (val, unc) self._standards[z] = standard
def _setup_region_material(region, material): region.removeAllElements() for z, fraction in material.composition.items(): region.addElement(ep.symbol(z), weightFraction=fraction) region.update() # Calculate number of elements, mean atomic number region.User_Density = True region.Rho = material.density_kg_m3 / 1000.0 # g/cm3 region.Name = material.name
def add_rule(self, rule): """ Adds a rule to this measurement. :arg rule: rule object """ z = rule.z if z in self._rules: raise ValueError, 'A rule is already defined for element: %s' % ep.symbol(z) if z in self._transitions: raise ValueError, 'A k-ratio is already defined for element: %s' % ep.symbol(z) # Ensure that there is only one ElementByDifference rule diff_rules = any(map(lambda rule: isinstance(rule, ElementByDifferenceRule), self._rules.values())) if diff_rules and isinstance(rule, ElementByDifferenceRule): raise ValueError, 'A ElementByDifferenceRule was already added' self._rules[z] = rule
def add_rule(self, rule): """ Adds a rule to this measurement. :arg rule: rule object """ z = rule.z if z in self._rules: raise ValueError, 'A rule is already defined for element: %s' % ep.symbol( z) if z in self._transitions: raise ValueError, 'A k-ratio is already defined for element: %s' % ep.symbol( z) # Ensure that there is only one ElementByDifference rule diff_rules = any( map(lambda rule: isinstance(rule, ElementByDifferenceRule), self._rules.values())) if diff_rules and isinstance(rule, ElementByDifferenceRule): raise ValueError, 'A ElementByDifferenceRule was already added' self._rules[z] = rule
def _group(z, siegbahn, iupac, include_satellite=False): transitions = [] for ssiegbahn in _SIEGBAHNS: if ssiegbahn.startswith(siegbahn): transitions.append(Transition(z, siegbahn=ssiegbahn)) transitions = filter(methodcaller('exists'), transitions) if not include_satellite: transitions = filter(methodcaller('is_diagram_line'), transitions) if not transitions: raise ValueError('No transition for %s %s' % (ep.symbol(z), iupac)) return transitionset(z, siegbahn, iupac, list(transitions))
def _shell(z, dest, include_satellite=False): subshell = Subshell(z, dest) siegbahn = subshell.siegbahn iupac = subshell.iupac transitions = [] for src, ddest, satellite in _SUBSHELLS: if ddest != dest: continue if satellite != 0 and not include_satellite: continue transitions.append(Transition(z, src, dest)) transitions = filter(methodcaller('exists'), transitions) if not transitions: raise ValueError('No transition for %s %s' % (ep.symbol(z), iupac)) return transitionset(z, siegbahn, iupac, list(transitions))
def _import_photon_intensity(self, options, name, detector, path): wxrresult = CharacteristicIntensity(path) factor = self._get_normalization_factor(options, detector) # Retrieve intensities intensities = {} for z, line in wxrresult.getAtomicNumberLines(): data = wxrresult.intensities[z][line] transition = from_string("%s %s" % (symbol(z), line)) gnf = list(map(mul, data[WXRGENERATED], [factor] * 2)) enf = list(map(mul, data[WXREMITTED], [factor] * 2)) intensities[PhotonKey(transition, False, PhotonKey.P)] = gnf intensities[PhotonKey(transition, True, PhotonKey.P)] = enf return PhotonIntensityResult(intensities)
def __init__(self, atomic_number, parent=None): QPushButton.__init__(self, parent) self.setFixedSize(40, 40) self._atomic_number = atomic_number self._symbol = ep.symbol(atomic_number) self.setText(self._symbol) font = self.font() font.setWeight(QFont.Bold) self.setFont(font) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.setDefault(False) self.setAutoDefault(False)
def generate_name(composition): """ Generates a name from the composition. The name is generated on the basis of a classical chemical formula. :arg composition: composition in weight fraction. The composition is specified by a dictionary. The key are atomic numbers and the values weight fractions. No wildcard are accepted. :type composition: :class:`dict` """ composition = Material.calculate_composition(composition) composition_atomic = Material.calculate_composition_atomic(composition) symbols = [] fractions = [] for z in sorted(composition_atomic.keys(), reverse=True): symbols.append(ep.symbol(z)) fractions.append(int(composition_atomic[z] * 100.0)) # Find gcd of the fractions smallest_gcd = 100 if len(fractions) >= 2: gcds = [] for a, b in combinations(fractions, 2): gcds.append(gcd(a, b)) smallest_gcd = min(gcds) if smallest_gcd == 0.0: smallest_gcd = 100.0 # Write formula name = '' for symbol, fraction in zip(symbols, fractions): fraction /= smallest_gcd if fraction == 0: continue elif fraction == 1: name += "%s" % symbol else: name += '%s%i' % (symbol, fraction) return name
def _extract(data, absorption): distributions = {} for z in data: for xrayline in data[z]: transition = from_string(symbol(z) + " " + xrayline) dist = np.array(data[z][xrayline]).T # Convert z values in meters dist[:, 0] *= -1e-9 # WinXRay starts from the bottom to the top # The order must be reversed dist = dist[::-1] key = PhotonKey(transition, absorption, PhotonKey.P) distributions[key] = dist return distributions
def __init__(self, z, index=None, orbital=None, iupac=None, siegbahn=None): """ Creates an atomic subshell:: s = SubShell(29, 1) # K s = SubShell(29, siegbahn='K') :arg z: atomic number (from 1 to 99 inclusively) :arg index: index of the subshell between 1 (K) and 30 (outer) :arg orbital: orbital of the subshell (e.g. ``1s1/2``) :arg iupac: IUPAC symbol of the subshell :arg siegbahn: Siegbahn symbol of the subshell If more than one argument is given, only the first one is used to create the subshell. """ self._z = z self._symbol = ep.symbol(z) if index is not None: if index < 1 or index > 30: raise ValueError("Id (%s) must be between [1, 30]." % index) elif orbital is not None: try: index = _ORBITALS.index(orbital.lower()) + 1 except ValueError: raise ValueError("Unknown orbital (%s). Possible orbitals: %s" % \ (orbital, _ORBITALS)) elif iupac is not None: try: index = _IUPACS.index(iupac.upper()) + 1 except ValueError: raise ValueError("Unknown IUPAC (%s). Possible IUPAC: %s" % \ (iupac, _IUPACS)) elif siegbahn is not None: try: index = _SIEGBAHNS.index(siegbahn.upper()) + 1 except ValueError: raise ValueError("Unknown Siegbahn (%s). Possible Siegbahn: %s" % \ (siegbahn, _SIEGBAHNS)) else: raise ValueError("You must specify an index, orbital, IUPAC or Siegbahn") self._index = index self._orbtial = _ORBITALS[index - 1] self._iupac = _IUPACS[index - 1] self._siegbahn = _SIEGBAHNS[index - 1] self._family = self._iupac[0].upper() if index != 30 else None try: self._ionization_energy_eV = subshell_data.energy_eV(z, index) except ValueError: self._ionization_energy_eV = float('inf') self._exists = subshell_data.exists(z, index) try: self._width_eV = subshell_data.width_eV(z, index) except ValueError: self._width_eV = 0.0
def testsymbol(self): self.assertEqual('H', ep.symbol(1)) self.assertEqual('Uuo', ep.symbol(118))
def testsymbol(self): self.assertEqual('Al', ep.symbol(13))
def _export_geometry_substrate(self, options, geometry, outputdir, *args): material = geometry.body.material composition = sorted(material.composition.items(), key=itemgetter(0)) density_g_cm3 = material.density_kg_m3 / 1000.0 filepath = os.path.join(outputdir, options.name + '.MAT') with open(filepath, 'wb') as fp: # Header # DELPHI: s:=6;Blockwrite(Matfile,Typ,6,f);Inc(Sum,f); # 1st Byte: Type = 2 (homogenous bulk) # 2nd Byte: NC = <nr. of elements> (amount of occurring formulae (compounds or elements)) # 3rd Byte: NZ = <nr. of elements> # 4th Byte: NP = 0 (nr. of layers) # 5th Byte: CU = 2 (1=at%, 2=wt%) # 6th Byte: MU = 1 (not important for bulk; this is the unit for the layer thickness) fp.write(struct.pack('b', 2)) fp.write(struct.pack('b', len(composition))) fp.write(struct.pack('b', len(composition))) fp.write(struct.pack('b', 0)) fp.write(struct.pack('b', 2)) fp.write(struct.pack('b', 1)) # Write length of element and element # DELPHI: # for i:=1 to Nc do begin # l:=1+Length(Comp[i]);Inc(s,l); # Blockwrite(Matfile,Comp[i,0],l,f);Inc(Sum,f); # end; for z, _wf in composition: symbol = ep.symbol(z).upper() fp.write( struct.pack('b', len(symbol)) + symbol.encode('ascii')) # Write molar mass # DELPHI: l:=4*Nc;Inc(s,l);Blockwrite(Matfile,AC[1],l,f);Inc(Sum,f); for z, _wf in composition: mass = ep.atomic_mass_kg_mol(z) * 1000.0 fp.write(struct.pack('f', mass)) # Write atomic number # DELPHI: Inc(s,NZ);Blockwrite(Matfile,Z[1],NZ,f);Inc(Sum,f); for z, _wf in composition: fp.write(struct.pack('b', z)) # Write molar mass # DELPHI: # l:=4*Nc+4; # for i:=0 to NZ do begin # Inc(s,l);BlockWrite(Matfile,GZ[i],l,f);Inc(Sum,f); # end; fp.write(b'\x00\x00\x00\x00') # Skip 4 bytes for z, _wf in composition: mass = ep.atomic_mass_kg_mol(z) * 1000.0 fp.write(struct.pack('f', mass)) for i, item in enumerate(composition): z = item[0] mass = ep.atomic_mass_kg_mol(z) * 1000.0 fp.write(struct.pack('f', mass)) fp.write(b'\x00\x00\x00\x00' * i) # Skip 4 bytes fp.write(struct.pack('f', 1.0 / mass)) fp.write(b'\x00\x00\x00\x00' * (len(composition) - i - 1)) # Skip 4 bytes # DELPHI: Inc(s,l);BlockWrite(Matfile,GM,l,f);Inc(Sum,f); gs = [ wf / (ep.atomic_mass_kg_mol(z) * 1000.0) for z, wf in composition ] g0 = 1.0 / sum(gs) fp.write(struct.pack('f', g0)) for g in gs: fp.write(struct.pack('f', g)) # DELPHI: # for i:=0 to NP do begin # Inc(s,l);BlockWrite(Matfile,GS[i],l,f);Inc(Sum,f); # end; fp.write(b'\x00\x00\x00\x00' * (len(composition) + 1)) # DELPHI: # l:=4*NP+4;Inc(s,l);Blockwrite(Matfile,ML[0],l,f);Inc(Sum,f); fp.write(b'\x00\x00\x00\x00') # DELPHI: Inc(s,l);Blockwrite(Matfile,rho[0],l,f);Inc(Sum,f); fp.write(struct.pack('f', density_g_cm3)) # DELPHI: # l:=NC+1; # for i:=0 to NP do begin # Inc(s,l);BlockWrite(Matfile,PC[i],l,f);Inc(Sum,f); # end; fp.write(struct.pack('b', len(composition))) fp.write(b'\x00' * len(composition)) # DELPHI: Inc(s,l);BlockWrite(Matfile,PM,l,f);Inc(Sum,f); fp.write(struct.pack('b', len(composition))) for i in range(len(composition)): fp.write(struct.pack('b', i + 1)) return filepath
def _export_geometry_substrate(self, options, geometry, outputdir, *args): material = geometry.body.material composition = sorted(material.composition.items(), key=itemgetter(0)) density_g_cm3 = material.density_kg_m3 / 1000.0 filepath = os.path.join(outputdir, options.name + '.MAT') with open(filepath, 'wb') as fp: # Header # DELPHI: s:=6;Blockwrite(Matfile,Typ,6,f);Inc(Sum,f); # 1st Byte: Type = 2 (homogenous bulk) # 2nd Byte: NC = <nr. of elements> (amount of occurring formulae (compounds or elements)) # 3rd Byte: NZ = <nr. of elements> # 4th Byte: NP = 0 (nr. of layers) # 5th Byte: CU = 2 (1=at%, 2=wt%) # 6th Byte: MU = 1 (not important for bulk; this is the unit for the layer thickness) fp.write(struct.pack('b', 2)) fp.write(struct.pack('b', len(composition))) fp.write(struct.pack('b', len(composition))) fp.write(struct.pack('b', 0)) fp.write(struct.pack('b', 2)) fp.write(struct.pack('b', 1)) # Write length of element and element # DELPHI: # for i:=1 to Nc do begin # l:=1+Length(Comp[i]);Inc(s,l); # Blockwrite(Matfile,Comp[i,0],l,f);Inc(Sum,f); # end; for z, _wf in composition: symbol = ep.symbol(z).upper() fp.write(struct.pack('b', len(symbol)) + symbol.encode('ascii')) # Write molar mass # DELPHI: l:=4*Nc;Inc(s,l);Blockwrite(Matfile,AC[1],l,f);Inc(Sum,f); for z, _wf in composition: mass = ep.atomic_mass_kg_mol(z) * 1000.0 fp.write(struct.pack('f', mass)) # Write atomic number # DELPHI: Inc(s,NZ);Blockwrite(Matfile,Z[1],NZ,f);Inc(Sum,f); for z, _wf in composition: fp.write(struct.pack('b', z)) # Write molar mass # DELPHI: # l:=4*Nc+4; # for i:=0 to NZ do begin # Inc(s,l);BlockWrite(Matfile,GZ[i],l,f);Inc(Sum,f); # end; fp.write(b'\x00\x00\x00\x00') # Skip 4 bytes for z, _wf in composition: mass = ep.atomic_mass_kg_mol(z) * 1000.0 fp.write(struct.pack('f', mass)) for i, item in enumerate(composition): z = item[0] mass = ep.atomic_mass_kg_mol(z) * 1000.0 fp.write(struct.pack('f', mass)) fp.write(b'\x00\x00\x00\x00' * i) # Skip 4 bytes fp.write(struct.pack('f', 1.0 / mass)) fp.write(b'\x00\x00\x00\x00' * (len(composition) - i - 1)) # Skip 4 bytes # DELPHI: Inc(s,l);BlockWrite(Matfile,GM,l,f);Inc(Sum,f); gs = [wf / (ep.atomic_mass_kg_mol(z) * 1000.0) for z, wf in composition] g0 = 1.0 / sum(gs) fp.write(struct.pack('f', g0)) for g in gs: fp.write(struct.pack('f', g)) # DELPHI: # for i:=0 to NP do begin # Inc(s,l);BlockWrite(Matfile,GS[i],l,f);Inc(Sum,f); # end; fp.write(b'\x00\x00\x00\x00' * (len(composition) + 1)) # DELPHI: # l:=4*NP+4;Inc(s,l);Blockwrite(Matfile,ML[0],l,f);Inc(Sum,f); fp.write(b'\x00\x00\x00\x00') # DELPHI: Inc(s,l);Blockwrite(Matfile,rho[0],l,f);Inc(Sum,f); fp.write(struct.pack('f', density_g_cm3)) # DELPHI: # l:=NC+1; # for i:=0 to NP do begin # Inc(s,l);BlockWrite(Matfile,PC[i],l,f);Inc(Sum,f); # end; fp.write(struct.pack('b', len(composition))) fp.write(b'\x00' * len(composition)) # DELPHI: Inc(s,l);BlockWrite(Matfile,PM,l,f);Inc(Sum,f); fp.write(struct.pack('b', len(composition))) for i in range(len(composition)): fp.write(struct.pack('b', i + 1)) return filepath
def __init__(self, z, siegbahn, iupac): self._z = z self._symbol = ep.symbol(z) self._siegbahn = siegbahn self._iupac = iupac
def __init__(self, z, index=None, orbital=None, iupac=None, siegbahn=None): """ Creates an atomic subshell:: s = SubShell(29, 1) # K s = SubShell(29, siegbahn='K') :arg z: atomic number (from 1 to 99 inclusively) :arg index: index of the subshell between 1 (K) and 30 (outer) :arg orbital: orbital of the subshell (e.g. ``1s1/2``) :arg iupac: IUPAC symbol of the subshell :arg siegbahn: Siegbahn symbol of the subshell If more than one argument is given, only the first one is used to create the subshell. """ self._z = z self._symbol = ep.symbol(z) if index is not None: if index < 1 or index > 30: raise ValueError("Id (%s) must be between [1, 30]." % index) elif orbital is not None: try: index = _ORBITALS.index(orbital.lower()) + 1 except ValueError: raise ValueError("Unknown orbital (%s). Possible orbitals: %s" % \ (orbital, _ORBITALS)) elif iupac is not None: try: index = _IUPACS.index(iupac.upper()) + 1 except ValueError: raise ValueError("Unknown IUPAC (%s). Possible IUPAC: %s" % \ (iupac, _IUPACS)) elif siegbahn is not None: try: index = _SIEGBAHNS.index(siegbahn.upper()) + 1 except ValueError: raise ValueError("Unknown Siegbahn (%s). Possible Siegbahn: %s" % \ (siegbahn, _SIEGBAHNS)) else: raise ValueError( "You must specify an index, orbital, IUPAC or Siegbahn") self._index = index self._orbtial = _ORBITALS[index - 1] self._iupac = _IUPACS[index - 1] self._siegbahn = _SIEGBAHNS[index - 1] self._family = self._iupac[0].upper() if index != 30 else None try: self._ionization_energy_eV = subshell_data.energy_eV(z, index) except ValueError: self._ionization_energy_eV = float('inf') self._exists = subshell_data.exists(z, index) try: self._width_eV = subshell_data.width_eV(z, index) except ValueError: self._width_eV = 0.0