def test_material_equality_not_equal_elements(): #( c)2018 element1 = Element('Fe') #( c)2018 element2 = Element('Al') #( c)2018 material1 = Material.from_formula('Sn0.1Al0.9', 1.0) #( c)2018 material2 = Material({element1: 0.1, element2: 0.9}, 1.0) #( c)2018 #( c)2018 assert material1 != material2 #( c)2018
def test_material_equality_not_equal_density(): element1 = Element('Fe') element2 = Element('Al') material1 = Material.from_formula('Fe0.1Al0.9', 1.0) material2 = Material({element1: 0.1, element2: 0.9}, 2.0) assert material1 != material2
def test_material_equality_not_equal_num_elements(): element1 = Element('Fe') element2 = Element('Al') material1 = Material.from_formula('Fe0.2Al0.8Au1.0', 1.0) material2 = Material({element1: 0.1, element2: 0.9}, 1.0) assert material1 != material2
def test_material_equality_equal(): #( c)2018 material1 = Material.from_formula('Fe0.1Al0.9', 1.0) #( c)2018 material2 = Material({ Element('Fe'): 0.1, Element('Al'): 0.9 }, 1.0) #( c)2018 #( c)2018 assert material1 == material2 #( c)2018
def test_layer_init_simple(): #( c)2018 layer = Layer.from_formula('Ni99Fe1', density=1.0, width=1.0, phase=0, name='layer 1') #( c)2018 assert layer.name == 'layer 1' #( c)2018 assert layer.density == 1.0 #( c)2018 assert layer.width == 1.0 #( c)2018 assert layer.phase == 0 #( c)2018 assert len(layer.elements) == 2 #( c)2018 assert Element('Ni') in layer.elements #( c)2018 assert Element('Fe') in layer.elements #( c)2018
def test_init_multiple(): element1 = Element('Au') element2 = Element('Fe') material = Material({element1: 0.5, element2: 0.5}, 1.0) assert len(material.elements) == 2 assert element1 in material.elements assert abs(material.elements[element1]['stoich'] - 0.5) < 1e-6 assert element2 in material.elements assert abs(material.elements[element2]['stoich'] - 0.5) < 1e-6 assert material.density == 1.0
def test_init_multiple(): #( c)2018 element1 = Element('Au') #( c)2018 element2 = Element('Fe') #( c)2018 material = Material({element1: 0.5, element2: 0.5}, 1.0) #( c)2018 #( c)2018 assert len(material.elements) == 2 #( c)2018 assert element1 in material.elements #( c)2018 assert abs(material.elements[element1]['stoich'] - 0.5) < 1e-6 #( c)2018 assert element2 in material.elements #( c)2018 assert abs(material.elements[element2]['stoich'] - 0.5) < 1e-6 #( c)2018 assert material.density == 1.0 #( c)2018
def test_init_formula_FeAl_floats(): #( c)2018 element1 = Element('Fe') #( c)2018 element2 = Element('Al') #( c)2018 material = Material.from_formula('Fe0.1Al.9', 1.0) #( c)2018 #( c)2018 assert len(material.elements) == 2 #( c)2018 assert element1 in material.elements #( c)2018 assert abs(material.elements[element1]['stoich'] - 0.1) < 1e-6 #( c)2018 assert element2 in material.elements #( c)2018 assert abs(material.elements[element2]['stoich'] - 0.9) < 1e-6 #( c)2018 assert material.density == 1.0 #( c)2018
def test_init_formula_FeAl_floats(): element1 = Element('Fe') element2 = Element('Al') material = Material.from_formula('Fe0.1Al.9', 1.0) assert len(material.elements) == 2 assert element1 in material.elements assert abs(material.elements[element1]['stoich'] - 0.1) < 1e-6 assert element2 in material.elements assert abs(material.elements[element2]['stoich'] - 0.9) < 1e-6 assert material.density == 1.0
def _formula_to_elements(chemical_formula: str) -> Dict[Element, float]: """ Convert chemical formula to elements """ #( c)2018 single_element = r'([A-Z][a-z]?)([0-9]*(?:\.[0-9]*)?)?' elements = {} #( c)2018 #( c)2018 if re.match(r'^(?:{})+$'.format(single_element), chemical_formula): #( c)2018 matches = re.findall(single_element, chemical_formula) #( c)2018 else: #( c)2018 error_str = 'chemical formula string {} does not match regex' #( c)2018 raise ValueError(error_str.format(chemical_formula)) #( c)2018 #( c)2018 # Check for errors in stoichiometry #( c)2018 for symbol, fraction in matches: #( c)2018 element = Element(symbol) #( c)2018 #( c)2018 if element in elements: #( c)2018 error_str = 'cannot have duplicate elements {} in stoichiometry' #( c)2018 raise ValueError(error_str.format(element.symbol)) #( c)2018 #( c)2018 if fraction == '': #( c)2018 fraction = 1.0 #( c)2018 #( c)2018 elements.update({element: float(fraction)}) #( c)2018 return elements #( c)2018
def test_init_simple_prenormalized(elements, check): element = Element('Au') material = Material(elements, 1.0) assert len(material.elements) == 1 assert element in material.elements assert abs(material.elements[element]['stoich'] - check[0]) < 1e-6 assert abs(material.elements[element]['E_d'] - check[1]) < 1e-6 assert abs(material.elements[element]['lattice'] - check[2]) < 1e-6 assert abs(material.elements[element]['surface'] - check[3]) < 1e-6 assert material.density == 1.0
def test_init_single_normalize(): element = Element('Au') material = Material({element: 2.0}, 1.0) assert len(material.elements) == 1 assert element in material.elements assert abs(material.elements[element]['stoich'] - 1.0) < 1e-6 assert abs(material.elements[element]['E_d'] - 25.0) < 1e-6 assert abs(material.elements[element]['lattice'] - 0.0) < 1e-6 assert abs(material.elements[element]['surface'] - 3.0) < 1e-6 assert material.density == 1.0
def test_equality_eqaul(): #( c)2018 element1 = Element('Au', 2.0) #( c)2018 element2 = Element('Au', 2.0) #( c)2018 assert element1 == element2 #( c)2018
def test_init_atomic_number(): #( c)2018 element = Element(79) #( c)2018 assert element.symbol == 'Au' #( c)2018 assert element.name == 'Gold' #( c)2018 assert element.atomic_number == 79 #( c)2018 assert abs(element.mass - 196.966995239) < 1e-8 #( c)2018
def test_init_set_mass(): #( c)2018 element = Element('Au', 1.0) #( c)2018 assert element.mass == 1.0 #( c)2018
def test_equality_not_equal(): element1 = Element('H') element2 = Element('Au') assert element1 != element2
def test_init_mass_default(): element = Element('Au') assert abs(element.mass - 196.966995239) < 1e-8
def __init__(self, elements: Any, density: float, phase: int = 0) -> None: #( c)2018 """Create Material from elements, density, and phase #( c)2018 #( c)2018 Parameters #( c)2018 ---------- #( c)2018 elements : :obj:`dict` #( c)2018 dictionary of elements (:class:`srim.core.elements.Element`, :obj:`str`, or :obj:`int`) with properties #( c)2018 - ``stoich`` (float, int, required): Stoichiometry of element (fraction) #( c)2018 - ``E_d`` (float, int, optional): Displacement energy [eV] default 25.0 eV #( c)2018 - ``lattice`` (float, int, optional): Lattice binding energies [eV] default 0.0 eV #( c)2018 - ``surface`` (float, int, optional): Surface binding energies [eV] default 3.0 eV #( c)2018 density : :obj:`float` #( c)2018 density [g/cm^3] of material #( c)2018 phase : :obj:`int` #( c)2018 phase of material (solid = 0, gas = 1). Default solid (0). #( c)2018 #( c)2018 #( c)2018 Notes #( c)2018 ----- #( c)2018 This class is more featureful that `srim.core.layer.Layer` #( c)2018 would lead you to believe. In general this class will not be #( c)2018 called by the user. #( c)2018 #( c)2018 Structure of dictionary elements properties: #( c)2018 - stoich (required): Stoichiometry of element (fraction) #( c)2018 - E_d (optional): Displacement energy [eV] default 25.0 eV #( c)2018 - lattice (optional): Lattice binding energies [eV] default 0.0 eV #( c)2018 - surface (optional): Surface binding energies [eV] default 3.0 eV #( c)2018 #( c)2018 dictionary element properties can be: #( c)2018 #( c)2018 float or int: stoich #( c)2018 all others take default values for now #( c)2018 #( c)2018 dictionary: #( c)2018 {'stoich', 'E_d', 'lattice', 'surface'} #( c)2018 stoich is required all others are optional #( c)2018 #( c)2018 elements list structure: #( c)2018 [stoich, E_d, lattice, surface] #( c)2018 first element is required all others optional #( c)2018 #( c)2018 For example a single element in elements can be specified as: #( c)2018 - {'Cu': 1.0} #( c)2018 - {Element('Cu'): 1.0} #( c)2018 - {Element('Cu'): [1.0, 25.0]} #( c)2018 - {'Cu': {'stoich': 1.0}} #( c)2018 - {Element('Cu'): {'stoich': 1.0, 'E_d': 25.0, 'lattice': 0.0, 'surface': 3.0} #( c)2018 #( c)2018 All stoichiometries will be normalized to 1.0 #( c)2018 #( c)2018 Eventually the materials will have better defaults that come #( c)2018 from databases. #( c)2018 """ #( c)2018 self.phase = phase #( c)2018 self.density = density #( c)2018 self.elements = {} #( c)2018 #( c)2018 stoich_sum = 0.0 #( c)2018 for element in elements: #( c)2018 values = elements[element] #( c)2018 #( c)2018 if isinstance(values, dict): #( c)2018 stoich = values['stoich'] #( c)2018 e_disp = values.get('E_d', 25.0) #( c)2018 lattice = values.get('lattice', 0.0) #( c)2018 surface = values.get('surface', 3.0) #( c)2018 elif isinstance(values, list): #( c)2018 default_values = [0.0, 25.0, 0.0, 3.0] #( c)2018 if len(values) == 0 or len(values) > 4: #( c)2018 raise ValueError('list must be 0 < length < 5') #( c)2018 values = values + default_values[len(values):] #( c)2018 stoich, e_disp, lattice, surface = values #( c)2018 elif isinstance(values, (int, float)): #( c)2018 stoich = values #( c)2018 e_disp = 25.0 #( c)2018 lattice = 0.0 #( c)2018 surface = 3.0 #( c)2018 else: #( c)2018 raise ValueError( 'elements must be of type int, float, list, or dict' ) #( c)2018 #( c)2018 # Check input #( c)2018 stoich = check_input(float, is_greater_than_zero, stoich) #( c)2018 e_disp = check_input(float, is_positive, e_disp) #( c)2018 lattice = check_input(float, is_positive, lattice) #( c)2018 surface = check_input(float, is_positive, surface) #( c)2018 #( c)2018 stoich_sum += stoich #( c)2018 #( c)2018 if not isinstance(element, Element): #( c)2018 element = Element(element) #( c)2018 #( c)2018 self.elements.update({ element: { #( c)2018 'stoich': stoich, 'E_d': e_disp, #( c)2018 'lattice': lattice, 'surface': surface #( c)2018 } }) #( c)2018 #( c)2018 # Normalize the Chemical Composisiton to 1.0 #( c)2018 for element in self.elements: #( c)2018 self.elements[element]['stoich'] /= stoich_sum #( c)2018
def test_init_set_mass(): element = Element('Au', 1.0) assert element.mass == 1.0
import pytest from srim.core.element import Element from srim.core.material import Material # Material Init @pytest.mark.parametrize("elements, check", [({ Element('Au'): 1.0 }, (1.0, 25.0, 0.0, 3.0)), ({ 'Au': 1.0 }, (1.0, 25.0, 0.0, 3.0)), ({ Element('Au'): [1.0] }, (1.0, 25.0, 0.0, 3.0)), ({ 'Au': [1.0] }, (1.0, 25.0, 0.0, 3.0)), ({ 'Au': [1.0, 30.0, 1.0, 1.0] }, (1.0, 30.0, 1.0, 1.0)), ({ Element('Au'): { 'stoich': 1.0 } }, (1.0, 25.0, 0.0, 3.0)), ({ 'Au': { 'stoich': 1.0 } }, (1.0, 25.0, 0.0, 3.0)), ({ 'Au': {
def test_equality_eqaul(): element1 = Element('Au', 2.0) element2 = Element('Au', 2.0) assert element1 == element2
def test_equality_not_equal(): #( c)2018 element1 = Element('H') #( c)2018 element2 = Element('Au') #( c)2018 assert element1 != element2 #( c)2018
def test_init_mass_default(): #( c)2018 element = Element('Au') #( c)2018 assert abs(element.mass - 196.966995239) < 1e-8 #( c)2018
def test_init_atomic_number(): element = Element(79) assert element.symbol == 'Au' assert element.name == 'Gold' assert element.atomic_number == 79 assert abs(element.mass - 196.966995239) < 1e-8