def test_set_abc(self): a = 4.3 b = 3.2 c = 8.1 alpha = 110 origin = [3.1, 1.4, 4.1] box = am.Box(a=a, b=b, c=c, alpha=alpha, origin=origin) assert np.isclose(box.a, a) assert np.isclose(box.b, b) assert np.isclose(box.c, c) assert np.isclose(box.alpha, alpha) assert np.isclose(box.beta , 90.0) assert np.isclose(box.gamma, 90.0) assert np.allclose(box.origin, origin) a = 24.5 b = 236.2 c = 42.5 beta = 101 box = am.Box(a=a, b=b, c=c, beta=beta) assert np.isclose(box.a, a) assert np.isclose(box.b, b) assert np.isclose(box.c, c) assert np.isclose(box.alpha, 90.0) assert np.isclose(box.beta , beta) assert np.isclose(box.gamma, 90.0) assert np.allclose(box.origin, np.zeros(3))
def test_set_hi_los(self): xlo = -1 xhi = 5 ylo = -2.1 yhi = 5 zlo = 0.1 zhi = 3.1 xy = 0.5 box = am.Box(xlo=xlo, xhi=xhi, ylo=ylo, yhi=yhi, zlo=zlo, zhi=zhi, xy=xy) assert np.isclose(box.xlo, xlo) assert np.isclose(box.xhi, xhi) assert np.isclose(box.ylo, ylo) assert np.isclose(box.yhi, yhi) assert np.isclose(box.zlo, zlo) assert np.isclose(box.zhi, zhi) assert np.isclose(box.xz, 0.0) assert np.isclose(box.xy, xy) assert np.isclose(box.yz, 0.0) xlo = -143 xhi = 125 ylo = -124 yhi = 364 zlo = -172 zhi = 235 yz = 10 box = am.Box(xlo=xlo, xhi=xhi, ylo=ylo, yhi=yhi, zlo=zlo, zhi=zhi, yz=yz) assert np.isclose(box.xlo, xlo) assert np.isclose(box.xhi, xhi) assert np.isclose(box.ylo, ylo) assert np.isclose(box.yhi, yhi) assert np.isclose(box.zlo, zlo) assert np.isclose(box.zhi, zhi) assert np.isclose(box.xz, 0.0) assert np.isclose(box.xy, 0.0) assert np.isclose(box.yz, yz)
def test_default(self): box = am.Box() assert np.allclose(box.avect, [1., 0., 0.]) assert np.allclose(box.bvect, [0., 1., 0.]) assert np.allclose(box.cvect, [0., 0., 1.]) assert np.allclose(box.origin, [0., 0., 0.]) assert np.allclose(box.vects, [[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) assert np.isclose(box.a, 1.0) assert np.isclose(box.b, 1.0) assert np.isclose(box.c, 1.0) assert np.isclose(box.alpha, 90.0) assert np.isclose(box.beta , 90.0) assert np.isclose(box.gamma, 90.0) assert np.isclose(box.xlo, 0.0) assert np.isclose(box.xhi, 1.0) assert np.isclose(box.ylo, 0.0) assert np.isclose(box.yhi, 1.0) assert np.isclose(box.zlo, 0.0) assert np.isclose(box.zhi, 1.0) assert np.isclose(box.lx, 1.0) assert np.isclose(box.ly, 1.0) assert np.isclose(box.lz, 1.0) assert np.isclose(box.xy, 0.0) assert np.isclose(box.xz, 0.0) assert np.isclose(box.yz, 0.0) assert np.isclose(box.volume, 1.0)
def test_set_lengths(self): lx=42 ly=57 lz=112 xz=15 origin=[1,2,3] box = am.Box(lx=lx, ly=ly, lz=lz, xz=xz, origin=origin) assert np.isclose(box.lx, lx) assert np.isclose(box.ly, ly) assert np.isclose(box.lz, lz) assert np.isclose(box.xz, xz) assert np.isclose(box.xy, 0.0) assert np.isclose(box.yz, 0.0) assert np.allclose(box.origin, origin) lx=163 ly=347 lz=235 xy=19 box.set_lengths(lx=lx, ly=ly, lz=lz, xy=xy) assert np.isclose(box.lx, lx) assert np.isclose(box.ly, ly) assert np.isclose(box.lz, lz) assert np.isclose(box.xz, 0.0) assert np.isclose(box.xy, xy) assert np.isclose(box.yz, 0.0) assert np.allclose(box.origin, np.zeros(3))
def test_dmag_and_dvect(): pos_0 = np.random.uniform(1.0, 10.0, size=(200, 3)) pos_0[10] = [12.1234, 12.1234, 12.1234] pos_0[11] = [7.124, 132.15, 12.235] pos_1 = np.random.uniform(1.0, 10.0, size=(200, 3)) pos_1[10] = [12.1234, 12.1234, 12.1234] pos_1[11] = [18.124, 1.15, 1.235] box = am.Box(vects=[[20.0, 0.0, 0.0], [0.0, 135.0, 0.0], [0.0, 0.0, 20.0]]) # Test for all periodic boundaries pbc = [True, True, True] dvect = am.dvect(pos_0, pos_1, box, pbc) dmag = am.dmag(pos_0, pos_1, box, pbc) assert np.allclose(np.linalg.norm(dvect, axis=1), dmag) assert np.allclose(dvect[10], [0.0, 0.0, 0.0]) assert np.allclose(dvect[11], [-9., 4., 9.]) assert np.isclose(dmag[10], 0.0) assert np.isclose(dmag[11], 13.341664064126334) # Test for all nono-periodic boundaries pbc = [False, False, False] dvect = am.dvect(pos_0, pos_1, box, pbc) dmag = am.dmag(pos_0, pos_1, box, pbc) assert np.allclose(np.linalg.norm(dvect, axis=1), dmag) assert np.allclose(dvect[10], [0.0, 0.0, 0.0]) assert np.allclose(dvect[11], [11., -131., -11.]) assert np.isclose(dmag[10], 0.0) assert np.isclose(dmag[11], 131.92043056327552)
def test_vectortocartesian(): # Test 3 indices box = am.Box(a=3, b=4, c=5, alpha=90, beta=90, gamma=90) assert np.allclose(am.tools.miller.vectortocartesian([1, 2, 3], box), np.array([3, 8, 15])) box = am.Box(a=3, b=4, c=5, alpha=90, beta=90, gamma=80) assert np.allclose(am.tools.miller.vectortocartesian([1, 1, 1], box), np.array([[3.69459271, 3.93923101, 5.]])) # Test 4 indices box = am.Box(a=3, b=3, c=5, alpha=90, beta=90, gamma=120) assert np.allclose(am.tools.miller.vectortocartesian([-2, 1, 1, 1], box), np.array([-9, 0, 5])) box = am.Box(a=3, b=4, c=5, alpha=90, beta=90, gamma=120) with pytest.raises(AssertionError): am.tools.miller.vectortocartesian([-2, 1, 1, 1], box)
def test_vector_crystal_to_cartesian(): # Test 3 indices box = am.Box(a=3, b=4, c=5, alpha=90, beta=90, gamma=90) assert np.allclose(vector_crystal_to_cartesian([1,2,3], box), np.array([ 3, 8, 15])) box = am.Box(a=3, b=4, c=5, alpha=90, beta=90, gamma=80) assert np.allclose(vector_crystal_to_cartesian([1,1,1], box), np.array([[3.69459271, 3.93923101, 5. ]])) # Test 4 indices box = am.Box(a=3, b=3, c=5, alpha=90, beta=90, gamma=120) assert np.allclose(vector_crystal_to_cartesian([-2, 1, 1, 1], box), np.array([-9, 0, 5])) box = am.Box(a=3, b=4, c=5, alpha=90, beta=90, gamma=120) with pytest.raises(ValueError): vector_crystal_to_cartesian([-2, 1, 1, 1], box)
def test_is_lammps_norm(self): vects = np.array([[123, 0, 0], [4, 142, 0], [7, -9, 145]]) box = am.Box(vects=vects) assert box.is_lammps_norm() vects = np.array([[123, 1, 0], [4, 142, 0], [7, -9, 145]]) box = am.Box(vects=vects) assert not box.is_lammps_norm() vects = np.array([[123, 0, 1], [4, 142, 0], [7, -9, 145]]) box = am.Box(vects=vects) assert not box.is_lammps_norm() vects = np.array([[123, 0, 0], [4, 142, 1], [7, -9, 145]]) box = am.Box(vects=vects) assert not box.is_lammps_norm() vects = np.array([[-123, 0, 0], [4, 142, 0], [7, -9, 145]]) box = am.Box(vects=vects) assert not box.is_lammps_norm() vects = np.array([[123, 0, 0], [4, -142, 0], [7, -9, 145]]) box = am.Box(vects=vects) assert not box.is_lammps_norm() vects = np.array([[123, 0, 0], [4, 142, 0], [7, -9, -145]]) box = am.Box(vects=vects) assert not box.is_lammps_norm()
def fcc_edge(self): axes = np.array([[1, 0, -1], [1, 1, 1], [1, -2, 1]]) alat = uc.set_in_units(4.0248, 'angstrom') C11 = uc.set_in_units(113.76, 'GPa') C12 = uc.set_in_units(61.71, 'GPa') C44 = uc.set_in_units(31.25, 'GPa') c = am.ElasticConstants(C11=C11, C12=C12, C44=C44) burgers = alat / 2 * np.array([1., 0., -1.]) # initializing a new Stroh object using the data stroh = am.defect.Stroh(c, burgers, axes=axes) pos_test = uc.set_in_units(np.array([12.4, 13.5, -10.6]), 'angstrom') disp = stroh.displacement(pos_test) print("displacement =", uc.get_in_units(disp, 'angstrom'), 'angstrom') # monopole system box = am.Box(a=alat, b=alat, c=alat) atoms = am.Atoms(natoms=4, prop={ 'atype': 1, 'pos': [[0.0, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5]] }) ucell = am.System(atoms=atoms, box=box, scale=True) system = am.rotate_cubic(ucell, axes) shift = np.array( [0.12500000000000, 0.50000000000000, 0.00000000000000]) new_pos = system.atoms_prop(key='pos', scale=True) + shift system.atoms_prop(key='pos', value=new_pos, scale=True) system.supersize((-7, 7), (-6, 6), (0, 1)) disp = stroh.displacement(system.atoms_prop(key='pos')) system.atoms_prop(key='pos', value=system.atoms_prop(key='pos') + disp) system.pbc = (False, False, True) system.wrap() pos = system.atoms_prop(key='pos') x = uc.get_in_units(pos[:, 0], 'angstrom') y = uc.get_in_units(pos[:, 1], 'angstrom') plt.figure(figsize=(8, 8)) plt.scatter(x, y, s=30) plt.xlim(min(x), max(x)) plt.ylim(min(y), max(y)) plt.xlabel('x-position (Angstrom)', fontsize='large') plt.ylabel('y-position (Angstrom)', fontsize='large') plt.show()
def test_model(self): box = am.Box.cubic(5.42) model = box.model() assert np.allclose(uc.value_unit(model['box']['avect']), np.array([5.42, 0.0, 0.0])) assert np.allclose(uc.value_unit(model['box']['bvect']), np.array([0.0, 5.42, 0.0])) assert np.allclose(uc.value_unit(model['box']['cvect']), np.array([0.0, 0.0, 5.42])) assert np.allclose(uc.value_unit(model['box']['origin']), np.array([0.0, 0.0, 0.0])) box = am.Box(model=model) assert np.allclose(box.vects, np.array([[5.42, 0.0, 0.0], [0.0, 5.42, 0.0], [0.0, 0.0, 5.42]]))
def load_model(self, model, name=None): """ Loads record contents from a given model. Parameters ---------- model : str or DataModelDict The model contents of the record to load. name : str, optional The name to assign to the record. Often inferred from other attributes if not given. """ # Load universal and subset content super().load_model(model, name=name) calc = self.model[self.modelroot] # Load calculation-specific content run_params = calc['calculation']['run-parameter'] self.strainrange = run_params['strain-range'] # Load phase-state info self.pressure_xx = uc.value_unit(calc['phase-state']['pressure-xx']) self.pressure_yy = uc.value_unit(calc['phase-state']['pressure-yy']) self.pressure_zz = uc.value_unit(calc['phase-state']['pressure-zz']) # Load results if self.status == 'finished': self.__initial_dump = { 'filename': calc['initial-system']['artifact']['file'], 'symbols': calc['initial-system']['symbols'] } self.__final_dump = { 'filename': calc['final-system']['artifact']['file'], 'symbols': calc['final-system']['symbols'] } lx = uc.value_unit(calc['measured-box-parameter']['lx']) ly = uc.value_unit(calc['measured-box-parameter']['ly']) lz = uc.value_unit(calc['measured-box-parameter']['lz']) xy = uc.value_unit(calc['measured-box-parameter']['xy']) xz = uc.value_unit(calc['measured-box-parameter']['xz']) yz = uc.value_unit(calc['measured-box-parameter']['yz']) self.__final_box = am.Box(lx=lx, ly=ly, lz=lz, xy=xy, xz=xz, yz=yz) self.__potential_energy = uc.value_unit(calc['cohesive-energy']) mps = calc['measured-phase-state'] self.__measured_pressure_xx = uc.value_unit(mps['pressure-xx']) self.__measured_pressure_yy = uc.value_unit(mps['pressure-yy']) self.__measured_pressure_zz = uc.value_unit(mps['pressure-zz']) self.__measured_pressure_xy = uc.value_unit(mps['pressure-xy']) self.__measured_pressure_xz = uc.value_unit(mps['pressure-xz']) self.__measured_pressure_yz = uc.value_unit(mps['pressure-yz'])
def load(poscar): """ Reads a poscar-style coordination file for a system. Returns an atomman.System, and a list of elements if the file gives them. """ #Read in all lines of the file with uber_open_rmode(poscar) as f: lines = f.read().split('\n') #Interpret box information box_scale = float(lines[1]) avect = np.array(lines[2].split(), dtype='float64') * box_scale bvect = np.array(lines[3].split(), dtype='float64') * box_scale cvect = np.array(lines[4].split(), dtype='float64') * box_scale box = am.Box(avect=avect, bvect=bvect, cvect=cvect) #Read in elements, number of types, and style info try: typenums = np.array(lines[5].split(), dtype='int32') elements = [None for n in xrange(len(typenums))] style = lines[6] start_i = 7 except: elements = lines[5].split() typenums = np.array(lines[6].split(), dtype='int32') style = lines[7] start_i = 8 #Build atype list atype = np.array([], dtype='int32') for i in xrange(len(typenums)): atype = np.hstack((atype, np.full(typenums[i], i + 1, dtype='int32'))) #Check which coordinate style to use if style[0] in 'cCkK': scale = False else: scale = True #Read in positions natoms = np.sum(typenums) pos = np.empty((natoms, 3), dtype='float64') count = 0 for i in xrange(start_i, len(lines)): terms = lines[i].split() if len(terms) > 0: pos[count, :] = np.array(terms, dtype='float64') count += 1 atoms = am.Atoms(natoms=natoms, prop={'atype': atype, 'pos': pos}) system = am.System(atoms=atoms, box=box, scale=scale) return system, elements
def load(ase_atoms): """Convert an ase.Atoms into an atomman.System and list of elements.""" assert has_ase, 'ase not imported' box = am.Box(vects=ase_atoms.get_cell()) atoms = am.Atoms(natoms=len(ase_atoms)) atoms.prop(key='pos', value=ase_atoms.get_positions()) all_elements = np.array(ase_atoms.get_chemical_symbols()) elements, atype = np.unique(all_elements, return_inverse=True) atype += 1 atoms.prop(key='atype', value=atype) return am.System(atoms=atoms, box=box), elements
def test_atomic_no_imageflags(self): box = am.Box(vects=[[1.25694013, 0. , 0. ], [1.17551244, 4.01690452, 0. ], [0.23122344, 0.0768582 , 0.76391945]]) pos = [[0.53342537, 0.70899278, 0.21800393], [0.8766086 , 0.98893671, 0.57889022], [0.78898178, 0.44740662, 0.49997271], [0.78302097, 0.06197394, 0.77049739]] atoms = am.Atoms(pos=pos, atype=1) symbols = 'Al' pbc = (True, True, True) system = am.System(atoms=atoms, box=box, scale=True, symbols=symbols, pbc=pbc) self.load_dump(system, atom_style='atomic', units='metal')
def load(cif): """Reads in a CIF crystal file and returns an atomman.System and list of elements.""" assert has_diffpy, 'diffpy.Structure not imported' dps = diffpy.Structure.structure.Structure() #load from an open file-like object if hasattr(cif, 'read'): dps.readStr(cif.read()) #load using a file name elif os.path.isfile(cif): dps.read(cif) #load from a string else: dps.readStr(cif) all_elements = dps.element elements, all_atype = np.unique(all_elements, return_inverse=True) all_atype += 1 all_pos = dps.xyz atype = [] pos = [] for a1, p1 in zip(all_atype, all_pos): noMatch = True for a2, p2 in zip(atype, pos): if a1 == a2 and np.allclose(p1, p2): noMatch = False break if noMatch: atype.append(a1) pos.append(p1) atoms = am.Atoms(natoms=len(pos), prop={'atype':atype, 'pos':pos}) box = am.Box(a=dps.lattice.a, b=dps.lattice.b, c=dps.lattice.c, alpha=dps.lattice.alpha, beta=dps.lattice.beta, gamma=dps.lattice.gamma) return am.System(atoms=atoms, box=box, pbc=(True,True,True), scale=True), list(elements)
def test_set_vectors(self): avect = [3.2, 0.0, 0.0] bvect = [0.1, 3.2, 0.0] cvect = [-0.2, 0.15, 3.2] origin = [3.1, 1.4, 4.1] box = am.Box(avect=avect, bvect=bvect, cvect=cvect, origin=origin) assert np.allclose(box.avect, avect) assert np.allclose(box.bvect, bvect) assert np.allclose(box.cvect, cvect) assert np.allclose(box.origin, origin) avect = [6.2, 0.0, 0.0] bvect = [0.0, 4.2, 0.0] cvect = [0.0, 0.1, 5.2] box.set_vectors(avect=avect, bvect=bvect, cvect=cvect) assert np.allclose(box.avect, avect) assert np.allclose(box.bvect, bvect) assert np.allclose(box.cvect, cvect) assert np.allclose(box.origin, np.zeros(3))
def process_results(self, results_dict): """ Processes calculation results and saves them to the object's results attributes. Parameters ---------- results_dict: dict The dictionary returned by the calc() method. """ self.__initial_dump = { 'filename': results_dict['dumpfile_initial'], 'symbols': results_dict['symbols_initial'] } self.__final_dump = { 'filename': results_dict['dumpfile_final'], 'symbols': results_dict['symbols_final'] } lx = results_dict['lx'] / (self.system_mods.a_mults[1] - self.system_mods.a_mults[0]) ly = results_dict['ly'] / (self.system_mods.b_mults[1] - self.system_mods.b_mults[0]) lz = results_dict['lz'] / (self.system_mods.c_mults[1] - self.system_mods.c_mults[0]) xy = results_dict['xy'] / (self.system_mods.b_mults[1] - self.system_mods.b_mults[0]) xz = results_dict['xz'] / (self.system_mods.c_mults[1] - self.system_mods.c_mults[0]) yz = results_dict['yz'] / (self.system_mods.c_mults[1] - self.system_mods.c_mults[0]) self.__final_box = am.Box(lx=lx, ly=ly, lz=lz, xy=xy, xz=xz, yz=yz) self.__potential_energy = results_dict['E_pot'] self.__measured_pressure_xx = results_dict['measured_pxx'] self.__measured_pressure_yy = results_dict['measured_pyy'] self.__measured_pressure_zz = results_dict['measured_pzz'] self.__measured_pressure_xy = results_dict['measured_pxy'] self.__measured_pressure_xz = results_dict['measured_pxz'] self.__measured_pressure_yz = results_dict['measured_pyz']
def ucell(self, a_scale, c_scale): """ Generates a bct unit cell for intermediate structures based on the given bcc and fcc lattice constants. For the scaling parameters, values of a_scale = c_scale = 0 corresponds to the given fcc lattice, and values of a_scale = c_scale = 1 corresponds to the given bcc lattice. Parameters ---------- a_scale : float Scaling parameter for the bct structure's a lattice parameter. c_scale : float Scaling parameter for the bct structure's c lattice parameter. Returns ------- ucell : atomman.System The corresponding bct unit cell. """ # Set the ideal constants based on a_fcc and a_bcc a_0 = self.a_fcc * 2**0.5 / 2 c_0 = self.a_fcc a_1 = c_1 = self.a_bcc # Compute the bct lattice constants using the scale parameters a = a_0 * (1 - a_scale) + a_1 * a_scale c = c_0 * (1 - c_scale) + c_1 * c_scale # Generate box, atoms and system for the bct unit cell box = am.Box().tetragonal(a=a, c=c) atoms = am.Atoms(pos=[[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]]) ucell = am.System(atoms=atoms, box=box, symbols=self.symbol, scale=True) return ucell
def boxhexagonal(self): return am.Box(a=3, b=3, c=8, alpha=90, beta=90, gamma=120)
def calc_cij(lammps_command, system, potential, symbols, p_xx=0.0, p_yy=0.0, p_zz=0.0, delta=1e-5, cycle=0): """Runs cij_script and returns current Cij, stress, Ecoh, and new system guess.""" #Get lammps units lammps_units = lmp.style.unit(potential.units) #Define lammps variables lammps_variables = {} lammps_variables['atomman_system_info'] = lmp.sys_gen( units=potential.units, atom_style=potential.atom_style, ucell=system, size=np.array([[0, 3], [0, 3], [0, 3]])) lammps_variables['atomman_pair_info'] = potential.pair_info(symbols) lammps_variables['delta'] = delta lammps_variables['steps'] = 2 #Write lammps input script template_file = 'cij.template' lammps_script = 'cij.in' with open(template_file) as f: template = f.read() with open(lammps_script, 'w') as f: f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) #Run lammps output = lmp.run(lammps_command, lammps_script) shutil.move('log.lammps', 'cij-' + str(cycle) + '-log.lammps') #Extract LAMMPS thermo data. Each term ranges i=0-12 where i=0 is undeformed #The remaining values are for -/+ strain pairs in the six unique directions lx = uc.set_in_units(np.array(output.finds('Lx')), lammps_units['length']) ly = uc.set_in_units(np.array(output.finds('Ly')), lammps_units['length']) lz = uc.set_in_units(np.array(output.finds('Lz')), lammps_units['length']) xy = uc.set_in_units(np.array(output.finds('Xy')), lammps_units['length']) xz = uc.set_in_units(np.array(output.finds('Xz')), lammps_units['length']) yz = uc.set_in_units(np.array(output.finds('Yz')), lammps_units['length']) pxx = uc.set_in_units(np.array(output.finds('Pxx')), lammps_units['pressure']) pyy = uc.set_in_units(np.array(output.finds('Pyy')), lammps_units['pressure']) pzz = uc.set_in_units(np.array(output.finds('Pzz')), lammps_units['pressure']) pxy = uc.set_in_units(np.array(output.finds('Pxy')), lammps_units['pressure']) pxz = uc.set_in_units(np.array(output.finds('Pxz')), lammps_units['pressure']) pyz = uc.set_in_units(np.array(output.finds('Pyz')), lammps_units['pressure']) try: pe = uc.set_in_units(np.array(output.finds('v_peatom')), lammps_units['energy']) assert len(pe) > 0 except: pe = uc.set_in_units(np.array(output.finds('peatom')), lammps_units['energy']) #Set the six non-zero strain values strains = np.array([(lx[2] - lx[1]) / lx[0], (ly[4] - ly[3]) / ly[0], (lz[6] - lz[5]) / lz[0], (yz[8] - yz[7]) / lz[0], (xz[10] - xz[9]) / lz[0], (xy[12] - xy[11]) / ly[0]]) #calculate cij using stress changes associated with each non-zero strain cij = np.empty((6, 6)) for i in xrange(6): delta_stress = np.array([ pxx[2 * i + 1] - pxx[2 * i + 2], pyy[2 * i + 1] - pyy[2 * i + 2], pzz[2 * i + 1] - pzz[2 * i + 2], pyz[2 * i + 1] - pyz[2 * i + 2], pxz[2 * i + 1] - pxz[2 * i + 2], pxy[2 * i + 1] - pxy[2 * i + 2] ]) cij[i] = delta_stress / strains[i] for i in xrange(6): for j in xrange(i): cij[i, j] = cij[j, i] = (cij[i, j] + cij[j, i]) / 2 C = am.ElasticConstants(Cij=cij) if np.allclose(C.Cij, 0.0): raise RuntimeError('Divergence of elastic constants to <= 0') try: S = C.Sij except: raise RuntimeError('singular C:\n' + str(C.Cij)) #extract the current stress state stress = -1 * np.array([[pxx[0], pxy[0], pxz[0]], [pxy[0], pyy[0], pyz[0]], [pxz[0], pyz[0], pzz[0]]]) s_xx = stress[0, 0] + p_xx s_yy = stress[1, 1] + p_yy s_zz = stress[2, 2] + p_zz new_a = system.box.a / (S[0, 0] * s_xx + S[0, 1] * s_yy + S[0, 2] * s_zz + 1) new_b = system.box.b / (S[1, 0] * s_xx + S[1, 1] * s_yy + S[1, 2] * s_zz + 1) new_c = system.box.c / (S[2, 0] * s_xx + S[2, 1] * s_yy + S[2, 2] * s_zz + 1) if new_a <= 0 or new_b <= 0 or new_c <= 0: raise RuntimeError('Divergence of box dimensions to <= 0') newbox = am.Box(a=new_a, b=new_b, c=new_c) system_new = deepcopy(system) system_new.box_set(vects=newbox.vects, scale=True) return {'C': C, 'stress': stress, 'ecoh': pe[0], 'system_new': system_new}
def rotate_cubic(system, axes): """ Rotate a cubic system according to the specified crystallographic axes. Returns an orthogonal system whose box lengths are: a * sqrt(i^2+j^2+k^2) where a is the original cubic box length, and ijk are the crystallographic indicies for the specific direction. """ # rotate system generically system = rotate(system, axes) # test for cubic a = system.box.a try: assert np.isclose(a, system.box.b), str(a) + ' ' + str(system.box.b) assert np.isclose(a, system.box.c), str(a) + ' ' + str(system.box.c) assert np.isclose(90.0, system.box.alpha), str(system.box.alpha) assert np.isclose(90.0, system.box.beta), str(system.box.beta) assert np.isclose(90.0, system.box.gamma), str(system.box.gamma) except: raise ValueError('Cubic system not given') # Test for integer axes values try: for ax_val in axes.flat: assert np.isclose(ax_val, int(ax_val)) except: raise ValueError('axes values must be integers') # Get magnitudes of the axes mag = np.linalg.norm(axes, axis=1) # compute number of atoms for the new system natoms = system.natoms * mag[0] * mag[1] * mag[2] if np.isclose(int(round(natoms)), natoms): natoms = int(round(natoms)) else: raise ValueError( 'not an integer number of atoms associated with the axes.') # create a new box with scaled lattice parameters box = am.Box(a=a * mag[0], b=a * mag[1], c=a * mag[2], origin=system.box.origin) # supersize the rotated box m = int(ceil(max(mag))) system = am.tools.supersize(system, (-m, m), (-m, m), (-m, m)) # filter atoms for only those in the new box data = system.atoms.data # round x-positions near xlo, xhi and only keep data for atoms where xlo # <= x < xhi data[np.where(np.isclose(data.T[1], box.xlo, atol=1e-8, rtol=0)), 1] = box.xlo data = data[data.T[1] >= box.xlo] data[np.where(np.isclose(data.T[1], box.xhi, atol=1e-8, rtol=0)), 1] = box.xhi data = data[data.T[1] < box.xhi] # round y-positions near ylo, yhi and only keep data for atoms where ylo # <= y < yhi data[np.where(np.isclose(data.T[2], box.ylo, atol=1e-8, rtol=0)), 2] = box.ylo data = data[data.T[2] >= box.ylo] data[np.where(np.isclose(data.T[2], box.yhi, atol=1e-8, rtol=0)), 2] = box.yhi data = data[data.T[2] < box.yhi] # round z-positions near zlo, zhi and only keep data for atoms where zlo # <= z < zhi data[np.where(np.isclose(data.T[3], box.zlo, atol=1e-8, rtol=0)), 3] = box.zlo data = data[data.T[3] >= box.zlo] data[np.where(np.isclose(data.T[3], box.zhi, atol=1e-8, rtol=0)), 3] = box.zhi data = data[data.T[3] < box.zhi] # deepcopy the data array to guarantee that it is new and separate data = deepcopy(data) # rebuild views start = 0 view = OrderedDict() for k in system.atoms.view: vshape = (len(data), ) + system.atoms.view[k].shape[1:] view[k] = data[:, start:start + system.atoms.view[k][0].size] view[k].shape = vshape start = start + system.atoms.view[k][0].size # create atoms from natoms, data, view and dtype atoms = am.Atoms(natoms=natoms, data=data, view=view, prop_dtype=system.atoms.dtype) # return new system return am.System(box=box, atoms=atoms)
def boxcubic(self): return am.Box(a=3, b=3, c=3, alpha=90, beta=90, gamma=90)
def quick_a_Cij(lammps_command, system, potential, symbols, mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0, delta=1e-5, tol=1e-10, diverge_scale=3.): """ Quickly refines static orthorhombic system by evaluating the elastic constants and the virial pressure. Arguments: lammps_command -- directory location for lammps executable system -- atomman.System to statically deform and evaluate a,b,c and Cij at a given pressure potential -- atomman.lammps.Potential representation of a LAMMPS implemented potential symbols -- list of element-model symbols for the Potential that correspond to the System's atypes Keyword Arguments: p_xx, p_yy, p_zz -- tensile pressures to equilibriate to. Default is 0.0 for all. delta -- the strain range to use in calculating the elastic constants. Default is 1e-5. tol -- the relative tolerance criterion for identifying box size convergence. Default is 1e-10. diverge_scale -- identifies a divergent system if x / diverge_scale < x < x * diverge_scale is not True for x = a,b,c. """ #initial parameter setup converged = False #flag for if values have converged #define boxes for iterating system_current = deepcopy( system) #system with box parameters being evaluated system_old = None #system with previous box parameters evaluated for cycle in xrange(100): #Run LAMMPS and evaluate results based on system_old results = calc_cij(lammps_command, system_current, potential, symbols, p_xx, p_yy, p_zz, delta, cycle) system_new = results['system_new'] #Test if box has converged to a single size if np.allclose(system_new.box.vects, system_current.box.vects, rtol=tol, atol=0): converged = True break #Test if box has converged to two sizes elif system_old is not None and np.allclose( system_new.box.vects, system_old.box.vects, rtol=tol, atol=0): #Run LAMMPS Cij script using average between alat0 and alat1 box = am.Box(a=(system_new.box.a + system_old.box.a) / 2., b=(system_new.box.b + system_old.box.b) / 2., c=(system_new.box.c + system_old.box.c) / 2.) system_current.box_set(vects=box.vects, scale=True) results = calc_cij(lammps_command, system_current, potential, symbols, p_xx, p_yy, p_zz, delta, cycle + 1) converged = True break #Test if values have diverged from initial guess elif system_new.box.a < system.box.a / diverge_scale or system_new.box.a > system.box.a * diverge_scale: raise RuntimeError('Divergence of box dimensions') elif system_new.box.b < system.box.b / diverge_scale or system_new.box.b > system.box.b * diverge_scale: raise RuntimeError('Divergence of box dimensions') elif system_new.box.c < system.box.c / diverge_scale or system_new.box.c > system.box.c * diverge_scale: raise RuntimeError('Divergence of box dimensions') elif results['ecoh'] == 0.0: raise RuntimeError('Divergence: cohesive energy is 0') #if not converged or diverged, update system_old and system_current else: system_old, system_current = system_current, system_new #Return values if converged if converged: return results else: raise RuntimeError('Failed to converge after 100 cycles')
def supersize(system, a_size, b_size, c_size): """ Builds a large system based on a seed system and multipliers. Keyword Arguments: system -- atomman.System to use as the seed. a_size -- int or tuple of 2 ints for multiplying along the avect direction. b_size -- int or tuple of 2 ints for multiplying along the bvect direction. c_size -- int or tuple of 2 ints for multiplying along the cvect direction. The multiplier values *_size are taken to be integer tuples (m, n) where m <= 0 and n >= 0. The system multiplication works such that if n = -m, then the seed system's origin will be at the center of the new system. If only one integer is given, then it is assigned to m or n depending on its sign, and the other value is taken to be 0. """ #initial parameter setup sizes = [a_size, b_size, c_size] mults = np.array([0, 0, 0], dtype=int) vects = system.box.vects origin = system.box.origin spos = system.atoms_prop(key='pos', scale=True) for i in xrange(3): #check values in sizes if isinstance(sizes[i], (int, long)): if sizes[i] > 0: sizes[i] = (0, sizes[i]) elif sizes[i] < 0: sizes[i] = (sizes[i], 0) elif isinstance(sizes[i], tuple): assert len(sizes[i]) == 2, 'Invalid system multipliers' assert isinstance( sizes[i][0], (int, long)) and sizes[i][0] <= 0, 'Invalid system multipliers' assert isinstance( sizes[i][1], (int, long)) and sizes[i][1] >= 0, 'Invalid system multipliers' else: raise TypeError('Invalid system multipliers') #calculate multipliers and scale box and first set of positions accordingly mults[i] = sizes[i][1] - sizes[i][0] assert mults[i] != 0, 'Cannot multiply system dimension by zero' spos[:, i] /= mults[i] origin += vects[i] * sizes[i][0] vects[i] *= mults[i] #initilize new Box and Atoms box = atomman.Box(vects=vects, origin=origin) natoms = system.natoms * mults[0] * mults[1] * mults[2] atoms = atomman.Atoms(natoms=natoms) #Copy over all property values using numpy broadcasting for prop in system.atoms_prop(): o_values = system.atoms_prop(key=prop) n_values = np.empty( (mults[0] * mults[1] * mults[2], ) + o_values.shape, dtype=o_values.dtype) n_values[:] = system.atoms_prop(key=prop) n_shape = n_values.shape n_shape = (n_shape[0] * n_shape[1], ) + n_shape[2:] atoms.prop(key=prop, value=n_values.reshape(n_shape)) #Expand spos using broadcasting n_spos = np.empty((mults[0] * mults[1] * mults[2], ) + spos.shape) n_spos[:] = spos n_shape = n_spos.shape n_shape = (n_shape[0] * n_shape[1], ) + n_shape[2:] n_spos = n_spos.reshape(n_shape) #use broadcasting to create arrays to add to spos test = np.empty(mults[0] * system.natoms) test.shape = (system.natoms, mults[0]) test[:] = np.arange(mults[0]) x = test.T.flatten() test = np.empty(mults[1] * len(x)) test.shape = (len(x), mults[1]) test[:] = np.arange(mults[1]) y = test.T.flatten() test.shape = (mults[1], len(x)) test[:] = x x = test.flatten() test = np.empty(mults[2] * len(x)) test.shape = (len(x), mults[2]) test[:] = np.arange(mults[2]) z = test.T.flatten() test.shape = (mults[2], len(x)) test[:] = x x = test.flatten() test[:] = y y = test.flatten() #xyz is displacement values to add to spos xyz = np.hstack( (x[:, np.newaxis], y[:, np.newaxis], z[:, np.newaxis])) * np.array( [1. / mults[0], 1. / mults[1], 1. / mults[2]]) #save pos values, return new System atoms.prop(key='pos', value=n_spos + xyz) return atomman.System(box=box, atoms=atoms, scale=True)
def boxrhombohedral(self): return am.Box(a=3, b=3, c=3, alpha=84, beta=84, gamma=84)
def boxorthorhombic(self): return am.Box(a=3, b=4, c=5, alpha=90, beta=90, gamma=90)
def boxtriclinic(self): return am.Box(a=3, b=4, c=5, alpha=74, beta=87, gamma=105)
def boxmonoclinic(self): return am.Box(a=3, b=4, c=5, alpha=90, beta=105, gamma=90)
def make_screw_plate_old(self, size=[40, 60, 3], rad=[100, 115], move=[0., 0., 0.], filename="lmp_init.txt", opt=None): alat = uc.set_in_units(self.pot['lattice'], 'angstrom') C11 = uc.set_in_units(self.pot['c11'], 'GPa') C12 = uc.set_in_units(self.pot['c12'], 'GPa') C44 = uc.set_in_units(self.pot['c44'], 'GPa') axes = np.array([[1, -2, 1], [1, 0, -1], [1, 1, 1]]) unitx = alat * np.sqrt(6) unity = alat * np.sqrt(2) sizex = size[0] sizey = size[1] sizez = size[2] c = am.ElasticConstants(C11=C11, C12=C12, C44=C44) burgers = 0.5 * alat * -np.array([1., 1., 1.]) # initializing a new Stroh object using the data stroh = am.defect.Stroh(c, burgers, axes=axes) # monopole system box = am.Box(a=alat, b=alat, c=alat) atoms = am.Atoms(natoms=2, prop={ 'atype': 2, 'pos': [[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]] }) ucell = am.System(atoms=atoms, box=box, scale=True) system = am.rotate_cubic(ucell, axes) # shftx = 0.5 * alat * np.sqrt(6.) / 3. shftx = 0.0 shfty = -1. / 3. * alat * np.sqrt(2) / 2. # shfty = 2. / 3. * alat * np.sqrt(2) / 2. center = [0.5 * unitx * sizex, 0.5 * unity * sizey] new_pos = system.atoms_prop(key='pos') + np.array([shftx, shfty, 0.0]) system.atoms_prop(key='pos', value=new_pos) system.supersize((0, sizex), (0, sizey), (0, sizez)) # to make a plate # radius2 = rad[0] * rad[0] radiusout2 = rad[1] * rad[1] elements = [] for atom in system.atoms: elements.append('Nb') ase_atoms = am.convert.ase_Atoms.dump(system, elements) pos = ase_atoms.get_positions() delindex = [] for i in range(len(pos)): atom = ase_atoms[i] dx = pos[i, 0] - center[0] dy = pos[i, 1] - center[1] r = dx * dx + dy * dy if r > radiusout2: delindex.append(atom.index) if r < radius2: atom.symbol = 'W' del ase_atoms[delindex] (system, elements) = am.convert.ase_Atoms.load(ase_atoms) # use neb, it's to generate init configuration if opt in ['neb']: system_init = copy.deepcopy(system) shift = np.array([-0.5, -0.5, 0.0]) new_pos = system_init.atoms_prop(key='pos', scale=True) + shift system_init.atoms_prop(key='pos', value=new_pos, scale=True) disp = stroh.displacement(system_init.atoms_prop(key='pos')) system_init.atoms_prop(key='pos', value=system_init.atoms_prop(key='pos') + disp) shift = np.array([0.5, 0.50, 0.0]) new_pos = system_init.atoms_prop(key='pos', scale=True) + shift system_init.atoms_prop(key='pos', value=new_pos, scale=True) # for lammps read structure lmp.atom_data.dump(system_init, "init.txt") # for dd map plot ase.io.write("lmp_perf.cfg", images=ase_atoms, format='cfg') lmp.atom_data.dump(system, "lmp_perf.txt") shift = np.array([-0.5, -0.5, 0.0]) new_pos = system.atoms_prop(key='pos', scale=True) + shift system.atoms_prop(key='pos', value=new_pos, scale=True) new_pos = system.atoms_prop(key='pos') + move system.atoms_prop(key='pos', value=new_pos) disp = stroh.displacement(system.atoms_prop(key='pos')) # pull pull = False if pull is True: core_rows = [disp[:, 2].argsort()[-3:][::-1]] print(disp[core_rows]) exclus = np.arange(len(disp), dtype=int) unitburger = np.mean(disp[core_rows][:, 2]) print(unitburger) exclus = np.delete(exclus, core_rows) disp[core_rows] -= 1. / 3. * unitburger # disp[exclus] -= 1. / 3. * unitburger system.atoms_prop(key='pos', value=system.atoms_prop(key='pos') + disp) new_pos = system.atoms_prop(key='pos') - move system.atoms_prop(key='pos', value=new_pos) shift = np.array([0.500000, 0.500000, 0.000000]) new_pos = system.atoms_prop(key='pos', scale=True) + shift system.atoms_prop(key='pos', value=new_pos, scale=True) new_pos = system.atoms_prop(key='pos', scale=False) # for lammps read structure lmp.atom_data.dump(system, filename) dis_atoms = am.convert.ase_Atoms.dump(system, elements) return (ase_atoms, dis_atoms)
def boxtetragonal(self): return am.Box(a=3, b=3, c=8, alpha=90, beta=90, gamma=90)