def relax_gb(gb_file='file_name', traj_steps=120, total_steps=1200, force_tol=0.05): """Method to relax a grain_boundary bicrystal structure. Requires a .json file with at a minimum the 'param_file' variable specified. Args: gb_file(str): gbid. traj_steps(int): number of steps between print trajectories. total_steps(int): total number of force relaxation steps. force_tol(float): Force relaxation criterion in ev/A. Returns: :class:`ase.Atoms` Object """ def converged(grain, smax, fmax): maxstress = max(grain.get_stress().ravel()) rmsforces = np.sum(grain.get_forces()**2, axis=1)**0.5 maxforce = max(rmsforces) if maxforce < fmax and maxstress < smax: return True return False with open('subgb.json', 'r') as outfile: j_dict = json.load(outfile) try: POT_DIR = os.path.join(app.root_path, 'potentials') except KeyError: sys.exit( "Please set POTDIR in os environment. `export POTDIR='path/to/potfiles/`" ) try: param_file = j_dict['param_file'] if param_file == 'iron_mish.xml': eam_pot = os.path.join(POT_DIR, 'iron_mish.xml') r_scale = 1.0129007626 elif param_file == 'Fe_Mendelev.xml': eam_pot = os.path.join(POT_DIR, 'Fe_Mendelev.xml') r_scale = 1.00894848312 elif param_file == 'PotBH.xml': eam_pot = os.path.join(POT_DIR, 'PotBH.xml') r_scale = 1.00894848312 elif param_file == 'Fe_Ackland.xml': eam_pot = os.path.join(POT_DIR, 'Fe_Ackland.xml') r_scale = 1.00894185389 elif param_file == 'Fe_Dudarev.xml': eam_pot = os.path.join(POT_DIR, 'Fe_Dudarev.xml') r_scale = 1.01279093417 elif param_file == 'gp33b.xml': eam_pot = os.path.join(POT_DIR, 'gp33b.xml') sparse_file = 'gp33b.xml.sparseX.GAP_2016_10_3_60_19_29_10_8911' eam_pot_sparse = os.path.join(POT_DIR, sparse_file) shutil.copy(eam_pot, './') shutil.copy(eam_pot_sparse, './') else: print 'No paramfile found!' sys.exit() except KeyError: print 'No EAM potential file with that name. Relax failed.' sys.exit() print 'Using: ', eam_pot pot_file = eam_pot.split('/')[-1] print '{0}.xyz'.format(gb_file) print os.getcwd() grain = io.read('{0}.xyz'.format(gb_file), index='-1') if param_file != 'gp33b.xml': pot = Potential( 'IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(r_scale), param_filename=eam_pot) else: pot = Potential('IP GAP', param_filename=eam_pot) grain.set_calculator(pot) grain.info['adsorbate_info'] = None E_gb_init = grain.get_potential_energy() traj_file = gb_file if 'traj' in traj_file: out = AtomsWriter('{0}'.format('{0}.xyz'.format(traj_file))) else: out = AtomsWriter('{0}'.format('{0}_traj.xyz'.format(traj_file))) strain_mask = [0, 0, 1, 0, 0, 0] ucf = UnitCellFilter(grain, strain_mask) opt = FIRE(ucf) cell = grain.get_cell() A = cell[0][0] * cell[1][1] H = cell[2][2] #Calculation dumps total energyenergy and grainboundary area data to json file. with open('subgb.json', 'r') as f: gb_dict = json.load(f) #Write an initial dict so we know if the system has been initialized but the calculation is not finished. with open('subgb.json', 'w') as outfile: for key, value in gb_dict.items(): j_dict[key] = value json.dump(j_dict, outfile, indent=2) CONVERGED = False FORCE_TOL = force_tol #default to 5 if traj_steps = 120, otherwise increases num_iters = int(float(total_steps) / float(traj_steps)) logging.debug('num_iters: {}'.format(num_iters)) for i in range(num_iters): opt.run(fmax=FORCE_TOL, steps=traj_steps) out.write(grain) force_array = grain.get_forces() max_force_II = max([max(f) for f in force_array]) max_forces = [ np.sqrt(fx**2 + fy**2 + fz**2) for fx, fy, fz in zip( grain.properties['force'][0], grain.properties['force'][1], grain.properties['force'][2]) ] if max(max_forces) <= FORCE_TOL: CONVERGED = True break out.close() gb_dict['converged'] = CONVERGED E_gb = grain.get_potential_energy() gb_dict['E_gb'] = E_gb gb_dict['E_gb_init'] = E_gb_init gb_dict['area'] = A with open('subgb.json', 'w') as outfile: for key, value in gb_dict.items(): j_dict[key] = value json.dump(j_dict, outfile, indent=2) if param_file == 'gp33b.xml': os.remove(param_file) os.remove(sparse_file) else: pass return grain
def molecular_dynamics(system, potential, potential_filename=None, temperature=300, total_steps=1100000, timestep=1.0, connect_interval=200, write_interval=20000, equilibration_steps=100000, out_of_plane=None, random_seed=None): """ Run very simple molecular dynamics to generate some configurations. Writes configurations out as xyz and CASTEP files. """ info("Inside MD.") if random_seed is None: random_seed = random.SystemRandom().randint(0, 2**63) quippy.system.system_set_random_seeds(random_seed) info("Quippy Random Seed {0}.".format(random_seed)) system = Atoms(system) # Can take Potential objects, or just use a string if not isinstance(potential, Potential): if potential_filename: potential = Potential(potential, param_filename=potential_filename) else: potential = Potential(potential) system.set_calculator(potential) dynamical_system = DynamicalSystem(system) with Capturing(debug_on_exit=True): dynamical_system.rescale_velo(temperature) if out_of_plane is not None: # Stop things moving vertically in the cell dynamical_system.atoms.velo[3, :] = 0 base_dir = os.getcwd() run_path = '{0}_{1:g}/'.format(system.info['name'], temperature) info("Putting files in {0}.".format(run_path)) os.mkdir(run_path) os.chdir(run_path) trajectory = 'traj_{0}_{1:g}.xyz'.format(system.info['name'], temperature) out = AtomsWriter(trajectory) dynamical_system.atoms.set_cutoff(potential.cutoff() + 2.0) dynamical_system.atoms.calc_connect() potential.calc(dynamical_system.atoms, force=True, energy=True, virial=True) structure_count = 0 # Basic NVE molecular dynamics for step_number in range(1, total_steps + 1): dynamical_system.advance_verlet1(timestep, virial=dynamical_system.atoms.virial) potential.calc(dynamical_system.atoms, force=True, energy=True, virial=True) dynamical_system.advance_verlet2(timestep, f=dynamical_system.atoms.force, virial=dynamical_system.atoms.virial) # Maintenance of the system if not step_number % connect_interval: debug("Connect at step {0}".format(step_number)) dynamical_system.atoms.calc_connect() if step_number < equilibration_steps: with Capturing(debug_on_exit=True): dynamical_system.rescale_velo(temperature) if not step_number % write_interval: debug("Status at step {0}".format(step_number)) # Print goes to captured stdout with Capturing(debug_on_exit=True): dynamical_system.print_status( epot=dynamical_system.atoms.energy) dynamical_system.rescale_velo(temperature) if step_number > equilibration_steps: debug("Write at step {0}".format(step_number)) out.write(dynamical_system.atoms) sp_path = '{0:03d}'.format(structure_count) write_filename = '{0}_{1:g}.{2:03d}'.format( system.info['name'], temperature, structure_count) os.mkdir(sp_path) os.chdir(sp_path) castep_write(dynamical_system.atoms, filename=write_filename) espresso_write(dynamical_system.atoms, prefix=write_filename) write_extxyz("{0}.xyz".format(write_filename), dynamical_system.atoms) info("Wrote a configuration {0}.".format(write_filename)) os.chdir('..') structure_count += 1 out.close() os.chdir(base_dir) info("MD Done.")
bulk.set_calculator(pot) ener_per_atom = bulk.get_potential_energy()/len(bulk) surf_cell.set_calculator(pot) surf_ener = surf_cell.get_potential_energy() 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:
class ParamWriter(object): """ Write out configurations to a trajectory and castep files to individual subdirectories. """ def __init__(self, atoms, name, potential, calc_energy=True): """ Initialise the writer with the templating atoms and potential. """ self.atoms = atoms self.name = name self.potential = potential self.calc_energy = calc_energy self.counter = 0 # TODO: check naming self.base_dir = os.getcwd() run_path = '{0}'.format(atoms.info['name']) info("Putting files in {0}.".format(run_path)) os.mkdir(run_path) os.chdir(run_path) trajectory = 'traj_{0}.xyz'.format(atoms.info['name']) self.out = AtomsWriter(trajectory) def write_config(self, params): cell_params = params[:6] # Make a list of 3 item lists atom_params = [self.atoms[0].position] + zip(*[iter(params[6:])] * 3) new_atoms = self.atoms.copy() new_atoms.set_cell([[cell_params[0], 0.0, 0.0], [cell_params[1], cell_params[2], 0.0], [cell_params[3], cell_params[4], cell_params[5]]]) new_atoms.set_positions(atom_params) info("Cell volume: {0}".format(new_atoms.get_volume())) if self.calc_energy: self.potential.calc(new_atoms, energy=True, forces=True, virial=True) # Add to the xyz self.out.write(new_atoms) sp_path = '{0:03d}'.format(self.counter) write_filename = '{0}.{1:03d}'.format(self.atoms.info['name'], self.counter) os.mkdir(sp_path) os.chdir(sp_path) castep_write(new_atoms, filename=write_filename, kpoint_spacing=0.015) info("Wrote a configuration {0}.".format(write_filename)) os.chdir('..') self.counter += 1 def close(self): """ Clean up. """ self.out.close() os.chdir(self.base_dir)