def calc_elast_dipole_dft(input_file, vasp_calc=True): """Reads OUTCAR file in the same directory with one shot forces induced by removal of defect. Reads defect position from .xyz file (which contains the defect) defined by `input_file` calculates and returns the elastic dipole tensor of the defect. Args: input_file(str): name of input .xyz file containing defect cell. Returns: Elastic Dipole Tensor 3x3 numpy array. """ elastic = ElasticDipole() ats_def = Atoms(input_file) defect = find_h_atom(ats_def) if vasp_calc: import ase.io.vasp as vasp ats_pos = vasp.read_vasp() ats = vasp.read_vasp_out() ats = Atoms(ats) else: pass print 'Defect index', defect.index, 'Position', defect.position, 'Type: ', defect.number f = ats.get_forces() ats.add_property('force', f.T) ats.write('force.xyz') return elastic.compute_vacancy_dipole(defect, ats_pos.copy(), forces=ats.get_forces())
def gen_super(self, grain=None, rbt=None, sup_v=6, sup_bxv=2, rcut=2.0): """ :method:`gen_super` Creates a :class:SubGrainBoundary super cell according to conventions described in Rittner and Seidman (PRB 54 6999). Args: grain(:class:`ase.Atoms`): atoms object passed from gen_super_rbt. rbt (list): rigid body translation as fractional translations of the supercell. sup_v(int): Size of supercell along v. sup_bxv(int): Size of supercell along boundary_plane_normal crossed with v. rcut(float): Atom deletion criterion in angstrom. """ io = ImeallIO() if rbt == None: x = Atoms('{0}.xyz'.format(os.path.join(self.grain_dir, self.gbid))) else: x = Atoms(grain) struct_dir = os.path.join(self.grain_dir, 'structs') self.name = '{0}_v{1}bxv{2}_tv{3}bxv{4}_d{5}z'.format(self.gbid, str(sup_v), str(sup_bxv), '0.0', '0.0', str(rcut)) #TODO fix this so it is more transparent. #if rcut = 0 then only a super cell is generated with no deletion of atoms. if rcut > 0.0: x.set_cutoff(2.4) x.calc_connect() x.calc_dists() rem = [] u = np.zeros(3) for i in range(x.n): for n in range(x.n_neighbours(i)): j = x.neighbour(i, n, distance=3.0, diff=u) if x.distance_min_image(i,j) < rcut and j != i: rem.append(sorted([j,i])) rem = list(set([a[0] for a in rem])) if len(rem) > 0: x.remove_atoms(rem) else: print 'No duplicate atoms in list.' else: x = x*(sup_v, sup_bxv, 1) x.set_scaled_positions(x.get_scaled_positions()) if rbt == None: self.struct_file = self.name self.subgrain_dir = io.make_dir(self.calc_dir, self.name) try: with open('{0}/subgb.json'.format(self.subgrain_dir), 'r') as f: j_dict = json.load(f) except IOError: j_dict = {} j_dict['name'] = self.name j_dict['param_file'] = self.param_file j_dict['rbt'] = [0.0, 0.0] j_dict['rcut'] = rcut with open('{0}/subgb.json'.format(self.subgrain_dir), 'w') as f: json.dump(j_dict, f, indent=2) else: return sup_v, sup_bxv, x
def test_gb(GB9, tmpdir): """Tests the basic grain boundary instance attributes and methods (i.e., those that don't interact with other modules). """ assert len(GB9) == 644 a = GB9.atoms assert a.n == 644 fxyz = str(tmpdir.join("s9.xyz")) GB9.save_xyz(fxyz, "Ni") from quippy import Atoms A = Atoms(fxyz) B = Atoms("tests/gb/s9.xyz") assert A.equivalent(B)
def castep_write(atoms, filename='default.cell', optimise=False, fix_lattice=False, kpoint_spacing=0.03): """Write atoms a castep cell file and param file.""" atoms = Atoms(atoms) local_cell = BASE_CELL.copy() # Set some extra parameters local_cell['kpoint_mp_spacing'] = kpoint_spacing if fix_lattice: local_cell['fix_all_cell'] = 'true' if filename.endswith('.cell'): cell_filename = filename param_filename = filename[:-5] + '.param' else: cell_filename = filename + '.cell' param_filename = filename + '.param' local_param = BASE_PARAM.copy() if optimise: local_param['task'] = 'GeometryOptimization' cell = CastepCell(cellfile=local_cell, atoms=atoms) cell.update_from_atoms(atoms) cell.write(cell_filename) param = CastepParam(paramfile=local_param, atoms=atoms) param.write(param_filename)
def gen_screw_dislocation_quad(self): # Easy core screw_slab_unit = BodyCenteredCubic(directions = [self.x, self.y, self.z], size = (1,1,1), symbol='Fe', pbc=(1,1,1), latticeconstant = alat) screw_slab_unit = Atoms(screw_slab_unit) # set the supercell: n_x = int(18.0/screw_slab_unit.get_cell()[0,0]) n_y = int(18.0/screw_slab_unit.get_cell()[1,1]) n_z = 2 ref_slab = screw_slab_unit*(n_x,n_y,n_z) ref_slab.write('ref_slab.xyz') screw_slab_super = supercell(screw_slab_unit, n_x, n_y, n_z) b = screw_slab_unit.get_cell()[2,2] brg_vec = b*np.array([0,0,1]) disloc_l = np.array([0,0,1]) super_slab = screw_slab_super.copy() L_x = screw_slab_super.lattice[0,0] L_y = screw_slab_super.lattice[1,1] L_z = screw_slab_super.lattice[2,2] core = [(np.array([(L_x)/2., (L_y)/2., L_z/2.]), brg_vec), np.array([(L_x)/2., (L_y)/2., L_z/2.]), np.array([(L_x)/2., (L_y)/2., L_z/2.]), np.array([(L_x)/2., (L_y)/2., L_z/2.])]
def gen_edge_dislocation(self): screw_slab_unit = BodyCenteredCubic(directions = [self.x, self.y, self.z], size = (1,1,1), symbol='Fe', pbc=(1,1,1), latticeconstant = 2.83) screw_slab_unit = Atoms(screw_slab_unit) n_x = int(self.l_x/screw_slab_unit.get_cell()[0,0]) n_y = int(self.l_y/screw_slab_unit.get_cell()[1,1]) n_z = 1 screw_slab_super = supercell(screw_slab_unit, n_x, n_y, n_z) screw_slab_unit.write('ref_slab.xyz') b = screw_slab_unit.get_cell()[0,0] brg_vec = b*np.array([1,0,0]) vacuum = 70. screw_slab_super.lattice[1,1] += vacuum disloc_l = np.array([0,0,1]) screw_slab_super.set_lattice(screw_slab_super.get_cell(), scale_positions=False) super_slab = screw_slab_super.copy() L_x = screw_slab_super.lattice[0,0] L_y = screw_slab_super.lattice[1,1] L_z = screw_slab_super.lattice[2,2] #Maintain Periodicity along x and z for an edge dislocation: core = np.array([(L_x)/2., (L_y-vacuum)/2., (L_z)/2.]) screw_slab_super.set_cutoff(3.0) screw_slab_super.calc_connect() disloc_noam(screw_slab_super, core, disloc_l, brg_vec) screw_slab_super.info['core'] = core screw_slab_super.write('e{0}.xyz'.format(self.name))
def update_json(self, filename): """ This function was originally written to update all keys in the json dictionaries in the grain boundary directories. The pattern is quite general and can be adapted to just add new keys delete old keys consider it a dictionary migration routine. """ new_json = {} with open(filename, 'r') as json_old: old_json = json.load(json_old) new_json['zplanes'] = old_json['zplanes'] new_json['orientation_axis'] = old_json['orientation axis'] new_json['boundary_plane'] = old_json['boundary plane'] new_json['coincident_sites'] = old_json['coincident sites'] new_json['angle'] = old_json['angle'] new_json['gbid'] = old_json['gbid'] new_json['n_at'] = old_json['n_unit_cell'] new_json['type'] = 'symmetric tilt boundary' dir_path = os.path.join('/'.join((filename.split('/'))[:-1]), old_json['gbid']) at = Atoms('{0}.xyz'.format(dir_path, old_json['gbid'])) cell = at.get_cell() A = cell[0, 0] * cell[1, 1] new_json['A'] = A json_path = filename with open(json_path, 'w') as json_new_file: json.dump(new_json, json_new_file, indent=2)
def del_atoms(x=None): rcut = 2.0 #x = Atoms('crack.xyz') if x == None: x = Atoms('1109337334_frac.xyz') else: pass x.set_cutoff(3.0) x.calc_connect() x.calc_dists() rem=[] r = farray(0.0) u = fzeros(3) print len(x) for i in frange(x.n): for n in frange(x.n_neighbours(i)): j = x.neighbour(i, n, distance=3.0, diff=u) if x.distance_min_image(i, j) < rcut and j!=i: rem.append(sorted([j,i])) if i%10000==0: print i rem = list(set([a[0] for a in rem])) if len(rem) > 0: print rem x.remove_atoms(rem) else: print 'No duplicate atoms in list.' x.write('crack_nodup.xyz') return x
def gen_interface(): """Selects an interfacial region of a bicrystal based on common neighbour analysis. The width of the interfacial region is equal to 2*(gb_max-gb_min) where gb_max is the z-coordinate of the highest non-bcc atom, and gb_min is the lowest non-bcc atom. The method creates a file `interface.xyz` in the working directory, with the interface centered in a unit cell with 1 angstrom vacuum on each side. Returns: :class:`ase.Atoms`: Atoms object of the interfacial slab in same coordinates as original bicrystal. """ #output.xyz must have structure_type property attached. ats = Atoms('output.xyz') cell_midpoint = ats.get_cell()[2,2]/2.0 #select non-BCC sites are 0 otherwise 3. struct_type = np.array(ats.properties['structure_type']) struct_mask = [not struct for struct in struct_type] interface = ats.select(struct_mask) #select upper interface to decorate. interface = interface.select([at.position[2] > cell_midpoint for at in interface]) z_vals = [at.position[2] for at in interface] z_min = min(z_vals) z_max = max(z_vals) #take slice of interface max uncoordinated with min uncoordinated. z_width = (z_max-z_min)/2.0 z_center = z_width + z_min gb_max = z_max + 1.0*z_width gb_min = z_min - 1.0*z_width zint = ats.select([(gb_min <= at.position[2] <= gb_max) for at in ats]) #make a copy to return int_ats = zint.copy() zint.center(vacuum=1.0, axis=2) zint.write('interface.xyz') #Write POSCAR to use interstitial site generator: ats = Atoms('interface.xyz') #vasp_args=dict(xc='PBE', amix=0.01, amin=0.001, bmix=0.001, amix_mag=0.01, bmix_mag=0.001, # kpts=[3, 3, 3], kpar=9, lreal='auto', ibrion=-1, nsw=0, nelmdl=-15, ispin=2, # nelm=100, algo='VeryFast', npar=24, lplane=False, lwave=False, lcharg=False, istart=0, # voskown=0, ismear=1, sigma=0.1, isym=2) #vasp = Vasp(**vasp_args) #vasp.initialize(ats) #write_vasp('POSCAR', vasp.atoms_sorted, symbol_count=vasp.symbol_count, vasp5=True) return int_ats
def delete_atoms(self, grain=None, rcut=2.0): """ Delete atoms below a certain distance threshold. Args: grain(:class:`quippy.Atoms`): Atoms object of the grain. rcut(float): Atom deletion criterion. Returns: :class:`quippy.Atoms` object with atoms nearer than deletion criterion removed. """ io = ImeallIO() if grain == None: x = Atoms('{0}.xyz'.format(os.path.join(self.grain_dir, self.gbid))) else: x = Atoms(grain) x.set_cutoff(2.4) x.calc_connect() x.calc_dists() rem = [] u = fzeros(3) for i in frange(x.n): for n in frange(x.n_neighbours(i)): j = x.neighbour(i, n, distance=3.0, diff=u) if x.distance_min_image(i, j) < rcut and j != i: rem.append(sorted([j, i])) rem = list(set([a[0] for a in rem])) if len(rem) > 0: x.remove_atoms(rem) else: print 'No duplicate atoms in list.' if grain == None: self.name = '{0}_d{1}'.format(self.gbid, str(rcut)) self.subgrain_dir = io.make_dir(self.calc_dir, self.name) self.struct_file = gbid + '_' + 'n' + str( len(rem)) + 'd' + str(rcut) x.write('{0}.xyz'.format( os.path.join(self.subgrain_dir, self.struct_file))) return len(rem) else: return x
def add_key_to_dict(self, dirname): os.path.join(dirname, 'subgb.json') new_json = {} with open(json_path, 'r') as json_old: old_json = json.load(json_old) for key in old_json.keys(): new_json[key] = old_json[key] at = Atoms('{0}.xyz'.format(os.path.join(dirname, ))) cell = at.get_cell() A = cell[0, 0] * cell[1, 1] new_json['A'] = A new_json['n_at'] = len(at)
def calc_elast_dipole_eam(input_file, force_tol, relax_cell): """ Calculate elastic dipole using an Embedded Atom Potential. Args: input_file (str): Name of .xyz file contains unitcell with defect. force_tol (float): Force tolerance to stop relaxation. relax_cell (bool): Relax lattice vectors. Returns: Elastic Dipole Tensor 3x3 numpy array. """ try: POT_DIR = os.environ['POTDIR'] except KeyError: sys.exit("PLEASE SET export POTDIR='path/to/potfiles/'") elastic = ElasticDipole() eam_pot = os.path.join(POT_DIR, 'PotBH.xml') pot = Potential( 'IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(1.00894848312), param_filename=eam_pot) ats = Atoms(input_file) ats.set_calculator(pot) init_vol = ats.get_volume() print 'Initial Vol.', init_vol elastic.relax_defect_cell(ats, force_tol=force_tol, relax_cell=relax_cell) final_vol = ats.get_volume() print 'Final Vol.', final_vol print 'Volume Diff.', final_vol - init_vol ats = Atoms('defect_cell_relaxed.xyz') defect = find_h_atom(ats) print 'Defect index', defect.index, 'Position', defect.position, 'Type: ', defect.number ats.set_calculator(pot) return elastic.compute_vacancy_dipole(defect, ats.copy(), pot)
def calc_chemoelast(input_file): """Adds the structure type using an ovitos script to the :py:class:`Atoms` object and calculates the breakdown of the energy contributions. Args: input_file(str):Relaxed grain boundary structure file. Returns: list(float):[(chemical_energy/total_energy)*gb_energy, (elastic_energy/total_energy)*gb_energy, gb_energy] """ potparam = PotentialParameters() ener_bulk_dict = potparam.gs_ener_per_atom() r_scale_dict = potparam.eam_rscale() r_scale = r_scale_dict['PotBH.xml'] E_bulk = ener_bulk_dict['PotBH.xml'] try: POT_DIR = os.environ['POTDIR'] except KeyError: sys.exit("PLEASE SET export POTDIR='path/to/potfiles/'") eam_pot = 'PotBH.xml' eam_pot = os.path.join(POT_DIR, eam_pot) pot = Potential( 'IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(r_scale), param_filename=eam_pot) ats = AtomsReader(input_file)[-1] ats.set_calculator(pot) gb_energy = potparam.calc_e_gb(ats, E_bulk) print gb_energy, 'J/^2m' ats.write('full.xyz') elastic_energy = strain_energy(ats) with open('elast.dat', 'w') as f: for x in elastic_energy: print >> f, x[0], x[1] #generates output.xyz imeall_root = os.path.join(app.root_path, 'ovito_scripts/attach_cna.py') args_str = 'ovitos {imeall_root} -i {input_file}'.format( imeall_root=app.root_path, input_file='full.xyz').split() job = subprocess.Popen(args_str) job.wait() ats = Atoms('output.xyz') #print the three contributions x = calc_chemomechanical(ats) try: assert round(gb_energy, 2) == round(x[2], 2) except AssertionError: print "WARNING ENERGIES DON'T MATCH", gb_energy, x[2] return x
def get_cosangle(conf, csvfile): from quippy import Atoms at = Atoms(conf) with open(csvfile, 'r') as fff: fff.readline() line = fff.readline() tipatoms = line.split(',')[2:] tipatoms = [int(i) for i in tipatoms] p1, p2 = at.positions[tipatoms] dvec = p2[:2] - p1[:2] d = np.linalg.norm(dvec) cosangle = dvec[1] / d print(tipatoms) return cosangle
def relax_structure(system, potential, potential_filename=None, relax_positions=True, relax_cell=True): """ Run a geometry optimisation on the structure to find the energy minimum. Parameters ---------- system : ase.Atoms A system of atoms to run the minimisation on. The structure is altered in-place. potential : Potential or str A quippy Potential object with the desired potential, or a potential_str to initialise a new potential. Returns ------- minimised_structure : Atoms The geometry optimised structure. """ info("Inside minimiser.") qsystem = Atoms(system) if not isinstance(potential, Potential): if potential_filename: potential = Potential(potential, param_filename=potential_filename) else: potential = Potential(potential) qsystem.set_calculator(potential) minimiser = Minim(qsystem, relax_positions=relax_positions, relax_cell=relax_cell) with Capturing(debug_on_exit=True): minimiser.run() system.set_cell(qsystem.cell) system.set_positions(qsystem.positions) system.energy = qsystem.get_potential_energy() info("Minimiser done.") return system
def h2_formation_energy(pot): """ Given a potential calculate the H2 formation energy and equilibrium bond spacing. Args: pot(:quippy:class:`Potential`) potential object. Returns: float: Hydrogen molecule formation energy. """ h2 = aseAtoms('H2', positions=[[0, 0, 0], [0, 0, 0.7]]) h2 = Atoms(h2) h2.set_calculator(pot) opt = BFGS(h2) opt.run(fmax=0.0001) E_h2 = h2.get_potential_energy() return E_h2
def decorate_interface(): ats = Atoms('interface.xyz') dataset = spglib.get_symmetry_dataset(ats, symprec=1e-5) with open('unique_lattice_sites.json', 'w') as f: json.dump([ list(ats[site_num].position) for site_num in np.unique(dataset['equivalent_atoms']) ], f) unique_atoms = [] for at in ats: unique_atoms.append(at.position) voronoi = Voronoi(limits=tuple(np.diag(ats.cell)), periodic=(True, True, False)) cntr = voronoi.compute_voronoi(unique_atoms) ints_list = [] for site_num in np.unique(dataset['equivalent_atoms']): for vert in voronoi.get_vertices(site_num, cntr): ints_list.append(vert.tolist()) for unique in ints_list: ats.add_atoms(unique, 1) for i in range(len(ats)): ats.id[i] = i #remove voronoi duplicates print 'Fe_H atoms', len(ats) ats.wrap() del_ats = aseAtoms() for at in ats: del_ats.append(at) geometry.get_duplicate_atoms(del_ats, cutoff=0.2, delete=True) ats = del_ats.copy() print 'Fe_H atoms remove duplicates', len(ats) #select unique hydrogens #for i in range(len(ats)): # ats.id[i] = i ints_list = [at.position for at in ats if at.number == 1] with open('unique_h_sites.json', 'w') as f: json.dump([list(u) for u in ints_list], f) ats.write('hydrogenated_grain.xyz')
def pull_file(args, dir_name=None): if dir_name == None: ats = read(args.input, index=":") else: ats = read(os.path.join(dir_name, args.input), index=":") if not args.full_qm: init_ats = Atoms("crack_sim.xyz") crack_pos = init_ats.info["CrackPos"] qm_radius = 3.0 buff = 8.0 mm_pos = init_ats.get_positions() x, y, z = init_ats.positions.T #radius1 = np.sqrt((x - crack_pos[0])**2 + (y-crack_pos[1])**2 + (z-crack_pos[2])**2) radius1 = np.sqrt((x - crack_pos[0])**2 + (y - crack_pos[1])**2) qm_region_mask = (radius1 < qm_radius) qm_pos = init_ats.get_positions()[qm_region_mask] qm_com = qm_pos.mean(axis=0) # just to avoid pbc errors.. cell_center = np.diag(ats[0].get_cell()) / 2.0 print cell_center print 'Full Cell CrackPos: ', crack_pos crack_pos = crack_pos - qm_com + cell_center print 'Shift CrackPos', crack_pos print 'QM Radius', qm_radius print len(ats) for at in ats[args.start:args.end]: #mark quantum atoms x, y, z = at.positions.T radius1 = np.sqrt((x - crack_pos[0])**2 + (y - crack_pos[1])**2 + (z - crack_pos[2])**2) qm_region_mask = np.array(map(int, (radius1 <= qm_radius))) print sum(qm_region_mask) at.new_array("qm_atoms", qm_region_mask, dtype=float) at.set_array("qm_atoms", qm_region_mask) write_xyz(args.output, at, append=True) else: for at in ats[args.start:args.end]: write_xyz(args.output, at, append=True)
def gen_screw_dislocation(self): screw_slab_unit = BodyCenteredCubic(directions = [self.x, self.y, self.z], size = (1,1,1), symbol='Fe', pbc=(1,1,1), latticeconstant = 2.83) screw_slab_unit = Atoms(screw_slab_unit) # set the supercell: n_x = int(self.l_x/screw_slab_unit.get_cell()[0,0]) n_y = int(self.l_y/screw_slab_unit.get_cell()[1,1]) n_z = 2 screw_slab_super = supercell(screw_slab_unit, n_x, n_y, n_z) ref_slab = screw_slab_unit*(n_x,n_y,n_z) ref_slab.write('ref_slab.xyz') #Burgers vector modulus: b = screw_slab_unit.get_cell()[2,2] brg_vec = b*np.array([0,0,1]) print b vacuum = 70. screw_slab_super.lattice[0,0] += vacuum screw_slab_super.lattice[1,1] += vacuum disloc_l = np.array([0,0,1]) screw_slab_super.set_lattice(screw_slab_super.get_cell(), scale_positions=False) super_slab = screw_slab_super.copy() L_x = screw_slab_super.lattice[0,0] L_y = screw_slab_super.lattice[1,1] L_z = screw_slab_super.lattice[2,2] core = np.array([(L_x-vacuum)/2., (L_y-vacuum)/2., L_z/2.]) screw_slab_super.set_cutoff(3.0) screw_slab_super.calc_connect() disloc_noam(screw_slab_super, core, disloc_l, brg_vec) screw_slab_super.info['core'] = core screw_slab_super.write('s{0}.xyz'.format(self.name))
sc = SumCalculator(pot, cc) atoms.set_constraint(FixAtoms(mask=fix_line_mask)) atoms.set_calculator(sc) LBFGS(atoms, use_armijo=False).run(fmax=0.2) fix_line = [FixedLine(i, np.array([0, 1, 0])) for i in fix_line_idx] atoms.set_array('fix_line_mask', fix_line_mask) atoms.set_constraint(fix_line + springs) atoms.set_calculator(pot) opt = vanillaLBFGS(atoms) else: print("Method not understood") return opt.attach(trajectory_write, interval=5) opt.run(fmax=fmax) return if __name__ == '__main__': pot = Potential('IP TS', param_filename="../ts_params.xml") in_file = sys.argv[1] out_file = os.path.splitext(in_file)[0] + '_relaxed.xyz' atoms = Atoms(in_file) minim_precon(atoms) atoms.write(out_file)
def constrained_minim(atoms, method='LBFGS', vacuum=20.0, k_spring=0.6, clamp_mask=None, initial_positions=None, fmax=0.05, spring='point'): c = np.ptp(atoms.positions, axis=0) c += vacuum atoms.set_cell(np.diag(c)) if clamp_mask is None: at_help = Atoms('crack.xyz') clamp_mask = at_help.get_array('clamp_mask') if initial_positions is None: at_help = Atoms('crack.xyz') at_help.get_array('pos_orig') if spring == 'plane': springs = [ Hookean(a1=i, a2=[0, -1, 0, initial_positions[i, 1]], k=k_spring, rt=0) for i in np.where(clamp_mask)[0] ] else: springs = [ Hookean(a1=i, a2=initial_positions[i], k=k_spring, rt=0) for i in np.where(clamp_mask)[0] ] from quippy.io import AtomsWriter out = AtomsWriter("traj-relax_structure.xyz") trajectory_write = lambda: out.write(atoms) if method == "LBFGS": pot = atoms.calc cc = ConstraintCalculator(springs) sc = SumCalculator(pot, cc) left, bottom, _ = initial_positions.min(axis=0) fix_line_mask = (initial_positions[:, 0] < left + 6.5) fix_line = FixAtoms(mask=fix_line_mask) atoms.set_array('fix_line_mask', fix_line_mask) atoms.set_constraint(fix_line) atoms.set_calculator(sc) opt = LBFGS(atoms, use_armijo=False) elif method == "FIRE": right, top, _ = initial_positions.max(axis=0) left, bottom, _ = initial_positions.min(axis=0) fix_line_mask = np.logical_or(initial_positions[:, 0] > right - 6.5, initial_positions[:, 0] < left + 6.5) fix_line_idx = np.where(fix_line_mask)[0] fix_line = [FixedLine(i, np.array([0, 1, 0])) for i in fix_line_idx] atoms.set_array('fix_line_mask', fix_line_mask) atoms.set_constraint(fix_line + springs) opt = FIRE(atoms, dtmax=2.5, maxmove=0.5) elif method == "mix": # do a first opt by keeping vertical edges fixed, then make them move along y right, top, _ = initial_positions.max(axis=0) left, bottom, _ = initial_positions.min(axis=0) fix_line_mask = np.logical_or(initial_positions[:, 0] > right - 6.5, initial_positions[:, 0] < left + 6.5) fix_line_idx = np.where(fix_line_mask)[0] pot = atoms.calc cc = ConstraintCalculator(springs) sc = SumCalculator(pot, cc) atoms.set_constraint(FixAtoms(mask=fix_line_mask)) atoms.set_calculator(sc) LBFGS(atoms, use_armijo=False).run(fmax=0.2) fix_line = [FixedLine(i, np.array([0, 1, 0])) for i in fix_line_idx] atoms.set_array('fix_line_mask', fix_line_mask) atoms.set_constraint(fix_line + springs) atoms.set_calculator(pot) opt = vanillaLBFGS(atoms) else: print("Method not understood") return opt.attach(trajectory_write, interval=5) opt.run(fmax=fmax) return
#For edge z is dislocation line z = [0, 1, 1] s_system = list(x) s_system.extend(y) name = ''.join(map(str, s_system)).replace('-', '') print x, y, z disloc = Dislocation(x=x, y=y, z=z, name=name) disloc.gen_edge_dislocation() POT_DIR = '/Users/lambert/pymodules/imeall/imeall/potentials' eam_pot = os.path.join(POT_DIR, 'Fe_Mendelev.xml') print 'Open Atoms' at = Atoms('e{0}.xyz'.format(name)) at.set_cutoff(3.0) at.calc_connect() print 'Delete atoms' at = gbr.delete_atoms(grain=at, rcut=1.5) at.info['OrigHeight'] = at.positions[:, 1].max() - at.positions[:, 1].min() r_scale = 1.00894848312 rem = [] for atom in at: if atom.position[0] <= 0.00 and atom.position[1] <= 100.0: rem.append(atom.index + 1) print 'Removing ', len(rem), ' atoms.' if len(rem) > 0: at.remove_atoms(rem) else:
POT_DIR = os.environ['POTDIR'] eam_pot = os.path.join(POT_DIR, 'PotBH.xml') r_scale = 1.00894848312 pot = Potential('IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(r_scale), param_filename=eam_pot) #alat = 2.82893 #could just use the proper one as well.... alat = 2.837666 sup_cell = args.supercellsize tetra_pos = alat*np.array([0.5, 0.0, 0.75]) octa_pos = alat*np.array([0.5, 0.5, 0.0]) #Structures gb = BodyCenteredCubic(directions = [[1,0,0], [0,1,0], [0,0,1]], size = (sup_cell[0],sup_cell[1],sup_cell[2]), symbol='Fe', pbc=(1,1,1), latticeconstant = alat) mid_point = 0.5*(np.diag(gb.get_cell())) mid_point = [((sup_cell[0]-1)/2.)*alat for sp in sup_cell] gb = Atoms(gb) if args.tetra: print 'Tetrahedral Defect' tetra_pos += mid_point gb.add_atoms(tetra_pos, 1) gb.write('bcc_h.xyz') elif args.octa: print 'Octahedral Defect' octa_pos += mid_point gb.add_atoms(octa_pos, 1) gb.write('bcc_h.xyz') else: gb.write('bcc.xyz')
def NetCDFReader(source, frame=None, start=0, stop=None, step=1, format=None): opened = False if isinstance(source, str): opened = True source = netcdf_file(source) from quippy import Atoms DEG_TO_RAD = pi/180.0 remap_names = {'coordinates': 'pos', 'velocities': 'velo', 'cell_lengths': None, 'cell_angles': None, 'cell_lattice': None, 'cell_rotated': None} prop_type_to_value = {PROPERTY_INT: 0, PROPERTY_REAL: 0.0, PROPERTY_STR: "", PROPERTY_LOGICAL: False} prop_dim_to_ncols = {('frame','atom','spatial'): 3, ('frame','atom','label'): 1, ('frame', 'atom'): 1} if frame is not None: start = frame stop = frame+1 step = 1 else: if stop is None: stop = source.variables['cell_lengths'].shape[0] for frame in range(start, stop, step): cl = source.variables['cell_lengths'][frame] ca = source.variables['cell_angles'][frame] lattice = make_lattice(cl[0],cl[1],cl[2],ca[0]*DEG_TO_RAD,ca[1]*DEG_TO_RAD,ca[2]*DEG_TO_RAD) at = Atoms(n=netcdf_dimlen(source, 'atom'), lattice=lattice, properties={}) for name, var in source.variables.iteritems(): name = remap_names.get(name, name) if name is None: continue name = str(name) # in case it's a unicode string if 'frame' in var.dimensions: if 'atom' in var.dimensions: # It's a property value = var[frame] if value.dtype.kind != 'S': value = value.T at.add_property(name, value) else: # It's a param if var.dimensions == ('frame','string'): # if it's a single string, join it and strip it at.params[name] = ''.join(var[frame]).strip() else: if name == 'cutoff': at.cutoff = var[frame] elif name == 'cutoff_skin': at.cutoff_skin = var[frame] elif name == 'nneightol': at.nneightol = var[frame] elif name == 'pbc': at.pbc = var[frame] else: at.params[name] = var[frame].T if 'cell_rotated' in source.variables: cell_rotated = source.variables['cell_rotated'][frame] orig_lattice = source.variables['cell_lattice'][frame] #if cell_rotated == 1: at.set_lattice(orig_lattice, True) yield at def close(self): if self.opened: source.close()
def pp_nye_tensor(at, rr=15.0, dis_type='edge'): # Post Processing routine to append nye tensor information # to atoms object. # Load reference slab and calculate connectivity ref_slab = Atoms('./ref_slab.xyz') at.set_cutoff(3.0) at.calc_connect() ref_slab.set_cutoff(3.0) ref_slab.calc_connect() core = np.zeros(3) # To save time it is possible to only # calculate the nye tensor for a 'core' region # determined by cutting out a cluster: if dis_type in ['edge', 'screw']: try: core = at.info['core'] except: sys.exit('No Core Info') print '\t Core Position: ', core elif dis_type == 'crack': core = at.info['CrackPos'] print '\t Crack Position: ', core fixed_mask = (np.sqrt((at.positions[:, 0] - core[0])**2 + (at.positions[:, 1] - core[1])**2) < rr) if dis_type in ['edge', 'screw']: at.add_property('edgex', 0.0) at.add_property('edgey', 0.0) at.add_property('screw', 0.0) #Going to append full nye tensor to the crack tip: elif dis_type == 'crack': at.add_property('nye', 0.0, n_cols=9, overwrite=True) cl = at.select(mask=fixed_mask, orig_index=True) print '\t Size of cluster: ', len(cl) # Append screw and edge information # Probably should just pass an array at this stage? alpha = calc_nye_tensor(cl, ref_slab, 3, 3, cl.n) cl.edgex = alpha[2, 0, :] cl.edgey = alpha[2, 1, :] cl.screw = alpha[2, 2, :] # Update quantum region according to the # position of the dislocation core: if dis_type in ['edge', 'screw']: if dis_type == 'screw': defect_pos = cl.screw elif dis_type == 'edge': defect_pos = cl.edgex total_def = 0. c = np.array([0., 0., 0.]) for i in range(len(cl)): total_def = total_def + defect_pos[i] c[0] = c[0] + cl.positions[i, 0] * defect_pos[i] c[1] = c[1] + cl.positions[i, 1] * defect_pos[i] c[0] = c[0] / total_def c[1] = c[1] / total_def c[2] = cl.lattice[2, 2] / 2. core[:] = c.copy() if dis_type in ['edge', 'screw']: for index, screw, edgex, edgey in zip(cl.orig_index, cl.screw, cl.edgex, cl.edgey): # Now thread atoms back in looks like select will have indices in the fortran convention. at.screw[index - 1] = screw at.edgex[index - 1] = edgex at.edgey[index - 1] = edgey elif dis_type == 'crack': for orig_index, index in zip(cl.orig_index, range(len(cl))): at.nye[:, orig_index - 1] = alpha[:, :, index].T.reshape(9) return core
print '\tCalculate Dynamics: ', run_dyn print '\tCalculate Nye Tensor: ', calc_nye print '\tInput File: ', input_file print '\tPotential: ', pot_type if pot_type == 'EAM': global potdir potdir = os.environ['POTDIR'] eam_pot = os.path.join(potdir, 'PotBH.xml') r_scale = 1.00894848312 pot = Potential( 'IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(r_scale), param_filename=eam_pot) elif pot_type == 'TB': tb = TightBindingPot(alat=1.00, nk=12) screw_slab_unit = Atoms(screw_slab_unit) center_cell = np.diag(screw_slab_unit.get_cell()) / 2. screw_slab_unit.add_atoms(center_cell, 1) #screw_slab_unit.add_atoms(center_cell*0.76, 6) screw_slab_unit.set_atoms(screw_slab_unit.Z) print len(screw_slab_unit) tb.write_control_file('ctrl.fe', screw_slab_unit) pot = Potential('IP LMTO_TBE', param_str=""" <params> <LMTO_TBE_params n_types="2" control_file="ctrl.fe"> <per_type_data type="1" atomic_num="26"/> <per_type_data type="2" atomic_num="1"/> </LMTO_TBE_params> </params>""")
from quippy import Atoms, bcc from matscipy.socketcalc import VaspClient, SocketCalculator #look for mpirun and vasp on $PATH #mpirun = spawn.find_executable('mpirun') #vasp = spawn.find_executable('vasp') #vasp = '/home/eng/essswb/vasp5/vasp.5.3.new/vasp' mpirun = '/usr/bin/cobalt-mpirun' vasp = '/projects/SiO2_Fracture/iron/vasp.bgq' npj = 512 # nodes per job ppn = 4 njobs = 1 nodes = npj * njobs job_xyz = glob.glob('feb*.xyz')[0] bulk = Atoms(job_xyz) line = [] for at in bulk: line.append(FixedLine(at.index, (0, 0, 1))) bulk.set_constraint(line) hostname, ip = get_hostname_ip() partsize, partition, job_name = get_cobalt_info() blocks = get_bootable_blocks(partition, nodes) print('Available blocks: %s' % blocks) boot_blocks(blocks) block, corner, shape = list(block_corner_iter(blocks, npj))[0] print block, corner, shape
def calc_bulk_dissolution(args): """Calculate the bulk dissolution energy for hydrogen in a tetrahedral position in bcc iron. Args: args(list): determine applied strain to unit cell. """ POT_DIR = os.path.join(app.root_path, 'potentials') eam_pot = os.path.join(POT_DIR, 'PotBH.xml') r_scale = 1.00894848312 pot = Potential( 'IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(r_scale), param_filename=eam_pot) alat = 2.83 gb = BodyCenteredCubic(directions=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], size=(6, 6, 6), symbol='Fe', pbc=(1, 1, 1), latticeconstant=alat) cell = gb.get_cell() print 'Fe Cell', cell e1 = np.array([1, 0, 0]) e2 = np.array([0, 1, 0]) e3 = np.array([0, 0, 1]) if args.hydrostatic != 0.0: strain_tensor = np.eye(3) + args.hydrostatic * np.eye(3) cell = cell * strain_tensor gb.set_cell(cell, scale_atoms=True) print 'Hydrostatic strain', args.hydrostatic print 'strain tensor', strain_tensor print gb.get_cell() elif args.stretch != 0.0: strain_tensor = np.tensordot(e2, e2, axes=0) strain_tensor = np.eye(3) + args.stretch * strain_tensor cell = strain_tensor * cell print 'Stretch strain' print 'Cell:', cell gb.set_cell(cell, scale_atoms=True) elif args.shear != 0.0: strain_tensor = np.tensordot(e1, e2, axes=0) strain_tensor = np.eye(3) + args.shear * strain_tensor cell = strain_tensor.dot(cell) print 'Shear Strain', strain_tensor print 'Cell:', cell gb.set_cell(cell, scale_atoms=True) gb.write('sheared.xyz') else: print 'No strain applied.' tetra_pos = alat * np.array([0.25, 0.0, 0.5]) h2 = aseAtoms('H2', positions=[[0, 0, 0], [0, 0, 0.7]]) h2 = Atoms(h2) gb = Atoms(gb) gb_h = gb.copy() gb_h.add_atoms(tetra_pos, 1) #caclulators gb.set_calculator(pot) h2.set_calculator(pot) gb_h.set_calculator(pot) gb_h.write('hydrogen_bcc.xyz') #Calc Hydrogen molecule energy opt = BFGS(h2) opt.run(fmax=0.0001) E_h2 = h2.get_potential_energy() h2.write('h2mol.xyz') #strain_mask = [1,1,1,0,0,0] strain_mask = [0, 0, 0, 0, 0, 0] ucf = UnitCellFilter(gb_h, strain_mask) #opt = BFGS(gb_h) opt = FIRE(ucf) opt.run(fmax=0.0001) E_gb = gb.get_potential_energy() E_gbh = gb_h.get_potential_energy() E_dis = E_gbh - E_gb - 0.5 * E_h2 print 'E_gb', E_gb print 'E_gbh', E_gbh print 'H2 Formation Energy', E_h2 print 'Dissolution Energy', E_dis
sparse_file = 'gp33b.xml.sparseX.GAP_2016_10_3_60_19_29_10_8911' gap_pot_sparse = os.path.join(POT_DIR, sparse_file) shutil.copy(gap_pot, './') shutil.copy(gap_pot_sparse, './') qm_pot = Potential('IP GAP', param_filename=gap_pot) else: print ("Using PURE EAM POTENTIAL") qm_pot = Potential('IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(1.00894848312), param_filename=eam_pot) nebpath = NEBPaths() nebanalysis = NEBAnalysis() if args.auto_gen: disloc_ini, disloc_fin = nebpath.build_h_nebpath(neb_path=np.array(args.neb_path), fmax = args.fmax, sup_cell=args.sup_cell) else: disloc_ini = Atoms('disloc_0.xyz') disloc_fin = Atoms('disloc_1.xyz') n_knots = args.knots images = [disloc_ini] + \ [disloc_ini.copy() for i in range(n_knots)] + \ [disloc_fin] #copied this from Tom's scripts: need to check and understand #Will turn these on after the initial run throughs to check the difference. #alpha = dft_alat/eam_alat #eam_bulk_mod = (eam_C11 + 2.0*eam_C12)/3.0 #dft_bulk_mod = (dft_C11 + 2.0*dft_C12)/3.0 #beta = eam_bulk_mod/dft_bulk_mod/alpha/alpha/alpha qmmm_pot = ForceMixingCarvingCalculator(disloc_ini, qm_region_mask,
h_pos = h + lat h_list.append(np.array(h_pos)) h_list = self.append_if_thresh(h_list, rcut = d_H) #for h_pos in h_list: # cl.add_atoms(h_pos,1) else: #In this case we just add to the octahedral or in a non-bulk #environment largest volume sites. h_list = [] for h in oct_sites: h_list.append(h) h_list = self.append_if_thresh(h_list, rcut = d_H) return h_list if __name__=='__main__': parser = argparse.ArgumentParser() parser.add_argument('-p','--pattern', default="1.traj.xyz") args = parser.parse_args() pattern = args.pattern jobs = glob.glob(pattern) print jobs hydrify = Hydrify() scratch = os.getcwd() for job in jobs: os.chdir(job) ats = Atoms('crack.xyz') hydrify.hydrogenate_gb(mode='CrackTip')