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 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 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 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 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 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 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 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 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 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))
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
</params>""") #If there is an initial strain energy increment that here: pot.print_() screw_slab_unit.write('screw_unitcell.xyz') screw_slab_unit.set_calculator(pot) #Elastic constants are disabled until we have tight binding operational. if calc_elastic_constants and dyn_type != 'LOTF': cij = pot.get_elastic_constants(screw_slab_unit) print 'ELASTIC CONSTANTS' print ((cij / units.GPa).round(2)) E = youngs_modulus(cij, y) nu = poisson_ratio(cij, y, x) print 'Youngs Modulus: ', E/units.GPa,'Poisson Ratio: ', nu print 'Effective elastic modulus E: ', E/(1.-nu**2) print 'Loading Structure File:', '{0}.xyz'.format(input_file) defect = Atoms('{0}.xyz'.format(input_file)) top = defect.positions[:,1].max() bottom = defect.positions[:,1].min() left = defect.positions[:,0].min() right = defect.positions[:,0].max() orig_height = (defect.positions[:,1].max()-defect.positions[:,1].min()) #Attaching Properties to atoms object if calc_elastic_constants: defect.info['YoungsModulus'] = E defect.info['PoissonRatio_yx'] = nu defect.info['OrigHeight'] = orig_height strain_atoms = fix_edges_defect(defect) xpos = defect.positions[:,0]
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
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
cell = surf_cell.get_cell() A = cell[0][0]*cell[1][1] gamma = (surf_ener- len(surf_cell)*ener_per_atom)/A print '2*gamma ev/A2', gamma print '2*gamma J/m2', gamma/(units.J/units.m**2) j_dict = {'or_axis':or_axis, 'bp':bp, 'gamma':gamma} with open('gbfrac.json','w') as f: json.dump(j_dict, f) out = AtomsWriter('{0}'.format('{0}_surf.xyz'.format(gbid))) out.write(Atoms(surf_cell)) out.close() frac_cell = gb_frac.build_tilt_sym_frac() #Unit cell for grain boundary fracture cell: print frac_cell.get_cell().round(2) frac_cell = Atoms(frac_cell) frac_cell = del_atoms(frac_cell) #Relax grainboundary crack cell unit cell: pot = Potential('IP EAM_ErcolAd', param_filename='Fe_Mendelev.xml') frac_cell.set_calculator(pot) slab_opt = FIRE(frac_cell) slab_opt.run(fmax = (0.02*units.eV/units.Ang)) #Print frac_cell to file: out = AtomsWriter('{0}'.format('frac_cell.xyz'.format(gbid))) out.write(Atoms(frac_cell)) out.close()
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 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 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
print args.input_file restart = args.restart print restart if restart: print 'Restarting job' input_file = args.input_file pot_file = args.pot_file if args.output_file: traj_file = args.output_file print 'Output_file: ', traj_file print 'POT FILE', pot_file #Need to add an arg parser here learn_on_the_fly = True if learn_on_the_fly: print 'Initialize Potentials' atoms = Atoms(input_file) cluster = Atoms('cluster.xyz') mm_pot = Potential(mm_init_args, param_filename=pot_file, cutoff_skin=cutoff_skin) unit_cell = BodyCenteredCubic(directions = [[1,0,0], [0,1,0],[0,0,1]], size = (4,4,4), symbol='Fe', pbc=(1,1,1), latticeconstant = 2.87) def proto_qm_pot_callback(unit_cell): global qm_pot tb = tb_pot.TightBindingPot(alat=1.00, nk=1) tb.write_control_file('ctrl.fe', unit_cell) qm_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"/>
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,
vasp_args = dict(xc='PBE', amix=0.22, amin=0.02, bmix=0.6, amix_mag=1.0, bmix_mag=0.9, lorbit=11, kpts=[1, 6, 6], kpar=args.kpar, lreal='auto', nelmdl=-15, ispin=2, prec='Accurate', ediff=1.e-4, encut=420, nelm=100, algo='VeryFast', lplane=False, lwave=False, lcharg=False, istart=0, magmom=magmoms, maxmix=25, #https://www.vasp.at/vasp-workshop/slides/handsonIV.pdf #for badly behaved clusters. voskown=0, ismear=1, sigma=0.1, isym=2, iwavpr=11) mpirun = spawn.find_executable('mpirun') vasp = '/home/mmm0007/vasp/vasp.5.4.1/bin/vasp_std' vasp_client = VaspClient(client_id=0, npj=96, ppn=1, exe=vasp, mpirun=mpirun, parmode='mpi', ibrion=13, nsw=1000000, npar=6, **vasp_args) traj = io.Trajectory('relaxation.traj','a', gam_cell) qm_pot = SocketCalculator(vasp_client) gam_cell.set_calculator(qm_pot) fixed_line=[] for at in gam_cell: fixed_line.append(FixedLine(at.index, (1,0,0))) gam_cell.set_constraint(fixed_line) opt = PreconLBFGS(Atoms(gam_cell)) #opt.attach(traj_writer, interval=1) opt.attach(traj.write, interval=1) opt.run(fmax=0.01) traj.close()
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
#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:
print 'no crack dictionary found.' sys.exit() Grain_Boundary = False if not Grain_Boundary: unit_slab = crack.build_unit_slab() pot_dir = os.environ['POTDIR'] pot_file = os.path.join(pot_dir, crack_info['param_file']) mm_pot = Potential('IP EAM_ErcolAd do_rescale_r=T r_scale=1.00894848312', param_filename=pot_file, cutoff_skin=2.0) # gb_frac.py will generate the frac_cell.xyz file which contains # a crack_cell: if Grain_Boundary: unit_slab = Atoms('frac_cell.xyz') unit_slab.set_calculator(mm_pot) #calculate the elasticity tensor: crack.calculate_c(mm_pot) surface = crack.build_surface(mm_pot) E_surf = surface.get_potential_energy() bulk = bcc(2.82893) bulk.set_atoms(26) bulk.info['adsorbate_info']=None bulk.set_calculator(mm_pot) E_bulk = bulk.get_potential_energy()/len(bulk) area = (surface.get_cell()[0,0]*surface.get_cell()[2,2]) print E_surf, E_bulk gamma = (E_surf - E_bulk*len(surface))/(2.0*area) print('Surface energy of %s surface %.4f J/m^2\n' %
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>""")
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)
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
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')
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
import numpy as np from ase import units from quippy import Atoms, set_fortran_indexing from quippy import set_fortran_indexing from hydrify_cracktips import Hydrify set_fortran_indexing(False) scratch = os.getcwd() hydrify = Hydrify() parser = argparse.ArgumentParser() parser.add_argument("-dc", "--double_cell", help="Double Cell along z direction", action="store_true") args = parser.parse_args() DOUBLE_CELL = args.double_cell ats = Atoms('crack.xyz') if DOUBLE_CELL: ats = ats*(1,1,2) ats.info['adsorbate_info']=None with open('crack_info.pckl','r') as f: crack_dict= pickle.load(f) print 'G: {}, H_d: {}, sim_T {}'.format(crack_dict['initial_G']*(units.m**2/units.J), crack_dict['H_d'], crack_dict['sim_T']/units.kB) h_list = hydrify.hydrogenate_gb(ats, mode='CrackTip', d_H=crack_dict['H_d'][0], tetrahedral=True, crackpos_fix=ats.params['CrackPos']) for h in h_list: ats.add_atoms(h,1) #ats.wrap() ats.write('crackH.xyz')