def lammps_ELASTIC(lammps_command, system, potential, symbols, mpi_command=None, strainrange=1e-6, etol=0.0, ftol=0.0, maxiter=100, maxeval=1000, dmax=0.01, pressure_unit='GPa'): """Sets up and runs the ELASTIC example distributed with LAMMPS""" #Get lammps units lammps_units = lmp.style.unit(potential.units) #Define lammps variables lammps_variables = {} lammps_variables['atomman_system_info'] = lmp.atom_data.dump(system, 'init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_pair_info'] = potential.pair_info(symbols) lammps_variables['strainrange'] = strainrange lammps_variables['pressure_unit_scaling'] = uc.get_in_units(uc.set_in_units(1.0, lammps_units['pressure']), pressure_unit) lammps_variables['pressure_unit'] = pressure_unit lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) #Fill in mod.template files with open('init.mod.template') as template_file: template = template_file.read() with open('init.mod', 'w') as in_file: in_file.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) with open('potential.mod.template') as template_file: template = template_file.read() with open('potential.mod', 'w') as in_file: in_file.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) output = lmp.run(lammps_command, 'in.elastic', mpi_command) #Extract output values relaxed = output['LAMMPS-log-thermo-data']['simulation'][0] results = {} results['E_coh'] = uc.set_in_units(relaxed['thermo']['PotEng'][-1], lammps_units['energy']) / system.natoms results['lx'] = uc.set_in_units(relaxed['thermo']['Lx'][-1], lammps_units['length']) results['ly'] = uc.set_in_units(relaxed['thermo']['Ly'][-1], lammps_units['length']) results['lz'] = uc.set_in_units(relaxed['thermo']['Lz'][-1], lammps_units['length']) with open('log.lammps') as log_file: log = log_file.read() start = log.find('print "Elastic Constant C11all = ${C11all} ${cunits}"') lines = log[start+54:].split('\n') for line in lines: terms = line.split() if len(terms) > 0 and terms[0] == 'Elastic': c_term = terms[2][:3] c_value = terms[4] results['c_unit'] = terms[5] results[c_term] = c_value return results
def gb_energy(lammps_command, potential, symbols, alat, axes_1, axes_2, E_coh, mpi_command=None, xshift=0.0, zshift=0.0): """Computes the grain boundary energy using the grain_boundary.in LAMMPS script""" axes_1 = np.asarray(axes_1, dtype=int) axes_2 = np.asarray(axes_2, dtype=int) lx = alat * np.linalg.norm(axes_1[0]) lz = 2 * alat * np.linalg.norm(axes_1[2]) mesh_dir = 'mesh-%.8f-%.8f' %(xshift, zshift) if not os.path.isdir(mesh_dir): os.makedirs(mesh_dir) #Get lammps units lammps_units = lmp.style.unit(potential.units) #Define lammps variables lammps_variables = {} lammps_variables['units'] = potential.units lammps_variables['atom_style'] = potential.atom_style lammps_variables['atomman_pair_info'] = potential.pair_info(symbols) lammps_variables['alat'] = uc.get_in_units(alat, lammps_units['length']) lammps_variables['xsize'] = uc.get_in_units(lx, lammps_units['length']) lammps_variables['zsize'] = uc.get_in_units(lz, lammps_units['length']) lammps_variables['xshift'] = uc.get_in_units(xshift, lammps_units['length']) lammps_variables['zshift'] = uc.get_in_units(zshift, lammps_units['length']) lammps_variables['x_axis_1'] = str(axes_1[0]).strip('[] ') lammps_variables['y_axis_1'] = str(axes_1[1]).strip('[] ') lammps_variables['z_axis_1'] = str(axes_1[2]).strip('[] ') lammps_variables['x_axis_2'] = str(axes_2[0]).strip('[] ') lammps_variables['y_axis_2'] = str(axes_2[1]).strip('[] ') lammps_variables['z_axis_2'] = str(axes_2[2]).strip('[] ') lammps_variables['mesh_dir'] = 'mesh-%.8f-%.8f' %(xshift, zshift) #Fill in mod.template files with open('grain_boundary.template') as template_file: template = template_file.read() lammps_input = os.path.join(mesh_dir, 'grain_boundary.in') with open(lammps_input, 'w') as in_file: in_file.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) output = lmp.run(lammps_command, lammps_input, mpi_command) #Extract output values try: E_total = uc.set_in_units(output.finds('c_eatoms')[-1], lammps_units['energy']) natoms = output.finds('v_natoms')[-1] except: E_total = uc.set_in_units(output.finds('eatoms')[-1], lammps_units['energy']) natoms = output.finds('natoms')[-1] #Compute grain boundary energy E_gb = (E_total - E_coh*natoms) / (lx * lz) return E_gb
def run(self): self.update() self.system.update() dL = dLmps.DataLammps(self.system) dL.genFile() self.create_in() import atomman.lammps as lmp output = lmp.run(self.lammps_exe, self.in_lmp, return_style='object') self.parse_log()
def run(self): self.calls += 1 dL = dLmps.DataLammps(self.settings) dL.genFile() # create data.lamp self.scriptLammps.create_in() # create in.min import atomman.lammps as lmp output = lmp.run(self.lammps_exe, self.in_lmp, return_style='object') self.parse_log()
def energy_check(lammps_command: str, system: am.System, potential: lmp.Potential, mpi_command: Optional[str] = None) -> dict: """ Performs a quick run 0 calculation to evaluate the potential energy of a configuration. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The atomic configuration to evaluate. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. Returns ------- dict Dictionary of results consisting of keys: - **'E_pot'** (*float*) - The per-atom potential energy of the system. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info # Fill in lammps input script template = read_calc_file('iprPy.calculation.energy_check', 'run0.template') script = filltemplate(template, lammps_variables, '<', '>') # Run LAMMPS output = lmp.run(lammps_command, script=script, mpi_command=mpi_command, logfile=None) # Extract output values thermo = output.simulations[-1]['thermo'] results = {} results['E_pot'] = uc.set_in_units(thermo.v_peatom.values[-1], lammps_units['energy']) return results
def ecoh_vs_r(lammps_exe, ucell, potential, symbols, rmin=2.0, rmax=5.0, rsteps=200): """Measure cohesive energy of a crystal as a function of nearest neighbor distance, r0""" #Initial size setup r_a = r_a_ratio(ucell) amin = rmin / r_a amax = rmax / r_a alat0 = (amax + amin) / 2. delta = (amax-amin)/alat0 #Create unit cell with a = alat0 ucell.box_set(a = alat0, b = alat0 * ucell.box.b / ucell.box.a, c = alat0 * ucell.box.c / ucell.box.a, scale=True) #LAMMPS script setup pair_info = potential.pair_info(symbols) system_info = lmp.sys_gen(units = potential.units, atom_style = potential.atom_style, ucell = ucell, size = np.array([[0,3], [0,3], [0,3]], dtype=np.int)) #Write the LAMMPS input file with open('alat.in','w') as script: script.write(alat_script(system_info, pair_info, delta=delta, steps=rsteps)) #Run LAMMPS data = lmp.run(lammps_exe, 'alat.in') #extract thermo data from log output avalues = np.array(data.finds('Lx')) / 3. rvalues = avalues * r_a evalues = np.array(data.finds('peatom')) #Use potential units and atom_style terms to convert values to appropriate length and energy units lmp_units = lmp.style.unit(potential.units) avalues = uc.set_in_units(avalues, lmp_units['length']) rvalues = uc.set_in_units(rvalues, lmp_units['length']) evalues = uc.set_in_units(evalues, lmp_units['energy']) return rvalues, avalues, evalues
def pointdefect(lammps_command, system, potential, point_kwargs, mpi_command=None, etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom')): """ Adds one or more point defects to a system and evaluates the defect formation energy. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. point_kwargs : dict or list of dict One or more dictionaries containing the keyword arguments for the atomman.defect.point() function to generate specific point defect configuration(s). mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. sim_directory : str, optional The path to the directory to perform the simuation in. If not given, will use the current working directory. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'E_coh'** (*float*) - The cohesive energy of the bulk system. - **'E_ptd_f'** (*float*) - The point.defect formation energy. - **'E_total_base'** (*float*) - The total potential energy of the relaxed bulk system. - **'E_total_ptd'** (*float*) - The total potential energy of the relaxed defect system. - **'system_base'** (*atomman.System*) - The relaxed bulk system. - **'system_ptd'** (*atomman.System*) - The relaxed defect system. - **'dumpfile_base'** (*str*) - The filename of the LAMMPS dump file for the relaxed bulk system. - **'dumpfile_ptd'** (*str*) - The filename of the LAMMPS dump file for the relaxed defect system. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='perfect.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = dmax # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'min.template' lammps_script = 'min.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 to relax perfect.dat output = lmp.run(lammps_command, lammps_script, mpi_command) # Extract LAMMPS thermo data. thermo = output.simulations[0]['thermo'] E_total_base = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) E_coh = E_total_base / system.natoms # Rename log file shutil.move('log.lammps', 'min-perfect-log.lammps') # Load relaxed system from dump file and copy old box vectors because # dump files crop the values. last_dump_file = 'atom.' + str(thermo.Step.values[-1]) system_base = am.load('atom_dump', last_dump_file, symbols=system.symbols) system_base.box_set(vects=system.box.vects) system_base.dump('atom_dump', f='perfect.dump') # Add defect(s) system_ptd = deepcopy(system_base) if not isinstance(point_kwargs, (list, tuple)): point_kwargs = [point_kwargs] for pkwargs in point_kwargs: system_ptd = am.defect.point(system_ptd, **pkwargs) # Update lammps variables system_info = system_ptd.dump('atom_data', f='defect.dat', units = potential.units, atom_style = potential.atom_style) lammps_variables['atomman_system_info'] = system_info # Write lammps input script with open(lammps_script, 'w') as f: f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) # Run lammps output = lmp.run(lammps_command, lammps_script, mpi_command) # Extract lammps thermo data thermo = output.simulations[0]['thermo'] E_total_ptd = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) # Rename log file shutil.move('log.lammps', 'min-defect-log.lammps') # Load relaxed system from dump file and copy old vects as # the dump files crop the values last_dump_file = 'atom.'+str(thermo.Step.values[-1]) system_ptd = am.load('atom_dump', last_dump_file, symbols=system_ptd.symbols) system_ptd.box_set(vects=system.box.vects) system_ptd.dump('atom_dump', f='defect.dump') # Compute defect formation energy E_ptd_f = E_total_ptd - E_coh * system_ptd.natoms # Cleanup files for fname in glob.iglob('atom.*'): os.remove(fname) for dumpjsonfile in glob.iglob('*.dump.json'): os.remove(dumpjsonfile) # Return results results_dict = {} results_dict['E_coh'] = E_coh results_dict['E_ptd_f'] = E_ptd_f results_dict['E_total_base'] = E_total_base results_dict['E_total_ptd'] = E_total_ptd results_dict['system_base'] = system_base results_dict['system_ptd'] = system_ptd results_dict['dumpfile_base'] = 'perfect.dump' results_dict['dumpfile_ptd'] = 'defect.dump' return results_dict
def diatom_scan(lammps_command: str, potential: am.lammps.Potential, symbols: list, mpi_command: Optional[str] = None, rmin: float = uc.set_in_units(0.02, 'angstrom'), rmax: float = uc.set_in_units(6.0, 'angstrom'), rsteps: int = 300) -> dict: """ Performs a diatom energy scan over a range of interatomic spaces, r. Parameters ---------- lammps_command :str Command for running LAMMPS. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. symbols : list The potential symbols associated with the two atoms in the diatom. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. rmin : float, optional The minimum r spacing to use (default value is 0.02 angstroms). rmax : float, optional The maximum r spacing to use (default value is 6.0 angstroms). rsteps : int, optional The number of r spacing steps to evaluate (default value is 300). Returns ------- dict Dictionary of results consisting of keys: - **'r_values'** (*numpy.array of float*) - All interatomic spacings, r, explored. - **'energy_values'** (*numpy.array of float*) - The computed potential energies for each r value. """ # Build lists of values r_values = np.linspace(rmin, rmax, rsteps) energy_values = np.empty(rsteps) # Define atype based on symbols symbols = aslist(symbols) if len(symbols) == 1: atype = [1, 1] elif len(symbols) == 2: atype = [1, 2] else: raise ValueError('symbols must have one or two values') # Initialize system (will shift second atom's position later...) box = am.Box.cubic(a=rmax + 1) atoms = am.Atoms(atype=atype, pos=[[0.1, 0.1, 0.1], [0.1, 0.1, 0.1]]) system = am.System(atoms=atoms, box=box, pbc=[False, False, False], symbols=symbols) # Add charges if required if potential.atom_style == 'charge': system.atoms.prop_atype('charge', potential.charges(system.symbols)) # Get lammps units lammps_units = lmp.style.unit(potential.units) # Define lammps variables lammps_variables = {} # Loop over values for i in range(rsteps): # Shift second atom's x position system.atoms.pos[1] = np.array([0.1 + r_values[i], 0.1, 0.1]) # Save configuration system_info = system.dump('atom_data', f='diatom.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info # Write lammps input script lammps_script = 'run0.in' template = read_calc_file('iprPy.calculation.diatom_scan', 'run0.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run lammps and extract data try: output = lmp.run(lammps_command, script_name=lammps_script, mpi_command=mpi_command) except: energy_values[i] = np.nan else: energy = output.simulations[0]['thermo'].PotEng.values[-1] energy_values[i] = uc.set_in_units(energy, lammps_units['energy']) if len(energy_values[np.isfinite(energy_values)]) == 0: raise ValueError( 'All LAMMPS runs failed. Potential likely invalid or incompatible.' ) # Collect results results_dict = {} results_dict['r_values'] = r_values results_dict['energy_values'] = energy_values return results_dict
def relax_dynamic(lammps_command, system, potential, mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0, p_xy=0.0, p_xz=0.0, p_yz=0.0, temperature=0.0, integrator=None, runsteps=220000, thermosteps=100, dumpsteps=None, equilsteps=20000, randomseed=None): """ Performs a full dynamic relax on a given system at the given temperature to the specified pressure state. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. symbols : list of str The list of element-model symbols for the Potential that correspond to system's atypes. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. p_xx : float, optional The value to relax the x tensile pressure component to (default is 0.0). p_yy : float, optional The value to relax the y tensile pressure component to (default is 0.0). p_zz : float, optional The value to relax the z tensile pressure component to (default is 0.0). temperature : float, optional The temperature to relax at (default is 0.0). runsteps : int, optional The number of integration steps to perform (default is 220000). integrator : str or None, optional The integration method to use. Options are 'npt', 'nvt', 'nph', 'nve', 'nve+l', 'nph+l'. The +l options use Langevin thermostat. (Default is None, which will use 'nph+l' for temperature == 0, and 'npt' otherwise.) thermosteps : int, optional Thermo values will be reported every this many steps (default is 100). dumpsteps : int or None, optional Dump files will be saved every this many steps (default is None, which sets dumpsteps equal to runsteps). equilsteps : int, optional The number of timesteps at the beginning of the simulation to exclude when computing average values (default is 20000). randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities and with the Langevin thermostat. (Default is None which will select a random int between 1 and 900000000.) Returns ------- dict Dictionary of results consisting of keys: - **'relaxed_system'** (*float*) - The relaxed system. - **'E_coh'** (*float*) - The mean measured cohesive energy. - **'measured_pxx'** (*float*) - The measured x tensile pressure of the relaxed system. - **'measured_pyy'** (*float*) - The measured y tensile pressure of the relaxed system. - **'measured_pzz'** (*float*) - The measured z tensile pressure of the relaxed system. - **'measured_pxy'** (*float*) - The measured xy shear pressure of the relaxed system. - **'measured_pxz'** (*float*) - The measured xz shear pressure of the relaxed system. - **'measured_pyz'** (*float*) - The measured yz shear pressure of the relaxed system. - **'temp'** (*float*) - The mean measured temperature. - **'E_coh_std'** (*float*) - The standard deviation in the measured cohesive energy values. - **'measured_pxx_std'** (*float*) - The standard deviation in the measured x tensile pressure of the relaxed system. - **'measured_pyy_std'** (*float*) - The standard deviation in the measured y tensile pressure of the relaxed system. - **'measured_pzz_std'** (*float*) - The standard deviation in the measured z tensile pressure of the relaxed system. - **'measured_pxy_std'** (*float*) - The standard deviation in the measured xy shear pressure of the relaxed system. - **'measured_pxz_std'** (*float*) - The standard deviation in the measured xz shear pressure of the relaxed system. - **'measured_pyz_std'** (*float*) - The standard deviation in the measured yz shear pressure of the relaxed system. - **'temp_std'** (*float*) - The standard deviation in the measured temperature values. """ try: # Get script's location if __file__ exists script_dir = Path(__file__).parent except: # Use cwd otherwise script_dir = Path.cwd() # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Handle default values if dumpsteps is None: dumpsteps = runsteps # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', potential=potential, return_pair_info=True) lammps_variables['atomman_system_pair_info'] = system_info integ_info = integrator_info(integrator=integrator, p_xx=p_xx, p_yy=p_yy, p_zz=p_zz, p_xy=p_xy, p_xz=p_xz, p_yz=p_yz, temperature=temperature, randomseed=randomseed, units=potential.units) lammps_variables['integrator_info'] = integ_info lammps_variables['thermosteps'] = thermosteps lammps_variables['runsteps'] = runsteps lammps_variables['dumpsteps'] = dumpsteps # Set compute stress/atom based on LAMMPS version if lammps_date < datetime.date(2014, 2, 12): lammps_variables['stressterm'] = '' else: lammps_variables['stressterm'] = 'NULL' # Set dump_keys based on atom_style if potential.atom_style in ['charge']: lammps_variables['dump_keys'] = 'id type q xu yu zu c_pe c_ke &\n' lammps_variables['dump_keys'] += 'c_stress[1] c_stress[2] c_stress[3] c_stress[4] c_stress[5] c_stress[6]' else: lammps_variables['dump_keys'] = 'id type xu yu zu c_pe c_ke &\n' lammps_variables['dump_keys'] += 'c_stress[1] c_stress[2] c_stress[3] c_stress[4] c_stress[5] c_stress[6]' # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): if potential.atom_style in ['charge']: lammps_variables['dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = Path(script_dir, 'full_relax.template') lammps_script = 'full_relax.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, mpi_command) # Extract LAMMPS thermo data. results = {} thermo = output.simulations[0]['thermo'] results['dumpfile_initial'] = '0.dump' results['symbols_initial'] = system.symbols # Load relaxed system from dump file last_dump_file = str(thermo.Step.values[-1])+'.dump' results['dumpfile_final'] = last_dump_file system = am.load('atom_dump', last_dump_file, symbols=system.symbols) results['symbols_final'] = system.symbols # Only consider values where Step >= equilsteps thermo = thermo[thermo.Step >= equilsteps] results['nsamples'] = len(thermo) # Get cohesive energy estimates natoms = system.natoms results['E_coh'] = uc.set_in_units(thermo.PotEng.mean() / natoms, lammps_units['energy']) results['E_coh_std'] = uc.set_in_units(thermo.PotEng.std() / natoms, lammps_units['energy']) results['lx'] = uc.set_in_units(thermo.Lx.mean(), lammps_units['length']) results['lx_std'] = uc.set_in_units(thermo.Lx.std(), lammps_units['length']) results['ly'] = uc.set_in_units(thermo.Ly.mean(), lammps_units['length']) results['ly_std'] = uc.set_in_units(thermo.Ly.std(), lammps_units['length']) results['lz'] = uc.set_in_units(thermo.Lz.mean(), lammps_units['length']) results['lz_std'] = uc.set_in_units(thermo.Lz.std(), lammps_units['length']) results['xy'] = uc.set_in_units(thermo.Xy.mean(), lammps_units['length']) results['xy_std'] = uc.set_in_units(thermo.Xy.std(), lammps_units['length']) results['xz'] = uc.set_in_units(thermo.Xz.mean(), lammps_units['length']) results['xz_std'] = uc.set_in_units(thermo.Xz.std(), lammps_units['length']) results['yz'] = uc.set_in_units(thermo.Yz.mean(), lammps_units['length']) results['yz_std'] = uc.set_in_units(thermo.Yz.std(), lammps_units['length']) results['measured_pxx'] = uc.set_in_units(thermo.Pxx.mean(), lammps_units['pressure']) results['measured_pxx_std'] = uc.set_in_units(thermo.Pxx.std(), lammps_units['pressure']) results['measured_pyy'] = uc.set_in_units(thermo.Pyy.mean(), lammps_units['pressure']) results['measured_pyy_std'] = uc.set_in_units(thermo.Pyy.std(), lammps_units['pressure']) results['measured_pzz'] = uc.set_in_units(thermo.Pzz.mean(), lammps_units['pressure']) results['measured_pzz_std'] = uc.set_in_units(thermo.Pzz.std(), lammps_units['pressure']) results['measured_pxy'] = uc.set_in_units(thermo.Pxy.mean(), lammps_units['pressure']) results['measured_pxy_std'] = uc.set_in_units(thermo.Pxy.std(), lammps_units['pressure']) results['measured_pxz'] = uc.set_in_units(thermo.Pxz.mean(), lammps_units['pressure']) results['measured_pxz_std'] = uc.set_in_units(thermo.Pxz.std(), lammps_units['pressure']) results['measured_pyz'] = uc.set_in_units(thermo.Pyz.mean(), lammps_units['pressure']) results['measured_pyz_std'] = uc.set_in_units(thermo.Pyz.std(), lammps_units['pressure']) results['temp'] = thermo.Temp.mean() results['temp_std'] = thermo.Temp.std() return results
def calc_cij(lammps_command, system, potential, mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0, strainrange=1e-6, cycle=0): """ Runs cij.in LAMMPS script to evaluate Cij, and E_coh of the current system, and define a new system with updated box dimensions to test. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. strainrange : float, optional The small strain value to apply when calculating the elastic constants (default is 1e-6). p_xx : float, optional The value to relax the x tensile pressure component to (default is 0.0). p_yy : float, optional The value to relax the y tensile pressure component to (default is 0.0). p_zz : float, optional The value to relax the z tensile pressure component to (default is 0.0). cycle : int, optional Indicates the iteration cycle of quick_a_Cij(). This is used to uniquely save the LAMMPS input and output files. Returns ------- dict Dictionary of results consisting of keys: - **'E_coh'** (*float*) - The cohesive energy of the supplied system. - **'stress'** (*numpy.array*) - The measured stress state of the supplied system. - **'C_elastic'** (*atomman.ElasticConstants*) - The supplied system's elastic constants. - **'system_new'** (*atomman.System*) - System with updated box dimensions. Raises ------ RuntimeError If any of the new box dimensions are less than zero. """ try: # Get script's location if __file__ exists script_dir = Path(__file__).parent except: # Use cwd otherwise script_dir = Path.cwd() # Get lammps units lammps_units = lmp.style.unit(potential.units) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init' + str(cycle) + '.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['delta'] = strainrange lammps_variables['steps'] = 2 # Write lammps input script template_file = Path(script_dir, '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, mpi_command=mpi_command, return_style='model') 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']) pe = uc.set_in_units( np.array(output.finds('PotEng')) / system.natoms, 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 range(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 range(6): for j in range(i): cij[i, j] = cij[j, i] = (cij[i, j] + cij[j, i]) / 2 C = am.ElasticConstants(Cij=cij) S = C.Sij # 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') system_new = deepcopy(system) system_new.box_set(a=new_a, b=new_b, c=new_c, scale=True) results_dict = {} results_dict['E_coh'] = pe[0] results_dict['system_new'] = system_new results_dict['measured_pxx'] = pxx[0] results_dict['measured_pyy'] = pyy[0] results_dict['measured_pzz'] = pzz[0] results_dict['measured_pxy'] = pxy[0] results_dict['measured_pxz'] = pxz[0] results_dict['measured_pyz'] = pyz[0] return results_dict
def pointdiffusion(lammps_command, system, potential, point_kwargs, mpi_command=None, temperature=300, runsteps=200000, thermosteps=None, dumpsteps=0, equilsteps=20000, randomseed=None): """ Evaluates the diffusion rate of a point defect at a given temperature. This method will run two simulations: an NVT run at the specified temperature to equilibrate the system, then an NVE run to measure the defect's diffusion rate. The diffusion rate is evaluated using the mean squared displacement of all atoms in the system, and using the assumption that diffusion is only due to the added defect(s). Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. point_kwargs : dict or list of dict One or more dictionaries containing the keyword arguments for the atomman.defect.point() function to generate specific point defect configuration(s). mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. temperature : float, optional The temperature to run at (default is 300.0). runsteps : int, optional The number of integration steps to perform (default is 200000). thermosteps : int, optional Thermo values will be reported every this many steps (default is 100). dumpsteps : int or None, optional Dump files will be saved every this many steps (default is 0, which does not output dump files). equilsteps : int, optional The number of timesteps at the beginning of the simulation to exclude when computing average values (default is 20000). randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities and with the Langevin thermostat. (Default is None which will select a random int between 1 and 900000000.) Returns ------- dict Dictionary of results consisting of keys: - **'natoms'** (*int*) - The number of atoms in the system. - **'temp'** (*float*) - The mean measured temperature. - **'pxx'** (*float*) - The mean measured normal xx pressure. - **'pyy'** (*float*) - The mean measured normal yy pressure. - **'pzz'** (*float*) - The mean measured normal zz pressure. - **'Epot'** (*numpy.array*) - The mean measured total potential energy. - **'temp_std'** (*float*) - The standard deviation in the measured temperature values. - **'pxx_std'** (*float*) - The standard deviation in the measured normal xx pressure values. - **'pyy_std'** (*float*) - The standard deviation in the measured normal yy pressure values. - **'pzz_std'** (*float*) - The standard deviation in the measured normal zz pressure values. - **'Epot_std'** (*float*) - The standard deviation in the measured total potential energy values. - **'dx'** (*float*) - The computed diffusion constant along the x-direction. - **'dy'** (*float*) - The computed diffusion constant along the y-direction. - **'dz'** (*float*) - The computed diffusion constant along the y-direction. - **'d'** (*float*) - The total computed diffusion constant. """ try: # Get script's location if __file__ exists script_dir = Path(__file__).parent except: # Use cwd otherwise script_dir = Path.cwd() # Add defect(s) to the initially perfect system if not isinstance(point_kwargs, (list, tuple)): point_kwargs = [point_kwargs] for pkwargs in point_kwargs: system = am.defect.point(system, **pkwargs) # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Check that temperature is greater than zero if temperature <= 0.0: raise ValueError('Temperature must be greater than zero') # Handle default values if thermosteps is None: thermosteps = runsteps // 1000 if thermosteps == 0: thermosteps = 1 if dumpsteps is None: dumpsteps = runsteps if randomseed is None: randomseed = random.randint(1, 900000000) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='initial.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['temperature'] = temperature lammps_variables['runsteps'] = runsteps lammps_variables['equilsteps'] = equilsteps lammps_variables['thermosteps'] = thermosteps lammps_variables['dumpsteps'] = dumpsteps lammps_variables['randomseed'] = randomseed lammps_variables['timestep'] = lmp.style.timestep(potential.units) # Set dump_info if dumpsteps == 0: lammps_variables['dump_info'] = '' else: lammps_variables['dump_info'] = '\n'.join([ '', '# Define dump files', 'dump dumpit all custom ${dumpsteps} *.dump id type x y z c_peatom', 'dump_modify dumpit format <dump_modify_format>', '', ]) # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = Path(script_dir, 'diffusion.template') lammps_script = 'diffusion.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, 'diffusion.in', mpi_command) # Extract LAMMPS thermo data. thermo = output.simulations[1]['thermo'] temps = thermo.Temp.values pxxs = uc.set_in_units(thermo.Pxx.values, lammps_units['pressure']) pyys = uc.set_in_units(thermo.Pyy.values, lammps_units['pressure']) pzzs = uc.set_in_units(thermo.Pzz.values, lammps_units['pressure']) potengs = uc.set_in_units(thermo.PotEng.values, lammps_units['energy']) steps = thermo.Step.values # Read user-defined thermo data if output.lammps_date < datetime.date(2016, 8, 1): msd_x = uc.set_in_units(thermo['msd[1]'].values, lammps_units['length'] + '^2') msd_y = uc.set_in_units(thermo['msd[2]'].values, lammps_units['length'] + '^2') msd_z = uc.set_in_units(thermo['msd[3]'].values, lammps_units['length'] + '^2') msd = uc.set_in_units(thermo['msd[4]'].values, lammps_units['length'] + '^2') else: msd_x = uc.set_in_units(thermo['c_msd[1]'].values, lammps_units['length'] + '^2') msd_y = uc.set_in_units(thermo['c_msd[2]'].values, lammps_units['length'] + '^2') msd_z = uc.set_in_units(thermo['c_msd[3]'].values, lammps_units['length'] + '^2') msd = uc.set_in_units(thermo['c_msd[4]'].values, lammps_units['length'] + '^2') # Initialize results dict results = {} results['natoms'] = system.natoms # Get mean and std for temperature, pressure, and potential energy results['temp'] = np.mean(temps) results['temp_std'] = np.std(temps) results['pxx'] = np.mean(pxxs) results['pxx_std'] = np.std(pxxs) results['pyy'] = np.mean(pyys) results['pyy_std'] = np.std(pyys) results['pzz'] = np.mean(pzzs) results['pzz_std'] = np.std(pzzs) results['Epot'] = np.mean(potengs) results['Epot_std'] = np.std(potengs) # Convert steps to times times = steps * uc.set_in_units(lammps_variables['timestep'], lammps_units['time']) # Estimate diffusion rates # MSD_ptd = natoms * MSD_atoms (if one defect in system) # MSD = 2 * ndim * D * t --> D = MSD/t / (2 * ndim) mx = np.polyfit(times, system.natoms * msd_x, 1)[0] my = np.polyfit(times, system.natoms * msd_y, 1)[0] mz = np.polyfit(times, system.natoms * msd_z, 1)[0] m = np.polyfit(times, system.natoms * msd, 1)[0] results['dx'] = mx / 2 results['dy'] = my / 2 results['dz'] = mz / 2 results['d'] = m / 6 return results
def stackingfaultpoint(lammps_command, system, potential, mpi_command=None, sim_directory=None, cutboxvector='c', faultpos=0.5, faultshift=[0.0, 0.0, 0.0], etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom'), lammps_date=None): """ Perform a stacking fault relaxation simulation for a single faultshift. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. sim_directory : str, optional The path to the directory to perform the simuation in. If not given, will use the current working directory. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). cutboxvector : str, optional Indicates which of the three system box vectors, 'a', 'b', or 'c', to cut with a non-periodic boundary (default is 'c'). faultpos : float, optional The fractional position along the cutboxvector where the stacking fault plane will be placed (default is 0.5). faultshift : list of float, optional The vector shift to apply to all atoms above the fault plane defined by faultpos (default is [0,0,0], i.e. no shift applied). lammps_date : datetime.date or None, optional The date version of the LAMMPS executable. If None, will be identified from the lammps_command (default is None). Returns ------- dict Dictionary of results consisting of keys: - **'logfile'** (*str*) - The filename of the LAMMPS log file. - **'dumpfile'** (*str*) - The filename of the LAMMPS dump file of the relaxed system. - **'system'** (*atomman.System*) - The relaxed system. - **'A_fault'** (*float*) - The area of the fault surface. - **'E_total'** (*float*) - The total potential energy of the relaxed system. - **'disp'** (*float*) - The center of mass difference between atoms above and below the fault plane in the cutboxvector direction. Raises ------ ValueError For invalid cutboxvectors. """ # Set options based on cutboxvector if cutboxvector == 'a': # Assert system is compatible with planeaxis value if system.box.xy != 0.0 or system.box.xz != 0.0: raise ValueError( "box tilts xy and xz must be 0 for cutboxvector='a'") # Specify cutindex cutindex = 0 # Identify atoms above fault faultpos = system.box.xlo + system.box.lx * faultpos abovefault = system.atoms.pos[:, cutindex] > (faultpos) # Compute fault area faultarea = np.linalg.norm(np.cross(system.box.bvect, system.box.cvect)) # Give correct LAMMPS fix setforce command fix_cut_setforce = 'fix cut all setforce NULL 0 0' elif cutboxvector == 'b': # Assert system is compatible with planeaxis value if system.box.yz != 0.0: raise ValueError("box tilt yz must be 0 for cutboxvector='b'") # Specify cutindex cutindex = 1 # Identify atoms above fault faultpos = system.box.ylo + system.box.ly * faultpos abovefault = system.atoms.pos[:, cutindex] > (faultpos) # Compute fault area faultarea = np.linalg.norm(np.cross(system.box.avect, system.box.cvect)) # Give correct LAMMPS fix setforce command fix_cut_setforce = 'fix cut all setforce 0 NULL 0' elif cutboxvector == 'c': # Specify cutindex cutindex = 2 # Identify atoms above fault faultpos = system.box.zlo + system.box.lz * faultpos abovefault = system.atoms.pos[:, cutindex] > (faultpos) # Compute fault area faultarea = np.linalg.norm(np.cross(system.box.avect, system.box.bvect)) # Give correct LAMMPS fix setforce command fix_cut_setforce = 'fix cut all setforce 0 0 NULL' else: raise ValueError('Invalid cutboxvector') # Assert faultshift is in cut plane if faultshift[cutindex] != 0.0: raise ValueError('faultshift must be in cut plane') # Generate stacking fault system by shifting atoms above the fault sfsystem = deepcopy(system) sfsystem.pbc = [True, True, True] sfsystem.pbc[cutindex] = False sfsystem.atoms.pos[abovefault] += faultshift sfsystem.wrap() if sim_directory is not None: # Create sim_directory if it doesn't exist if not os.path.isdir(sim_directory): os.mkdir(sim_directory) # Add '/' to end of sim_directory string if needed if sim_directory[-1] != '/': sim_directory = sim_directory + '/' else: # Set sim_directory if is None sim_directory = '' # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date if lammps_date is None: lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = sfsystem.dump('atom_data', f=os.path.join(sim_directory, 'system.dat'), units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info( sfsystem.symbols) lammps_variables['fix_cut_setforce'] = fix_cut_setforce lammps_variables['sim_directory'] = sim_directory lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%i %i %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'sfmin.template' lammps_script = os.path.join(sim_directory, 'sfmin.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, mpi_command, logfile=os.path.join(sim_directory, 'log.lammps')) # Extract output values thermo = output.simulations[-1]['thermo'] logfile = os.path.join(sim_directory, 'log.lammps') dumpfile = os.path.join(sim_directory, '%i.dump' % thermo.Step.values[-1]) E_total = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) # Load relaxed system sfsystem = am.load('atom_dump', dumpfile, symbols=sfsystem.symbols) # Find center of mass difference in top/bottom planes disp = (sfsystem.atoms.pos[abovefault, cutindex].mean() - sfsystem.atoms.pos[~abovefault, cutindex].mean()) # Return results results_dict = {} results_dict['logfile'] = logfile results_dict['dumpfile'] = dumpfile results_dict['system'] = sfsystem results_dict['A_fault'] = faultarea results_dict['E_total'] = E_total results_dict['disp'] = disp return results_dict
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 relax_system(lammps_command, system, potential, mpi_command=None, etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom')): """ Sets up and runs the min.in LAMMPS script for performing an energy/force minimization to relax a system. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'logfile'** (*str*) - The name of the LAMMPS log file. - **'initialdatafile'** (*str*) - The name of the LAMMPS data file used to import an inital configuration. - **'initialdumpfile'** (*str*) - The name of the LAMMPS dump file corresponding to the inital configuration. - **'finaldumpfile'** (*str*) - The name of the LAMMPS dump file corresponding to the relaxed configuration. - **'potentialenergy'** (*float*) - The total potential energy of the relaxed system. """ try: # Get script's location if __file__ exists script_dir = Path(__file__).parent except: # Use cwd otherwise script_dir = Path.cwd() # Ensure all atoms are within the system's box system.wrap() # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} # Generate system and pair info system_info = system.dump('atom_data', f='system.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) # Pass in run parameters lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%i %i %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = Path(script_dir, 'min.template') lammps_script = 'min.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, mpi_command) # Extract output values thermo = output.simulations[-1]['thermo'] results = {} results['logfile'] = 'log.lammps' results['initialdatafile'] = 'system.dat' results['initialdumpfile'] = 'atom.0' results['finaldumpfile'] = 'atom.%i' % thermo.Step.values[-1] results['potentialenergy'] = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) return results
def stackingfaultrelax(lammps_command, system, potential, mpi_command=None, sim_directory=None, cutboxvector='c', etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom'), lammps_date=None): """ Perform a stacking fault relaxation simulation for a single faultshift. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system containing a stacking fault. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. sim_directory : str, optional The path to the directory to perform the simulation in. If not given, will use the current working directory. cutboxvector : str, optional Indicates which of the three system box vectors, 'a', 'b', or 'c', has the non-periodic boundary (default is 'c'). Fault plane normal is defined by the cross of the other two box vectors. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). lammps_date : datetime.date or None, optional The date version of the LAMMPS executable. If None, will be identified from the lammps_command (default is None). Returns ------- dict Dictionary of results consisting of keys: - **'logfile'** (*str*) - The filename of the LAMMPS log file. - **'dumpfile'** (*str*) - The filename of the LAMMPS dump file of the relaxed system. - **'system'** (*atomman.System*) - The relaxed system. - **'E_total'** (*float*) - The total potential energy of the relaxed system. Raises ------ ValueError For invalid cutboxvectors. """ # Get script's location script_dir = Path(__file__).parent # Give correct LAMMPS fix setforce command if cutboxvector == 'a': fix_cut_setforce = 'fix cut all setforce NULL 0 0' elif cutboxvector == 'b': fix_cut_setforce = 'fix cut all setforce 0 NULL 0' elif cutboxvector == 'c': fix_cut_setforce = 'fix cut all setforce 0 0 NULL' else: raise ValueError('Invalid cutboxvector') if sim_directory is not None: # Create sim_directory if it doesn't exist sim_directory = Path(sim_directory) if not sim_directory.is_dir(): sim_directory.mkdir() sim_directory = sim_directory.as_posix()+'/' else: # Set sim_directory if is None sim_directory = '' # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date if lammps_date is None: lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f=Path(sim_directory, 'system.dat').as_posix(), units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['fix_cut_setforce'] = fix_cut_setforce lammps_variables['sim_directory'] = sim_directory lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%i %i %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = Path(script_dir, 'sfmin.template') lammps_script = Path(sim_directory, 'sfmin.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.as_posix(), mpi_command, logfile=Path(sim_directory, 'log.lammps').as_posix()) # Extract output values thermo = output.simulations[-1]['thermo'] logfile = Path(sim_directory, 'log.lammps').as_posix() dumpfile = Path(sim_directory, '%i.dump' % thermo.Step.values[-1]).as_posix() E_total = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) # Load relaxed system system = am.load('atom_dump', dumpfile, symbols=system.symbols) # Return results results_dict = {} results_dict['logfile'] = logfile results_dict['dumpfile'] = dumpfile results_dict['system'] = system results_dict['E_total'] = E_total return results_dict
def stackingfaultpoint(lammps_command, system, potential, mpi_command=None, sim_directory=None, cutboxvector='c', faultpos=0.5, faultshift=[0.0, 0.0, 0.0], etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom'), lammps_date=None): """ Perform a stacking fault relaxation simulation for a single faultshift. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. sim_directory : str, optional The path to the directory to perform the simuation in. If not given, will use the current working directory. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). cutboxvector : str, optional Indicates which of the three system box vectors, 'a', 'b', or 'c', to cut with a non-periodic boundary (default is 'c'). faultpos : float, optional The fractional position along the cutboxvector where the stacking fault plane will be placed (default is 0.5). faultshift : list of float, optional The vector shift to apply to all atoms above the fault plane defined by faultpos (default is [0,0,0], i.e. no shift applied). lammps_date : datetime.date or None, optional The date version of the LAMMPS executable. If None, will be identified from the lammps_command (default is None). Returns ------- dict Dictionary of results consisting of keys: - **'logfile'** (*str*) - The filename of the LAMMPS log file. - **'dumpfile'** (*str*) - The filename of the LAMMPS dump file of the relaxed system. - **'system'** (*atomman.System*) - The relaxed system. - **'A_fault'** (*float*) - The area of the fault surface. - **'E_total'** (*float*) - The total potential energy of the relaxed system. - **'disp'** (*float*) - The center of mass difference between atoms above and below the fault plane in the cutboxvector direction. Raises ------ ValueError For invalid cutboxvectors. """ # Set options based on cutboxvector if cutboxvector == 'a': # Assert system is compatible with planeaxis value if system.box.xy != 0.0 or system.box.xz != 0.0: raise ValueError("box tilts xy and xz must be 0 for cutboxvector='a'") # Specify cutindex cutindex = 0 # Identify atoms above fault faultpos = system.box.xlo + system.box.lx * faultpos abovefault = system.atoms.pos[:, cutindex] > (faultpos) # Compute fault area faultarea = np.linalg.norm(np.cross(system.box.bvect, system.box.cvect)) # Give correct LAMMPS fix setforce command fix_cut_setforce = 'fix cut all setforce NULL 0 0' elif cutboxvector == 'b': # Assert system is compatible with planeaxis value if system.box.yz != 0.0: raise ValueError("box tilt yz must be 0 for cutboxvector='b'") # Specify cutindex cutindex = 1 # Identify atoms above fault faultpos = system.box.ylo + system.box.ly * faultpos abovefault = system.atoms.pos[:, cutindex] > (faultpos) # Compute fault area faultarea = np.linalg.norm(np.cross(system.box.avect, system.box.cvect)) # Give correct LAMMPS fix setforce command fix_cut_setforce = 'fix cut all setforce 0 NULL 0' elif cutboxvector == 'c': # Specify cutindex cutindex = 2 # Identify atoms above fault faultpos = system.box.zlo + system.box.lz * faultpos abovefault = system.atoms.pos[:, cutindex] > (faultpos) # Compute fault area faultarea = np.linalg.norm(np.cross(system.box.avect, system.box.bvect)) # Give correct LAMMPS fix setforce command fix_cut_setforce = 'fix cut all setforce 0 0 NULL' else: raise ValueError('Invalid cutboxvector') # Assert faultshift is in cut plane if faultshift[cutindex] != 0.0: raise ValueError('faultshift must be in cut plane') # Generate stacking fault system by shifting atoms above the fault sfsystem = deepcopy(system) sfsystem.pbc = [True, True, True] sfsystem.pbc[cutindex] = False sfsystem.atoms.pos[abovefault] += faultshift sfsystem.wrap() if sim_directory is not None: # Create sim_directory if it doesn't exist if not os.path.isdir(sim_directory): os.mkdir(sim_directory) # Add '/' to end of sim_directory string if needed if sim_directory[-1] != '/': sim_directory = sim_directory + '/' else: # Set sim_directory if is None sim_directory = '' # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date if lammps_date is None: lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = sfsystem.dump('atom_data', f=os.path.join(sim_directory, 'system.dat'), units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(sfsystem.symbols) lammps_variables['fix_cut_setforce'] = fix_cut_setforce lammps_variables['sim_directory'] = sim_directory lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%i %i %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'sfmin.template' lammps_script = os.path.join(sim_directory, 'sfmin.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, mpi_command, logfile=os.path.join(sim_directory, 'log.lammps')) # Extract output values thermo = output.simulations[-1]['thermo'] logfile = os.path.join(sim_directory, 'log.lammps') dumpfile = os.path.join(sim_directory, '%i.dump' % thermo.Step.values[-1]) E_total = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) #Load relaxed system sfsystem = am.load('atom_dump', dumpfile, symbols=sfsystem.symbols) # Find center of mass difference in top/bottom planes disp = (sfsystem.atoms.pos[abovefault, cutindex].mean() - sfsystem.atoms.pos[~abovefault, cutindex].mean()) # Return results results_dict = {} results_dict['logfile'] = logfile results_dict['dumpfile'] = dumpfile results_dict['system'] = sfsystem results_dict['A_fault'] = faultarea results_dict['E_total'] = E_total results_dict['disp'] = disp return results_dict
def pointdiffusion(lammps_command, system, potential, point_kwargs, mpi_command=None, temperature=300, runsteps=200000, thermosteps=None, dumpsteps=0, equilsteps=20000, randomseed=None): """ Evaluates the diffusion rate of a point defect at a given temperature. This method will run two simulations: an NVT run at the specified temperature to equilibrate the system, then an NVE run to measure the defect's diffusion rate. The diffusion rate is evaluated using the mean squared displacement of all atoms in the system, and using the assumption that diffusion is only due to the added defect(s). Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. point_kwargs : dict or list of dict One or more dictionaries containing the keyword arguments for the atomman.defect.point() function to generate specific point defect configuration(s). mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. temperature : float, optional The temperature to run at (default is 300.0). runsteps : int, optional The number of integration steps to perform (default is 200000). thermosteps : int, optional Thermo values will be reported every this many steps (default is 100). dumpsteps : int or None, optional Dump files will be saved every this many steps (default is 0, which does not output dump files). equilsteps : int, optional The number of timesteps at the beginning of the simulation to exclude when computing average values (default is 20000). randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities and with the Langevin thermostat. (Default is None which will select a random int between 1 and 900000000.) Returns ------- dict Dictionary of results consisting of keys: - **'natoms'** (*int*) - The number of atoms in the system. - **'temp'** (*float*) - The mean measured temperature. - **'pxx'** (*float*) - The mean measured normal xx pressure. - **'pyy'** (*float*) - The mean measured normal yy pressure. - **'pzz'** (*float*) - The mean measured normal zz pressure. - **'Epot'** (*numpy.array*) - The mean measured total potential energy. - **'temp_std'** (*float*) - The standard deviation in the measured temperature values. - **'pxx_std'** (*float*) - The standard deviation in the measured normal xx pressure values. - **'pyy_std'** (*float*) - The standard deviation in the measured normal yy pressure values. - **'pzz_std'** (*float*) - The standard deviation in the measured normal zz pressure values. - **'Epot_std'** (*float*) - The standard deviation in the measured total potential energy values. - **'dx'** (*float*) - The computed diffusion constant along the x-direction. - **'dy'** (*float*) - The computed diffusion constant along the y-direction. - **'dz'** (*float*) - The computed diffusion constant along the y-direction. - **'d'** (*float*) - The total computed diffusion constant. """ # Add defect(s) to the initially perfect system if not isinstance(point_kwargs, (list, tuple)): point_kwargs = [point_kwargs] for pkwargs in point_kwargs: system = am.defect.point(system, **pkwargs) # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Check that temperature is greater than zero if temperature <= 0.0: raise ValueError('Temperature must be greater than zero') # Handle default values if thermosteps is None: thermosteps = runsteps // 1000 if thermosteps == 0: thermosteps = 1 if dumpsteps is None: dumpsteps = runsteps if randomseed is None: randomseed = random.randint(1, 900000000) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='initial.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['temperature'] = temperature lammps_variables['runsteps'] = runsteps lammps_variables['equilsteps'] = equilsteps lammps_variables['thermosteps'] = thermosteps lammps_variables['dumpsteps'] = dumpsteps lammps_variables['randomseed'] = randomseed lammps_variables['timestep'] = lmp.style.timestep(potential.units) # Set dump_info if dumpsteps == 0: lammps_variables['dump_info'] = '' else: lammps_variables['dump_info'] = '\n'.join([ '', '# Define dump files', 'dump dumpit all custom ${dumpsteps} *.dump id type x y z c_peatom', 'dump_modify dumpit format <dump_modify_format>', '', ]) # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'diffusion.template' lammps_script = 'diffusion.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, 'diffusion.in', mpi_command) # Extract LAMMPS thermo data. thermo = output.simulations[1]['thermo'] temps = thermo.Temp.values pxxs = uc.set_in_units(thermo.Pxx.values, lammps_units['pressure']) pyys = uc.set_in_units(thermo.Pyy.values, lammps_units['pressure']) pzzs = uc.set_in_units(thermo.Pzz.values, lammps_units['pressure']) potengs = uc.set_in_units(thermo.PotEng.values, lammps_units['energy']) steps = thermo.Step.values # Read user-defined thermo data if output.lammps_date < datetime.date(2016, 8, 1): msd_x = uc.set_in_units(thermo['msd[1]'].values, lammps_units['length']+'^2') msd_y = uc.set_in_units(thermo['msd[2]'].values, lammps_units['length']+'^2') msd_z = uc.set_in_units(thermo['msd[3]'].values, lammps_units['length']+'^2') msd = uc.set_in_units(thermo['msd[4]'].values, lammps_units['length']+'^2') else: msd_x = uc.set_in_units(thermo['c_msd[1]'].values, lammps_units['length']+'^2') msd_y = uc.set_in_units(thermo['c_msd[2]'].values, lammps_units['length']+'^2') msd_z = uc.set_in_units(thermo['c_msd[3]'].values, lammps_units['length']+'^2') msd = uc.set_in_units(thermo['c_msd[4]'].values, lammps_units['length']+'^2') # Initialize results dict results = {} results['natoms'] = system.natoms # Get mean and std for temperature, pressure, and potential energy results['temp'] = np.mean(temps) results['temp_std'] = np.std(temps) results['pxx'] = np.mean(pxxs) results['pxx_std'] = np.std(pxxs) results['pyy'] = np.mean(pyys) results['pyy_std'] = np.std(pyys) results['pzz'] = np.mean(pzzs) results['pzz_std'] = np.std(pzzs) results['Epot'] = np.mean(potengs) results['Epot_std'] = np.std(potengs) # Convert steps to times times = steps * uc.set_in_units(lammps_variables['timestep'], lammps_units['time']) # Estimate diffusion rates # MSD_ptd = natoms * MSD_atoms (if one defect in system) # MSD = 2 * ndim * D * t --> D = MSD/t / (2 * ndim) mx = np.polyfit(times, system.natoms * msd_x, 1)[0] my = np.polyfit(times, system.natoms * msd_y, 1)[0] mz = np.polyfit(times, system.natoms * msd_z, 1)[0] m = np.polyfit(times, system.natoms * msd, 1)[0] results['dx'] = mx / 2 results['dy'] = my / 2 results['dz'] = mz / 2 results['d'] = m / 6 return results
def disl_relax(lammps_command, system, potential, mpi_command=None, annealtemp=0.0, randomseed=None, etol=0.0, ftol=1e-6, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom')): """ Sets up and runs the disl_relax.in LAMMPS script for relaxing a dislocation monopole system. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. annealtemp : float, optional The temperature to perform a dynamic relaxation at. (Default is 0.0, which will skip the dynamic relaxation.) randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities and with the Langevin thermostat. (Default is None which will select a random int between 1 and 900000000.) etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'logfile'** (*str*) - The name of the LAMMPS log file. - **'dumpfile'** (*str*) - The name of the LAMMPS dump file for the relaxed system. - **'E_total'** (*float*) - The total potential energy for the relaxed system. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='system.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['anneal_info'] = anneal_info(annealtemp, randomseed, potential.units) lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = dmax lammps_variables['group_move'] = ' '.join(np.array(range(1, system.natypes // 2 + 1), dtype=str)) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'disl_relax.template' lammps_script = 'disl_relax.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, mpi_command) thermo = output.simulations[-1]['thermo'] # Extract output values results = {} results['logfile'] = 'log.lammps' results['dumpfile'] = '%i.dump' % thermo.Step.values[-1] results['E_total'] = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) return results
def e_vs_r(lammps_command, system, potential, symbols, mpi_command=None, ucell=None, rmin=2.0, rmax=6.0, rsteps=200): """ Performs a cohesive energy scan over a range of interatomic spaces, r. Arguments: lammps_command -- command for running LAMMPS. system -- atomman.System to perform the scan on. potential -- atomman.lammps.Potential representation of a LAMMPS implemented potential. symbols -- list of element-model symbols for the Potential that correspond to system's atypes. Keyword Arguments: mpi_command -- MPI command for running LAMMPS in parallel. Default value is None (serial run). ucell -- an atomman.System representing a fundamental unit cell of the system. If not given, ucell will be taken as system. rmin -- the minimum r spacing to use. Default value is 2.0. rmax -- the minimum r spacing to use. Default value is 6.0. rsteps -- the number of r spacing steps to evaluate. Default value is 200. """ #Make system a deepcopy of itself (protect original from changes) system = deepcopy(system) #Set ucell = system if ucell not given if ucell is None: ucell = system #Calculate the r/a ratio for the unit cell r_a = r_a_ratio(ucell) #Get ratios of lx, ly, and lz of system relative to a of ucell lx_a = system.box.a / ucell.box.a ly_a = system.box.b / ucell.box.a lz_a = system.box.c / ucell.box.a alpha = system.box.alpha beta = system.box.beta gamma = system.box.gamma #build lists of values r_values = np.linspace(rmin, rmax, rsteps) a_values = r_values / r_a Ecoh_values = np.empty(rsteps) #Loop over values for i in xrange(rsteps): #Rescale system's box a = a_values[i] system.box_set(a=a * lx_a, b=a * ly_a, c=a * lz_a, alpha=alpha, beta=beta, gamma=gamma, scale=True) #Get lammps units lammps_units = lmp.style.unit(potential.units) #Define lammps variables lammps_variables = {} lammps_variables['atomman_system_info'] = lmp.atom_data.dump( system, 'atom.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_pair_info'] = potential.pair_info(symbols) #Write lammps input script template_file = 'run0.template' lammps_script = 'run0.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 and extract data output = lmp.run(lammps_command, lammps_script, mpi_command) try: Ecoh_values[i] = uc.set_in_units( output.finds('v_peatom')[-1], lammps_units['energy']) except: Ecoh_values[i] = uc.set_in_units( output.finds('peatom')[-1], lammps_units['energy']) shutil.move('log.lammps', 'run0-' + str(i) + '-log.lammps') #Find unit cell systems at the energy minimums min_cells = [] for i in xrange(1, rsteps - 1): if Ecoh_values[i] < Ecoh_values[ i - 1] and Ecoh_values[i] < Ecoh_values[i + 1]: a = a_values[i] cell = deepcopy(ucell) cell.box_set(a=a, b=a * ucell.box.b / ucell.box.a, c=a * ucell.box.c / ucell.box.a, alpha=alpha, beta=beta, gamma=gamma, scale=True) min_cells.append(cell) return { 'r_values': r_values, 'a_values': a_values, 'Ecoh_values': Ecoh_values, 'min_cell': min_cells }
def e_vs_r(lammps_command, system, potential, mpi_command=None, ucell=None, rmin=uc.set_in_units(2.0, 'angstrom'), rmax=uc.set_in_units(6.0, 'angstrom'), rsteps=200): """ Performs a cohesive energy scan over a range of interatomic spaces, r. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. ucell : atomman.System, optional The fundamental unit cell correspodning to system. This is used to convert system dimensions to cell dimensions. If not given, ucell will be taken as system. rmin : float, optional The minimum r spacing to use (default value is 2.0 angstroms). rmax : float, optional The maximum r spacing to use (default value is 6.0 angstroms). rsteps : int, optional The number of r spacing steps to evaluate (default value is 200). Returns ------- dict Dictionary of results consisting of keys: - **'r_values'** (*numpy.array of float*) - All interatomic spacings, r, explored. - **'a_values'** (*numpy.array of float*) - All unit cell a lattice constants corresponding to the values explored. - **'Ecoh_values'** (*numpy.array of float*) - The computed cohesive energies for each r value. - **'min_cell'** (*list of atomman.System*) - Systems corresponding to the minima identified in the Ecoh_values. """ # Make system a deepcopy of itself (protect original from changes) system = deepcopy(system) # Set ucell = system if ucell not given if ucell is None: ucell = system # Calculate the r/a ratio for the unit cell r_a = r_a_ratio(ucell) # Get ratios of lx, ly, and lz of system relative to a of ucell lx_a = system.box.a / ucell.box.a ly_a = system.box.b / ucell.box.a lz_a = system.box.c / ucell.box.a alpha = system.box.alpha beta = system.box.beta gamma = system.box.gamma # Build lists of values r_values = np.linspace(rmin, rmax, rsteps) a_values = r_values / r_a Ecoh_values = np.empty(rsteps) # Loop over values for i in range(rsteps): # Rescale system's box a = a_values[i] system.box_set(a = a * lx_a, b = a * ly_a, c = a * lz_a, alpha=alpha, beta=beta, gamma=gamma, scale=True) # Get lammps units lammps_units = lmp.style.unit(potential.units) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='atom.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) # Write lammps input script template_file = 'run0.template' lammps_script = 'run0.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 and extract data output = lmp.run(lammps_command, lammps_script, mpi_command) thermo = output.simulations[0]['thermo'] if output.lammps_date < datetime.date(2016, 8, 1): Ecoh_values[i] = uc.set_in_units(thermo.peatom.values[-1], lammps_units['energy']) else: Ecoh_values[i] = uc.set_in_units(thermo.v_peatom.values[-1], lammps_units['energy']) # Rename log.lammps shutil.move('log.lammps', 'run0-'+str(i)+'-log.lammps') # Find unit cell systems at the energy minimums min_cells = [] for i in range(1, rsteps - 1): if (Ecoh_values[i] < Ecoh_values[i-1] and Ecoh_values[i] < Ecoh_values[i+1]): a = a_values[i] cell = deepcopy(ucell) cell.box_set(a = a, b = a * ucell.box.b / ucell.box.a, c = a * ucell.box.c / ucell.box.a, alpha=alpha, beta=beta, gamma=gamma, scale=True) min_cells.append(cell) # Collect results results_dict = {} results_dict['r_values'] = r_values results_dict['a_values'] = a_values results_dict['Ecoh_values'] = Ecoh_values results_dict['min_cell'] = min_cells return results_dict
def full_relax(lammps_command, system, potential, symbols, mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0, temperature=0.0, runsteps=100000, integrator=None, thermosteps=None, dumpsteps=None, randomseed=None): """ Performs a full dynamic relax on a given system at the given temperature to the specified pressure state. Arguments: lammps_command -- directory location for lammps executable system -- atomman.System to dynamically relax 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 value is 0.0 for all. temperature -- temperature to relax at. Default value is 0. runsteps -- number of integration steps to perform. Default value is 100000. integrator -- string giving the integration method to use. Options are 'npt', 'nvt', 'nph', 'nve', 'nve+l', 'nph+l'. The +l options use Langevin thermostat. Default value is 'nph+l' for temperature = 0, and 'npt' otherwise. thermosteps -- output thermo values every this many steps. Default value is runsteps/1000. dumpsteps -- output dump files every this many steps. Default value is runsteps (only first and last steps are outputted as dump files). randomseed -- random number seed used by LAMMPS for velocity creation and Langevin thermostat. Default value generates a new random integer every time. """ #Get lammps units lammps_units = lmp.style.unit(potential.units) #Handle default values if thermosteps is None: if thermosteps >= 1000: thermosteps = runsteps/1000 else: thermosteps = 1 if dumpsteps is None: dumpsteps = runsteps #Define lammps variables lammps_variables = {} lammps_variables['atomman_system_info'] = lmp.atom_data.dump(system, 'init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_pair_info'] = potential.pair_info(symbols) lammps_variables['integrator_info'] = integrator_info(integrator=integrator, p_xx=p_xx, p_yy=p_yy, p_zz=p_zz, temperature=temperature, randomseed=randomseed, units=potential.units) lammps_variables['thermosteps'] = thermosteps lammps_variables['runsteps'] = runsteps lammps_variables['dumpsteps'] = dumpsteps #Write lammps input script template_file = 'full_relax.template' lammps_script = 'full_relax.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, mpi_command) #Extract LAMMPS thermo data. thermo = output.find('thermo') lx = uc.set_in_units(np.array(thermo['Lx']), lammps_units['length']) ly = uc.set_in_units(np.array(thermo['Ly']), lammps_units['length']) lz = uc.set_in_units(np.array(thermo['Lz']), lammps_units['length']) #xy = uc.set_in_units(np.array(thermo['Xy']), lammps_units['length']) #xz = uc.set_in_units(np.array(thermo['Xz']), lammps_units['length']) #yz = uc.set_in_units(np.array(thermo['Yz']), lammps_units['length']) pxx = uc.set_in_units(np.array(thermo['Pxx']), lammps_units['pressure']) pyy = uc.set_in_units(np.array(thermo['Pyy']), lammps_units['pressure']) pzz = uc.set_in_units(np.array(thermo['Pzz']), lammps_units['pressure']) pxy = uc.set_in_units(np.array(thermo['Pxy']), lammps_units['pressure']) pxz = uc.set_in_units(np.array(thermo['Pxz']), lammps_units['pressure']) pyz = uc.set_in_units(np.array(thermo['Pyz']), lammps_units['pressure']) pe = uc.set_in_units(np.array(thermo['PotEng']), lammps_units['energy']) #ke = uc.set_in_units(np.array(thermo['KinEng']), lammps_units['energy']) temp = np.array(thermo['Temp']) step = np.array(thermo['Step'], dtype=int) return {'step':step, 'lx':lx, 'ly':ly, 'lz':lz, 'pe':pe, 'temp':temp, 'pxx':pxx, 'pyy':pyy, 'pzz':pzz, 'pxy':pxy, 'pxz':pxz, 'pyz':pyz}
def pointdefect( lammps_command: str, system: am.System, potential: lmp.Potential, point_kwargs: Union[list, dict], mpi_command: Optional[str] = None, etol: float = 0.0, ftol: float = 0.0, maxiter: int = 10000, maxeval: int = 100000, dmax: float = uc.set_in_units(0.01, 'angstrom') ) -> dict: """ Adds one or more point defects to a system and evaluates the defect formation energy. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. point_kwargs : dict or list of dict One or more dictionaries containing the keyword arguments for the atomman.defect.point() function to generate specific point defect configuration(s). mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. sim_directory : str, optional The path to the directory to perform the simulation in. If not given, will use the current working directory. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'E_pot'** (*float*) - The per-atom potential energy of the bulk system. - **'E_ptd_f'** (*float*) - The point defect formation energy. - **'E_total_base'** (*float*) - The total potential energy of the relaxed bulk system. - **'E_total_ptd'** (*float*) - The total potential energy of the relaxed defect system. - **'pij_tensor'** (*numpy.ndarray of float*) - The elastic dipole tensor associated with the defect. - **'system_base'** (*atomman.System*) - The relaxed bulk system. - **'system_ptd'** (*atomman.System*) - The relaxed defect system. - **'dumpfile_base'** (*str*) - The filename of the LAMMPS dump file for the relaxed bulk system. - **'dumpfile_ptd'** (*str*) - The filename of the LAMMPS dump file for the relaxed defect system. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='perfect.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = dmax # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script lammps_script = 'min.in' template = read_calc_file('iprPy.calculation.point_defect_static', 'min.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run lammps to relax perfect.dat output = lmp.run(lammps_command, script_name=lammps_script, mpi_command=mpi_command) # Extract LAMMPS thermo data. thermo = output.simulations[0]['thermo'] E_total_base = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) E_pot = E_total_base / system.natoms pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pressure_base = np.array([[pxx, pxy, pxz], [pxy, pyy, pyz], [pxz, pyz, pzz]]) # Rename log file shutil.move('log.lammps', 'min-perfect-log.lammps') # Load relaxed system from dump file and copy old box vectors because # dump files crop the values. last_dump_file = 'atom.' + str(thermo.Step.values[-1]) system_base = am.load('atom_dump', last_dump_file, symbols=system.symbols) system_base.box_set(vects=system.box.vects) system_base.dump('atom_dump', f='perfect.dump') # Add defect(s) system_ptd = deepcopy(system_base) if not isinstance(point_kwargs, (list, tuple)): point_kwargs = [point_kwargs] for pkwargs in point_kwargs: system_ptd = am.defect.point(system_ptd, **pkwargs) # Update lammps variables system_info = system_ptd.dump('atom_data', f='defect.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info # Write lammps input script with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run lammps output = lmp.run(lammps_command, script_name=lammps_script, mpi_command=mpi_command) # Extract lammps thermo data thermo = output.simulations[0]['thermo'] E_total_ptd = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pressure_ptd = np.array([[pxx, pxy, pxz], [pxy, pyy, pyz], [pxz, pyz, pzz]]) # Rename log file shutil.move('log.lammps', 'min-defect-log.lammps') # Load relaxed system from dump file and copy old vects as # the dump files crop the values last_dump_file = 'atom.' + str(thermo.Step.values[-1]) system_ptd = am.load('atom_dump', last_dump_file, symbols=system_ptd.symbols) system_ptd.box_set(vects=system.box.vects) system_ptd.dump('atom_dump', f='defect.dump') # Compute defect formation energy E_ptd_f = E_total_ptd - E_pot * system_ptd.natoms # Compute strain tensor pij = -(pressure_base - pressure_ptd) * system_base.box.volume # Cleanup files for fname in Path.cwd().glob('atom.*'): fname.unlink() for dumpjsonfile in Path.cwd().glob('*.dump.json'): dumpjsonfile.unlink() # Return results results_dict = {} results_dict['E_pot'] = E_pot results_dict['E_ptd_f'] = E_ptd_f results_dict['E_total_base'] = E_total_base results_dict['E_total_ptd'] = E_total_ptd results_dict['pij_tensor'] = pij results_dict['system_base'] = system_base results_dict['system_ptd'] = system_ptd results_dict['dumpfile_base'] = 'perfect.dump' results_dict['dumpfile_ptd'] = 'defect.dump' return results_dict
def elastic_constants_static(lammps_command, system, potential, mpi_command=None, strainrange=1e-6, etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom')): """ Repeatedly runs the ELASTIC example distributed with LAMMPS until box dimensions converge within a tolerance. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. strainrange : float, optional The small strain value to apply when calculating the elastic constants (default is 1e-6). etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'a_lat'** (*float*) - The relaxed a lattice constant. - **'b_lat'** (*float*) - The relaxed b lattice constant. - **'c_lat'** (*float*) - The relaxed c lattice constant. - **'alpha_lat'** (*float*) - The alpha lattice angle. - **'beta_lat'** (*float*) - The beta lattice angle. - **'gamma_lat'** (*float*) - The gamma lattice angle. - **'E_coh'** (*float*) - The cohesive energy of the relaxed system. - **'stress'** (*numpy.array*) - The measured stress state of the relaxed system. - **'C_elastic'** (*atomman.ElasticConstants*) - The relaxed system's elastic constants. - **'system_relaxed'** (*atomman.System*) - The relaxed system. """ # Convert hexagonal cells to orthorhombic to avoid LAMMPS tilt issues if am.tools.ishexagonal(system.box): system = system.rotate([[2,-1,-1,0], [0, 1, -1, 0], [0,0,0,1]]) # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['strainrange'] = strainrange lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Fill in template files 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, '<', '>')) template_file2 = 'potential.template' lammps_script2 = 'potential.in' with open(template_file2) as f: template = f.read() with open(lammps_script2, 'w') as f: f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) # Run LAMMPS output = lmp.run(lammps_command, lammps_script, mpi_command) # Pull out initial state thermo = output.simulations[0]['thermo'] pxx0 = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy0 = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz0 = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pyz0 = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pxz0 = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pxy0 = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) # Negative strains cij_n = np.empty((6,6)) for i in range(6): j = 1 + i * 2 # Pull out strained state thermo = output.simulations[j]['thermo'] pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) # Calculate cij_n using stress changes cij_n[i] = np.array([pxx - pxx0, pyy - pyy0, pzz - pzz0, pyz - pyz0, pxz - pxz0, pxy - pxy0])/ strainrange # Positive strains cij_p = np.empty((6,6)) for i in range(6): j = 2 + i * 2 # Pull out strained state thermo = output.simulations[j]['thermo'] pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) # Calculate cij_p using stress changes cij_p[i] = -np.array([pxx - pxx0, pyy - pyy0, pzz - pzz0, pyz - pyz0, pxz - pxz0, pxy - pxy0])/ strainrange # Average symmetric values cij = (cij_n + cij_p) / 2 for i in range(6): for j in range(i): cij[i,j] = cij[j,i] = (cij[i,j] + cij[j,i]) / 2 # Define results_dict results_dict = {} results_dict['raw_cij_negative'] = cij_n results_dict['raw_cij_positive'] = cij_p results_dict['C'] = am.ElasticConstants(Cij=cij) return results_dict
def relax_static(lammps_command, system, potential, mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0, p_xy=0.0, p_xz=0.0, p_yz=0.0, dispmult=0.0, etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom'), maxcycles=100, ctol=1e-10): """ Repeatedly runs the ELASTIC example distributed with LAMMPS until box dimensions converge within a tolerance. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. p_xx : float, optional The value to relax the x tensile pressure component to (default is 0.0). p_yy : float, optional The value to relax the y tensile pressure component to (default is 0.0). p_zz : float, optional The value to relax the z tensile pressure component to (default is 0.0). p_xy : float, optional The value to relax the xy shear pressure component to (default is 0.0). p_xz : float, optional The value to relax the xz shear pressure component to (default is 0.0). p_yz : float, optional The value to relax the yz shear pressure component to (default is 0.0). dispmult : float, optional Multiplier for applying a random displacement to all atomic positions prior to relaxing. Default value is 0.0. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). pressure_unit : str, optional The unit of pressure to calculate the elastic constants in (default is 'GPa'). maxcycles : int, optional The maximum number of times the minimization algorithm is called. Default value is 100. ctol : float, optional The relative tolerance used to determine if the lattice constants have converged (default is 1e-10). Returns ------- dict Dictionary of results consisting of keys: - **'relaxed_system'** (*float*) - The relaxed system. - **'E_coh'** (*float*) - The cohesive energy of the relaxed system. - **'measured_pxx'** (*float*) - The measured x tensile pressure of the relaxed system. - **'measured_pyy'** (*float*) - The measured y tensile pressure of the relaxed system. - **'measured_pzz'** (*float*) - The measured z tensile pressure of the relaxed system. - **'measured_pxy'** (*float*) - The measured xy shear pressure of the relaxed system. - **'measured_pxz'** (*float*) - The measured xz shear pressure of the relaxed system. - **'measured_pyz'** (*float*) - The measured yz shear pressure of the relaxed system. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Save initial configuration as a dump file system.dump('atom_dump', f='initial.dump') # Apply small random distortions to atoms system.atoms.pos += dispmult * np.random.rand( *system.atoms.pos.shape) - dispmult / 2 # Initialize parameters old_vects = system.box.vects converged = False # Run minimizations up to maxcycles times for cycle in range(maxcycles): old_system = deepcopy(system) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info( system.symbols) lammps_variables['p_xx'] = uc.get_in_units(p_xx, lammps_units['pressure']) lammps_variables['p_yy'] = uc.get_in_units(p_yy, lammps_units['pressure']) lammps_variables['p_zz'] = uc.get_in_units(p_zz, lammps_units['pressure']) lammps_variables['p_xy'] = uc.get_in_units(p_xy, lammps_units['pressure']) lammps_variables['p_xz'] = uc.get_in_units(p_xz, lammps_units['pressure']) lammps_variables['p_yz'] = uc.get_in_units(p_yz, lammps_units['pressure']) lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'minbox.template' lammps_script = 'minbox.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 and extract thermo data logfile = 'log-' + str(cycle) + '.lammps' output = lmp.run(lammps_command, lammps_script, mpi_command, logfile=logfile) thermo = output.simulations[0]['thermo'] # Clean up dump files os.remove('0.dump') last_dump_file = str(thermo.Step.values[-1]) + '.dump' renamed_dump_file = 'relax_static-' + str(cycle) + '.dump' shutil.move(last_dump_file, renamed_dump_file) # Load relaxed system system = am.load('atom_dump', renamed_dump_file, symbols=system.symbols) # Test if box dimensions have converged if np.allclose(old_vects, system.box.vects, rtol=ctol, atol=0): converged = True break else: old_vects = system.box.vects # Check for convergence if converged is False: raise RuntimeError('Failed to converge after ' + str(maxcycles) + ' cycles') # Zero out near-zero tilt factors lx = system.box.lx ly = system.box.ly lz = system.box.lz xy = system.box.xy xz = system.box.xz yz = system.box.yz if np.isclose(xy / ly, 0.0, rtol=0.0, atol=1e-10): xy = 0.0 if np.isclose(xz / lz, 0.0, rtol=0.0, atol=1e-10): xz = 0.0 if np.isclose(yz / lz, 0.0, rtol=0.0, atol=1e-10): yz = 0.0 system.box.set(lx=lx, ly=ly, lz=lz, xy=xy, xz=xz, yz=yz) system.wrap() # Build results_dict results_dict = {} results_dict['dumpfile_initial'] = 'initial.dump' results_dict['symbols_initial'] = system.symbols results_dict['dumpfile_final'] = renamed_dump_file results_dict['symbols_final'] = system.symbols results_dict['E_coh'] = uc.set_in_units( thermo.PotEng.values[-1] / system.natoms, lammps_units['energy']) results_dict['lx'] = uc.set_in_units(lx, lammps_units['length']) results_dict['ly'] = uc.set_in_units(ly, lammps_units['length']) results_dict['lz'] = uc.set_in_units(lz, lammps_units['length']) results_dict['xy'] = uc.set_in_units(xy, lammps_units['length']) results_dict['xz'] = uc.set_in_units(xz, lammps_units['length']) results_dict['yz'] = uc.set_in_units(yz, lammps_units['length']) results_dict['measured_pxx'] = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) results_dict['measured_pyy'] = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) results_dict['measured_pzz'] = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) results_dict['measured_pxy'] = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) results_dict['measured_pxz'] = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) results_dict['measured_pyz'] = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) return results_dict
def dynamic_stress(lammps_command, system, potential, symbols, mpi_command=None, temperature=0.0, runsteps=100000, integrator=None, thermosteps=None, dumpsteps=None, restartsteps=None, randomseed=None): """ Performs a dynamic run on a given system at the given temperature to measure stress state. Arguments: lammps_command -- directory location for lammps executable system -- atomman.System to dynamically relax 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: mpi_command -- MPI command to use when running LAMMPS. temperature -- temperature to relax at. Default value is 0. runsteps -- number of integration steps to perform. Default value is 100000. integrator -- string giving the integration method to use. Options are limited to 'nvt', 'nve' and 'nve+l'. The +l options use Langevin thermostat. Default value is 'nve+l' for temperature = 0, and 'nvt' otherwise. thermosteps -- output thermo values every this many steps. Default value is runsteps/1000. dumpsteps -- output dump files every this many steps. Default value is runsteps (only first and last steps are outputted as dump files). randomseed -- random number seed used by LAMMPS for velocity creation and Langevin thermostat. Default value generates a new random integer every time. """ assert integrator in ['nvt', 'nve', 'nve+l'], 'Only nvt, nve, and nve+l integrators allowed' #Get lammps units lammps_units = lmp.style.unit(potential.units) #Handle default values if thermosteps is None: if thermosteps >= 1000: thermosteps = runsteps/1000 else: thermosteps = 1 if dumpsteps is None: dumpsteps = runsteps if restartsteps is None: restartsteps = dumpsteps #Define lammps variables lammps_variables = {} lammps_variables['atomman_system_info'] = lmp.atom_data.dump(system, 'init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_pair_info'] = potential.pair_info(symbols) lammps_variables['integrator_info'] = integrator_info(integrator=integrator, temperature=temperature, randomseed=randomseed, units=potential.units) lammps_variables['thermosteps'] = thermosteps lammps_variables['runsteps'] = runsteps lammps_variables['restartsteps'] = restartsteps lammps_variables['dumpsteps'] = dumpsteps #Check LAMMPS compute stress version compute_stress_version = iprPy.tools.lammps_version.compute_stress(lammps_command) if compute_stress_version == 0: lammps_variables['stressterm'] = 'NULL' elif compute_stress_version == 1: lammps_variables['stressterm'] = '' #Write lammps input script template_file = 'full_relax.template' lammps_script = 'full_relax.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, '<', '>')) #Write restart input script lammps_restart = 'full_relax_restart.in' lammps_variables['atomman_system_info'] = 'read_restart *.restart' with open(lammps_restart, 'w') as f: f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) #Run lammps output = lmp.run(lammps_command, lammps_script, mpi_command, restart_script_name=lammps_restart, flatten_thermo='last') #Extract LAMMPS thermo data. thermo = output.find('thermo') #lx = uc.set_in_units(np.array(thermo['Lx']), lammps_units['length']) #ly = uc.set_in_units(np.array(thermo['Ly']), lammps_units['length']) #lz = uc.set_in_units(np.array(thermo['Lz']), lammps_units['length']) #xy = uc.set_in_units(np.array(thermo['Xy']), lammps_units['length']) #xz = uc.set_in_units(np.array(thermo['Xz']), lammps_units['length']) #yz = uc.set_in_units(np.array(thermo['Yz']), lammps_units['length']) pxx = uc.set_in_units(np.array(thermo['Pxx']), lammps_units['pressure']) pyy = uc.set_in_units(np.array(thermo['Pyy']), lammps_units['pressure']) pzz = uc.set_in_units(np.array(thermo['Pzz']), lammps_units['pressure']) pxy = uc.set_in_units(np.array(thermo['Pxy']), lammps_units['pressure']) pxz = uc.set_in_units(np.array(thermo['Pxz']), lammps_units['pressure']) pyz = uc.set_in_units(np.array(thermo['Pyz']), lammps_units['pressure']) pe = uc.set_in_units(np.array(thermo['PotEng']), lammps_units['energy']) #ke = uc.set_in_units(np.array(thermo['KinEng']), lammps_units['energy']) temp = np.array(thermo['Temp']) step = np.array(thermo['Step'], dtype=int) return {'step':step, 'pe':pe, 'temp':temp, 'pxx':pxx, 'pyy':pyy, 'pzz':pzz, 'pxy':pxy, 'pxz':pxz, 'pyz':pyz}
def isolated_atom(lammps_command: str, potential: am.lammps.Potential, mpi_command: Optional[str] = None) -> dict: """ Evaluates the isolated atom energy for each elemental model of a potential. Parameters ---------- lammps_command :str Command for running LAMMPS. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. Returns ------- dict Dictionary of results consisting of keys: - **'energy'** (*dict*) - The computed potential energies for each symbol. """ # Initialize dictionary energydict = {} # Initialize single atom system box = am.Box.cubic(a=1) atoms = am.Atoms(atype=1, pos=[[0.5, 0.5, 0.5]]) system = am.System(atoms=atoms, box=box, pbc=[False, False, False]) # Get lammps units lammps_units = lmp.style.unit(potential.units) # Define lammps variables lammps_variables = {} # Loop over symbols for symbol in potential.symbols: system.symbols = symbol # Add charges if required if potential.atom_style == 'charge': system.atoms.prop_atype('charge', potential.charges(system.symbols)) # Save configuration system_info = system.dump('atom_data', f='isolated.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info # Write lammps input script lammps_script = 'run0.in' template = read_calc_file('iprPy.calculation.isolated_atom', 'run0.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run lammps and extract data output = lmp.run(lammps_command, script_name=lammps_script, mpi_command=mpi_command) energy = output.simulations[0]['thermo'].PotEng.values[-1] energydict[symbol] = uc.set_in_units(energy, lammps_units['energy']) # Collect results results_dict = {} results_dict['energy'] = energydict return results_dict
def elastic_constants_static(lammps_command, system, potential, mpi_command=None, strainrange=1e-6, etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom')): """ Repeatedly runs the ELASTIC example distributed with LAMMPS until box dimensions converge within a tolerance. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. strainrange : float, optional The small strain value to apply when calculating the elastic constants (default is 1e-6). etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'a_lat'** (*float*) - The relaxed a lattice constant. - **'b_lat'** (*float*) - The relaxed b lattice constant. - **'c_lat'** (*float*) - The relaxed c lattice constant. - **'alpha_lat'** (*float*) - The alpha lattice angle. - **'beta_lat'** (*float*) - The beta lattice angle. - **'gamma_lat'** (*float*) - The gamma lattice angle. - **'E_coh'** (*float*) - The cohesive energy of the relaxed system. - **'stress'** (*numpy.array*) - The measured stress state of the relaxed system. - **'C_elastic'** (*atomman.ElasticConstants*) - The relaxed system's elastic constants. - **'system_relaxed'** (*atomman.System*) - The relaxed system. """ # Convert hexagonal cells to orthorhombic to avoid LAMMPS tilt issues if am.tools.ishexagonal(system.box): system = system.rotate([[2, -1, -1, 0], [0, 1, -1, 0], [0, 0, 0, 1]]) # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['strainrange'] = strainrange lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Fill in template files 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, '<', '>')) template_file2 = 'potential.template' lammps_script2 = 'potential.in' with open(template_file2) as f: template = f.read() with open(lammps_script2, 'w') as f: f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>')) # Run LAMMPS output = lmp.run(lammps_command, lammps_script, mpi_command) # Pull out initial state thermo = output.simulations[0]['thermo'] pxx0 = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy0 = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz0 = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pyz0 = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pxz0 = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pxy0 = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) # Negative strains cij_n = np.empty((6, 6)) for i in range(6): j = 1 + i * 2 # Pull out strained state thermo = output.simulations[j]['thermo'] pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) # Calculate cij_n using stress changes cij_n[i] = np.array([ pxx - pxx0, pyy - pyy0, pzz - pzz0, pyz - pyz0, pxz - pxz0, pxy - pxy0 ]) / strainrange # Positive strains cij_p = np.empty((6, 6)) for i in range(6): j = 2 + i * 2 # Pull out strained state thermo = output.simulations[j]['thermo'] pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) # Calculate cij_p using stress changes cij_p[i] = -np.array([ pxx - pxx0, pyy - pyy0, pzz - pzz0, pyz - pyz0, pxz - pxz0, pxy - pxy0 ]) / strainrange # Average symmetric values cij = (cij_n + cij_p) / 2 for i in range(6): for j in range(i): cij[i, j] = cij[j, i] = (cij[i, j] + cij[j, i]) / 2 # Define results_dict results_dict = {} results_dict['raw_cij_negative'] = cij_n results_dict['raw_cij_positive'] = cij_p results_dict['C'] = am.ElasticConstants(Cij=cij) return results_dict
def bain_run_calcs(input_dict, __calc_type__, step): #-------------------SETS UP THE SYSTEM-------------------- #Read in potential potential = lmp.Potential( input_dict['potential'], input_dict['potential_dir']) #reads the potential filename system = input_dict['initial_system'] #if initial step, set up system to find difference in cohesive energy. this step is skipped when a and c values change. if step == 'initial': a_scale = 1 c_scale = 1 elif step == 'bain': a_scale = input_dict['bain_a_scale'] c_scale = input_dict['bain_c_scale'] #scale box and atoms simultaneously system.box_set(a=a_scale * system.box.a, b=a_scale * system.box.b, c=c_scale * system.box.c, scale=True) #ensure all atoms are within the box system.wrap() #-------------------RUN LAMMPS AND SAVE RESULTS------------------ #use above information to generate system_info and pair_info for LAMMPS system_info = am.lammps.atom_data.dump('bain.dat', system, units=potential.units, atom_style=potential.atom_style) pair_info = potential.pair_info( input_dict['symbols'] ) #pulls the potential info when given which element the calculation is running on #write the LAMMPS input script with open('bain.in', 'w') as f: f.write( bain_relax_script('min.template', system_info, pair_info, etol=input_dict['energy_tolerance'], ftol=input_dict['force_tolerance'], maxiter=input_dict['maximum_iterations'], maxeval=input_dict['maximum_evaluations'])) #run LAMMPS output = lmp.run(input_dict['lammps_command'], 'bain.in', input_dict['mpi_command']) atom_last = 'atom.%i' % output.finds('Step')[ -1] #prints number of iterations (?) #save results into results_dict if step == 'initial': try: os.rename(atom_last, 'initial.dump') except: os.remove('initial.dump') os.rename(atom_last, 'initial.dump') os.remove('atom.0') d_system = lmp.atom_dump.load('initial.dump') elif step == 'bain': try: os.rename(atom_last, 'bain.dump') except: os.remove('bain.dump') os.rename(atom_last, 'bain.dump') os.remove('atom.0') d_system = lmp.atom_dump.load('bain.dump') results_dict = {} results_dict['potential_energy'] = float(output.finds('PotEng')[-1]) #return values return results_dict['potential_energy']
def phonon(lammps_command, ucell, potential, mpi_command=None, a_mult=3, b_mult=3, c_mult=3, distance=0.01, symprec=1e-5): try: # Get script's location if __file__ exists script_dir = Path(__file__).parent except: # Use cwd otherwise script_dir = Path.cwd() # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Generate pair_info pair_info = potential.pair_info(ucell.symbols) # Use spglib to find primitive unit cell of ucell convcell = ucell.dump('spglib_cell') primcell = spglib.find_primitive(convcell, symprec=symprec) primucell = am.load('spglib_cell', primcell, symbols=ucell.symbols).normalize() # Initialize Phonopy object phonon = phonopy.Phonopy(primucell.dump('phonopy_Atoms'), [[a_mult, 0, 0], [0, b_mult, 0], [0, 0, c_mult]]) phonon.generate_displacements(distance=distance) # Loop over displaced supercells to compute forces forcearrays = [] for supercell in phonon.supercells_with_displacements: # Save to LAMMPS data file system = am.load('phonopy_Atoms', supercell) system_info = system.dump('atom_data', f='disp.dat') # Define lammps variables lammps_variables = {} lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = pair_info # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = Path(script_dir, 'phonon.template') lammps_script = 'phonon.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 lmp.run(lammps_command, 'phonon.in', mpi_command=mpi_command) # Extract forces from dump file results = am.load('atom_dump', 'forces.dump') forces = uc.set_in_units(results.atoms.force, lammps_units['force']) forcearrays.append(forces) # Set computed forces phonon.set_forces(forcearrays) # Save to yaml file phonon.save('phonopy_params.yaml') # Compute band structure phonon.produce_force_constants() phonon.auto_band_structure(plot=True) plt.savefig(Path('.', 'band.png'), dpi=400) plt.close() # Compute total density of states phonon.auto_total_dos(plot=True) plt.savefig('total_dos.png', dpi=400) plt.close() # Compute partial density of states phonon.auto_projected_dos(plot=True) plt.savefig('projected_dos.png', dpi=400) plt.close() # Compute thermal properties phonon.run_thermal_properties() phonon.plot_thermal_properties() plt.savefig('thermal.png', dpi=400) plt.close() return {}
def relax_dynamic(lammps_command: str, system: am.System, potential: lmp.Potential, mpi_command: Optional[str] = None, p_xx: float = 0.0, p_yy: float = 0.0, p_zz: float = 0.0, p_xy: float = 0.0, p_xz: float = 0.0, p_yz: float = 0.0, temperature: float = 0.0, integrator: Optional[str] = None, runsteps: int = 220000, thermosteps: int = 100, dumpsteps: Optional[int] = None, restartsteps: Optional[int] = None, equilsteps: int = 20000, randomseed: Optional[int] = None) -> dict: """ Performs a full dynamic relax on a given system at the given temperature to the specified pressure state. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. symbols : list of str The list of element-model symbols for the Potential that correspond to system's atypes. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. p_xx : float, optional The value to relax the x tensile pressure component to (default is 0.0). p_yy : float, optional The value to relax the y tensile pressure component to (default is 0.0). p_zz : float, optional The value to relax the z tensile pressure component to (default is 0.0). temperature : float, optional The temperature to relax at (default is 0.0). runsteps : int, optional The number of integration steps to perform (default is 220000). integrator : str or None, optional The integration method to use. Options are 'npt', 'nvt', 'nph', 'nve', 'nve+l', 'nph+l'. The +l options use Langevin thermostat. (Default is None, which will use 'nph+l' for temperature == 0, and 'npt' otherwise.) thermosteps : int, optional Thermo values will be reported every this many steps (default is 100). dumpsteps : int or None, optional Dump files will be saved every this many steps (default is None, which sets dumpsteps equal to runsteps). restartsteps : int or None, optional Restart files will be saved every this many steps (default is None, which sets restartsteps equal to runsteps). equilsteps : int, optional The number of timesteps at the beginning of the simulation to exclude when computing average values (default is 20000). randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities and with the Langevin thermostat. (Default is None which will select a random int between 1 and 900000000.) Returns ------- dict Dictionary of results consisting of keys: - **'dumpfile_initial'** (*str*) - The name of the initial dump file created. - **'symbols_initial'** (*list*) - The symbols associated with the initial dump file. - **'dumpfile_final'** (*str*) - The name of the final dump file created. - **'symbols_final'** (*list*) - The symbols associated with the final dump file. - **'nsamples'** (*int*) - The number of thermodynamic samples included in the mean and standard deviation estimates. Can also be used to estimate standard error values assuming that the thermo step size is large enough (typically >= 100) to assume the samples to be independent. - **'E_pot'** (*float*) - The mean measured potential energy. - **'measured_pxx'** (*float*) - The measured x tensile pressure of the relaxed system. - **'measured_pyy'** (*float*) - The measured y tensile pressure of the relaxed system. - **'measured_pzz'** (*float*) - The measured z tensile pressure of the relaxed system. - **'measured_pxy'** (*float*) - The measured xy shear pressure of the relaxed system. - **'measured_pxz'** (*float*) - The measured xz shear pressure of the relaxed system. - **'measured_pyz'** (*float*) - The measured yz shear pressure of the relaxed system. - **'temp'** (*float*) - The mean measured temperature. - **'E_pot_std'** (*float*) - The standard deviation in the measured potential energy values. - **'measured_pxx_std'** (*float*) - The standard deviation in the measured x tensile pressure of the relaxed system. - **'measured_pyy_std'** (*float*) - The standard deviation in the measured y tensile pressure of the relaxed system. - **'measured_pzz_std'** (*float*) - The standard deviation in the measured z tensile pressure of the relaxed system. - **'measured_pxy_std'** (*float*) - The standard deviation in the measured xy shear pressure of the relaxed system. - **'measured_pxz_std'** (*float*) - The standard deviation in the measured xz shear pressure of the relaxed system. - **'measured_pyz_std'** (*float*) - The standard deviation in the measured yz shear pressure of the relaxed system. - **'temp_std'** (*float*) - The standard deviation in the measured temperature values. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Handle default values if dumpsteps is None: dumpsteps = runsteps if restartsteps is None: restartsteps = runsteps # Define lammps variables lammps_variables = {} # Dump initial system as data and build LAMMPS inputs system_info = system.dump('atom_data', f='init.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info # Generate LAMMPS inputs for restarting system_info2 = potential.pair_restart_info('*.restart', system.symbols) lammps_variables['atomman_pair_restart_info'] = system_info2 # Integrator lines for main run integ_info = integrator_info(integrator=integrator, p_xx=p_xx, p_yy=p_yy, p_zz=p_zz, p_xy=p_xy, p_xz=p_xz, p_yz=p_yz, temperature=temperature, randomseed=randomseed, units=potential.units, lammps_date=lammps_date) lammps_variables['integrator_info'] = integ_info # Integrator lines for restarts integ_info2 = integrator_info(integrator=integrator, p_xx=p_xx, p_yy=p_yy, p_zz=p_zz, p_xy=p_xy, p_xz=p_xz, p_yz=p_yz, temperature=temperature, velocity_temperature=0.0, randomseed=randomseed, units=potential.units, lammps_date=lammps_date) lammps_variables['integrator_restart_info'] = integ_info2 # Other run settings lammps_variables['thermosteps'] = thermosteps lammps_variables['runsteps'] = runsteps lammps_variables['dumpsteps'] = dumpsteps lammps_variables['restartsteps'] = restartsteps # Set compute stress/atom based on LAMMPS version if lammps_date < datetime.date(2014, 2, 12): lammps_variables['stressterm'] = '' else: lammps_variables['stressterm'] = 'NULL' # Set dump_keys based on atom_style if potential.atom_style in ['charge']: lammps_variables['dump_keys'] = 'id type q xu yu zu c_pe c_ke &\n' lammps_variables[ 'dump_keys'] += 'c_stress[1] c_stress[2] c_stress[3] c_stress[4] c_stress[5] c_stress[6]' else: lammps_variables['dump_keys'] = 'id type xu yu zu c_pe c_ke &\n' lammps_variables[ 'dump_keys'] += 'c_stress[1] c_stress[2] c_stress[3] c_stress[4] c_stress[5] c_stress[6]' # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): if potential.atom_style in ['charge']: lammps_variables['dump_modify_format'] = f'"%d %d{12 * " %.13e"}"' else: lammps_variables['dump_modify_format'] = f'"%d %d{11 * " %.13e"}"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script lammps_script = 'full_relax.in' template = read_calc_file('iprPy.calculation.relax_dynamic', 'full_relax.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Write lammps restart input script restart_script = 'full_relax_restart.in' template = read_calc_file('iprPy.calculation.relax_dynamic', 'full_relax_restart.template') with open(restart_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run lammps output = lmp.run(lammps_command, script_name=lammps_script, restart_script_name=restart_script, mpi_command=mpi_command, screen=False) # Extract LAMMPS thermo data. results = {} thermo = output.flatten()['thermo'] results['dumpfile_initial'] = '0.dump' results['symbols_initial'] = system.symbols # Load relaxed system from dump file last_dump_file = f'{thermo.Step.values[-1]}.dump' results['dumpfile_final'] = last_dump_file system = am.load('atom_dump', last_dump_file, symbols=system.symbols) results['symbols_final'] = system.symbols # Only consider values where Step >= equilsteps thermo = thermo[thermo.Step >= equilsteps] results['nsamples'] = len(thermo) # Get cohesive energy estimates natoms = system.natoms results['E_pot'] = uc.set_in_units(thermo.PotEng.mean() / natoms, lammps_units['energy']) results['E_pot_std'] = uc.set_in_units(thermo.PotEng.std() / natoms, lammps_units['energy']) results['E_total'] = uc.set_in_units(thermo.TotEng.mean() / natoms, lammps_units['energy']) results['E_total_std'] = uc.set_in_units(thermo.TotEng.std() / natoms, lammps_units['energy']) results['lx'] = uc.set_in_units(thermo.Lx.mean(), lammps_units['length']) results['lx_std'] = uc.set_in_units(thermo.Lx.std(), lammps_units['length']) results['ly'] = uc.set_in_units(thermo.Ly.mean(), lammps_units['length']) results['ly_std'] = uc.set_in_units(thermo.Ly.std(), lammps_units['length']) results['lz'] = uc.set_in_units(thermo.Lz.mean(), lammps_units['length']) results['lz_std'] = uc.set_in_units(thermo.Lz.std(), lammps_units['length']) results['xy'] = uc.set_in_units(thermo.Xy.mean(), lammps_units['length']) results['xy_std'] = uc.set_in_units(thermo.Xy.std(), lammps_units['length']) results['xz'] = uc.set_in_units(thermo.Xz.mean(), lammps_units['length']) results['xz_std'] = uc.set_in_units(thermo.Xz.std(), lammps_units['length']) results['yz'] = uc.set_in_units(thermo.Yz.mean(), lammps_units['length']) results['yz_std'] = uc.set_in_units(thermo.Yz.std(), lammps_units['length']) results['measured_pxx'] = uc.set_in_units(thermo.Pxx.mean(), lammps_units['pressure']) results['measured_pxx_std'] = uc.set_in_units(thermo.Pxx.std(), lammps_units['pressure']) results['measured_pyy'] = uc.set_in_units(thermo.Pyy.mean(), lammps_units['pressure']) results['measured_pyy_std'] = uc.set_in_units(thermo.Pyy.std(), lammps_units['pressure']) results['measured_pzz'] = uc.set_in_units(thermo.Pzz.mean(), lammps_units['pressure']) results['measured_pzz_std'] = uc.set_in_units(thermo.Pzz.std(), lammps_units['pressure']) results['measured_pxy'] = uc.set_in_units(thermo.Pxy.mean(), lammps_units['pressure']) results['measured_pxy_std'] = uc.set_in_units(thermo.Pxy.std(), lammps_units['pressure']) results['measured_pxz'] = uc.set_in_units(thermo.Pxz.mean(), lammps_units['pressure']) results['measured_pxz_std'] = uc.set_in_units(thermo.Pxz.std(), lammps_units['pressure']) results['measured_pyz'] = uc.set_in_units(thermo.Pyz.mean(), lammps_units['pressure']) results['measured_pyz_std'] = uc.set_in_units(thermo.Pyz.std(), lammps_units['pressure']) results['temp'] = thermo.Temp.mean() results['temp_std'] = thermo.Temp.std() return results
def cij_run0(lammps_command: str, system: am.System, potential: lmp.Potential, mpi_command: Optional[str] = None, strainrange: float = 1e-6, cycle: int = 0) -> dict: """ Runs cij_run0.in LAMMPS script to evaluate the elastic constants, pressure and potential energy of the current system. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. strainrange : float, optional The small strain value to apply when calculating the elastic constants (default is 1e-6). cycle : int, optional Indicates the iteration cycle of quick_a_Cij(). This is used to uniquely save the LAMMPS input and output files. Returns ------- dict Dictionary of results consisting of keys: - **'E_pot'** (*float*) - The potential energy per atom for the supplied system. - **'pressure'** (*numpy.array*) - The measured pressure state of the supplied system. - **'C_elastic'** (*atomman.ElasticConstants*) - The supplied system's elastic constants. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', potential=potential) restart_info = potential.pair_restart_info('initial.restart', system.symbols) lammps_variables['pair_data_info'] = system_info lammps_variables['pair_restart_info'] = restart_info lammps_variables['strainrange'] = strainrange # Write lammps input script lammps_script = 'cij_run0.in' template = read_calc_file('iprPy.calculation.relax_box', 'cij_run0.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run lammps output = lmp.run(lammps_command, script_name=lammps_script, mpi_command=mpi_command, logfile=f'cij-{cycle}-log.lammps') thermo = output.flatten('all').thermo # 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(thermo.Lx, lammps_units['length']) ly = uc.set_in_units(thermo.Ly, lammps_units['length']) lz = uc.set_in_units(thermo.Lz, lammps_units['length']) xy = uc.set_in_units(thermo.Xy, lammps_units['length']) xz = uc.set_in_units(thermo.Xz, lammps_units['length']) yz = uc.set_in_units(thermo.Yz, lammps_units['length']) pxx = uc.set_in_units(thermo.Pxx, lammps_units['pressure']) pyy = uc.set_in_units(thermo.Pyy, lammps_units['pressure']) pzz = uc.set_in_units(thermo.Pzz, lammps_units['pressure']) pxy = uc.set_in_units(thermo.Pxy, lammps_units['pressure']) pxz = uc.set_in_units(thermo.Pxz, lammps_units['pressure']) pyz = uc.set_in_units(thermo.Pyz, lammps_units['pressure']) pe = uc.set_in_units(thermo.PotEng / system.natoms, lammps_units['energy']) # Extract the pressure tensor pij = np.array([[pxx[0], pxy[0], pxz[0]], [pxy[0], pyy[0], pyz[0]], [pxz[0], pyz[0], pzz[0]]]) # 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 range(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 range(6): for j in range(i): cij[i, j] = cij[j, i] = (cij[i, j] + cij[j, i]) / 2 C = am.ElasticConstants(Cij=cij) results = {} results['E_pot'] = pe[0] results['pij'] = pij results['C'] = C return results
def relax_static(lammps_command, system, potential, mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0, p_xy=0.0, p_xz=0.0, p_yz=0.0, dispmult=0.0, etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom'), maxcycles=100, ctol=1e-10): """ Repeatedly runs the ELASTIC example distributed with LAMMPS until box dimensions converge within a tolerance. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. p_xx : float, optional The value to relax the x tensile pressure component to (default is 0.0). p_yy : float, optional The value to relax the y tensile pressure component to (default is 0.0). p_zz : float, optional The value to relax the z tensile pressure component to (default is 0.0). p_xy : float, optional The value to relax the xy shear pressure component to (default is 0.0). p_xz : float, optional The value to relax the xz shear pressure component to (default is 0.0). p_yz : float, optional The value to relax the yz shear pressure component to (default is 0.0). dispmult : float, optional Multiplier for applying a random displacement to all atomic positions prior to relaxing. Default value is 0.0. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). pressure_unit : str, optional The unit of pressure to calculate the elastic constants in (default is 'GPa'). maxcycles : int, optional The maximum number of times the minimization algorithm is called. Default value is 100. ctol : float, optional The relative tolerance used to determine if the lattice constants have converged (default is 1e-10). Returns ------- dict Dictionary of results consisting of keys: - **'relaxed_system'** (*float*) - The relaxed system. - **'E_coh'** (*float*) - The cohesive energy of the relaxed system. - **'measured_pxx'** (*float*) - The measured x tensile pressure of the relaxed system. - **'measured_pyy'** (*float*) - The measured y tensile pressure of the relaxed system. - **'measured_pzz'** (*float*) - The measured z tensile pressure of the relaxed system. - **'measured_pxy'** (*float*) - The measured xy shear pressure of the relaxed system. - **'measured_pxz'** (*float*) - The measured xz shear pressure of the relaxed system. - **'measured_pyz'** (*float*) - The measured yz shear pressure of the relaxed system. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Save initial configuration as a dump file system.dump('atom_dump', f='initial.dump') # Apply small random distortions to atoms system.atoms.pos += dispmult * np.random.rand(*system.atoms.pos.shape) - dispmult / 2 # Initialize parameters old_vects = system.box.vects converged = False # Run minimizations up to maxcycles times for cycle in range(maxcycles): old_system = deepcopy(system) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['p_xx'] = uc.get_in_units(p_xx, lammps_units['pressure']) lammps_variables['p_yy'] = uc.get_in_units(p_yy, lammps_units['pressure']) lammps_variables['p_zz'] = uc.get_in_units(p_zz, lammps_units['pressure']) lammps_variables['p_xy'] = uc.get_in_units(p_xy, lammps_units['pressure']) lammps_variables['p_xz'] = uc.get_in_units(p_xz, lammps_units['pressure']) lammps_variables['p_yz'] = uc.get_in_units(p_yz, lammps_units['pressure']) lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'minbox.template' lammps_script = 'minbox.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 and extract thermo data logfile = 'log-' + str(cycle) + '.lammps' output = lmp.run(lammps_command, lammps_script, mpi_command, logfile=logfile) thermo = output.simulations[0]['thermo'] # Clean up dump files os.remove('0.dump') last_dump_file = str(thermo.Step.values[-1]) + '.dump' renamed_dump_file = 'relax_static-' + str(cycle) + '.dump' shutil.move(last_dump_file, renamed_dump_file) # Load relaxed system system = am.load('atom_dump', renamed_dump_file, symbols=system.symbols) # Test if box dimensions have converged if np.allclose(old_vects, system.box.vects, rtol=ctol, atol=0): converged = True break else: old_vects = system.box.vects # Check for convergence if converged is False: raise RuntimeError('Failed to converge after ' + str(maxcycles) + ' cycles') # Zero out near-zero tilt factors lx = system.box.lx ly = system.box.ly lz = system.box.lz xy = system.box.xy xz = system.box.xz yz = system.box.yz if np.isclose(xy/ly, 0.0, rtol=0.0, atol=1e-10): xy = 0.0 if np.isclose(xz/lz, 0.0, rtol=0.0, atol=1e-10): xz = 0.0 if np.isclose(yz/lz, 0.0, rtol=0.0, atol=1e-10): yz = 0.0 system.box.set(lx=lx, ly=ly, lz=lz, xy=xy, xz=xz, yz=yz) system.wrap() # Build results_dict results_dict = {} results_dict['dumpfile_initial'] = 'initial.dump' results_dict['symbols_initial'] = system.symbols results_dict['dumpfile_final'] = renamed_dump_file results_dict['symbols_final'] = system.symbols results_dict['E_coh'] = uc.set_in_units(thermo.PotEng.values[-1] / system.natoms, lammps_units['energy']) results_dict['lx'] = uc.set_in_units(lx, lammps_units['length']) results_dict['ly'] = uc.set_in_units(ly, lammps_units['length']) results_dict['lz'] = uc.set_in_units(lz, lammps_units['length']) results_dict['xy'] = uc.set_in_units(xy, lammps_units['length']) results_dict['xz'] = uc.set_in_units(xz, lammps_units['length']) results_dict['yz'] = uc.set_in_units(yz, lammps_units['length']) results_dict['measured_pxx'] = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure']) results_dict['measured_pyy'] = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure']) results_dict['measured_pzz'] = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure']) results_dict['measured_pxy'] = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure']) results_dict['measured_pxz'] = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure']) results_dict['measured_pyz'] = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure']) return results_dict
def strain_system(lammps_command, system, potential, symbols, mpi_command=None, delta_strain=np.zeros(6), initial_strain=np.zeros(6), hold_atypes=[], number_of_steps=0, etol=0.0, ftol=1e-5, maxiter=10000, maxeval=100000): """ Applies strains to an atomic system in LAMMPS and relaxes the energy. Arguments: lammps_command -- command for running LAMMPS. system -- atomman.System to add the point defect to. potential -- atomman.lammps.Potential representation of a LAMMPS implemented potential. symbols -- list of element-model symbols for the Potential that correspond to system's atypes. Keyword Arguments: mpi_command -- MPI command for running LAMMPS in parallel. Default value is None (serial run). delta_strain -- strain state in 6 term Voigt to apply incrementally. Default value is all zeros. initial_strain -- strain state in 6 term Voigt to apply to the system prior to the incremental delta_strain. Default value is all zeros. number_of_steps -- number of times to apply the incremental delta_strain to the system. Default value is 0. hold_atypes -- list of atom types that should be held fixed (not allowed to relax). Default value is []. etol -- energy tolerance to use for the LAMMPS minimization. Default value is 0.0 (i.e. only uses ftol). ftol -- force tolerance to use for the LAMMPS minimization. Default value is 1e-6. maxiter -- the maximum number of iterations for the LAMMPS minimization. Default value is 100000. maxeval -- the maximum number of evaluations for the LAMMPS minimization. Default value is 100000. """ if am.tools.is_int(hold_atypes): hold_atypes = np.array([hold_atypes]) else: hold_atypes = np.asarray(hold_atypes) if len(hold_atypes) == 0: hold_info = '' else: move_atypes = np.setdiff1d(np.arange(1, system.natypes+1), hold_atypes) hold_info = '\n'.join(['', '#Fix boundary region atoms', 'group move type ' + ' '.join(np.char.mod('%d', move_atypes)), 'group hold subtract all move', 'fix nomove hold setforce 0.0 0.0 0.0', '']) #Get lammps units lammps_units = lmp.style.unit(potential.units) #Read LAMMPS input template with open('strain_system.template') as f: template = f.read() #Define lammps variables lammps_variables = {} lammps_variables['atomman_system_info'] = lmp.atom_data.dump(system, 'initial.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_pair_info'] = potential.pair_info(symbols) lammps_variables['hold_info'] = hold_info lammps_variables['energy_tolerance'] = etol lammps_variables['force_tolerance'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maximum_iterations'] = maxiter lammps_variables['maximum_evaluations'] = maxeval lammps_variables['number_of_steps'] = number_of_steps + 1 lammps_variables['delta_strain_xx'] = delta_strain[0] lammps_variables['delta_strain_yy'] = delta_strain[1] lammps_variables['delta_strain_zz'] = delta_strain[2] lammps_variables['delta_strain_xy'] = delta_strain[5] lammps_variables['delta_strain_xz'] = delta_strain[4] lammps_variables['delta_strain_yz'] = delta_strain[3] lammps_variables['initial_strain_xx'] = initial_strain[0] lammps_variables['initial_strain_yy'] = initial_strain[1] lammps_variables['initial_strain_zz'] = initial_strain[2] lammps_variables['initial_strain_xy'] = initial_strain[5] lammps_variables['initial_strain_xz'] = initial_strain[4] lammps_variables['initial_strain_yz'] = initial_strain[3] #Write lammps input script with open('strain_system.in', 'w') as f: f.write('\n'.join(iprPy.tools.fill_template(template, lammps_variables, '<', '>'))) #run lammps to relax perfect.dat output = lmp.run(lammps_command, 'strain_system.in', mpi_command) #Extract LAMMPS thermo data. lammps_step = np.asarray(output.finds('Step'), dtype=int)[1::2] E_total = uc.set_in_units(output.finds('PotEng'), lammps_units['energy'] )[1::2] p_xx = uc.set_in_units(output.finds('Pxx'), lammps_units['pressure'])[1::2] p_yy = uc.set_in_units(output.finds('Pyy'), lammps_units['pressure'])[1::2] p_zz = uc.set_in_units(output.finds('Pzz'), lammps_units['pressure'])[1::2] p_xy = uc.set_in_units(output.finds('Pxy'), lammps_units['pressure'])[1::2] p_xz = uc.set_in_units(output.finds('Pxz'), lammps_units['pressure'])[1::2] p_yz = uc.set_in_units(output.finds('Pyz'), lammps_units['pressure'])[1::2] strain_step = np.asarray(output.finds('s_step'), dtype=int)[1::2] return {'lammps_step':lammps_step, 'E_total':E_total, 'p_xx':p_xx, 'p_yy':p_yy, 'p_zz':p_zz, 'p_xy':p_xy, 'p_xz':p_xz, 'p_yz':p_yz, 'strain_step':strain_step}
def e_vs_r_scan(lammps_command: str, system: am.System, potential: am.lammps.Potential, mpi_command: Optional[str] = None, ucell: Optional[am.System] = None, rmin: float = uc.set_in_units(2.0, 'angstrom'), rmax: float = uc.set_in_units(6.0, 'angstrom'), rsteps: int = 200) -> dict: """ Performs a cohesive energy scan over a range of interatomic spaces, r. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. ucell : atomman.System, optional The fundamental unit cell correspodning to system. This is used to convert system dimensions to cell dimensions. If not given, ucell will be taken as system. rmin : float, optional The minimum r spacing to use (default value is 2.0 angstroms). rmax : float, optional The maximum r spacing to use (default value is 6.0 angstroms). rsteps : int, optional The number of r spacing steps to evaluate (default value is 200). Returns ------- dict Dictionary of results consisting of keys: - **'r_values'** (*numpy.array of float*) - All interatomic spacings, r, explored. - **'a_values'** (*numpy.array of float*) - All unit cell a lattice constants corresponding to the values explored. - **'Ecoh_values'** (*numpy.array of float*) - The computed cohesive energies for each r value. - **'min_cell'** (*list of atomman.System*) - Systems corresponding to the minima identified in the Ecoh_values. """ # Make system a deepcopy of itself (protect original from changes) system = deepcopy(system) # Set ucell = system if ucell not given if ucell is None: ucell = system # Calculate the r/a ratio for the unit cell r_a = ucell.r0() / ucell.box.a # Get ratios of lx, ly, and lz of system relative to a of ucell lx_a = system.box.a / ucell.box.a ly_a = system.box.b / ucell.box.a lz_a = system.box.c / ucell.box.a alpha = system.box.alpha beta = system.box.beta gamma = system.box.gamma # Build lists of values r_values = np.linspace(rmin, rmax, rsteps) a_values = r_values / r_a Ecoh_values = np.empty(rsteps) # Loop over values for i in range(rsteps): # Rescale system's box a = a_values[i] system.box_set(a=a * lx_a, b=a * ly_a, c=a * lz_a, alpha=alpha, beta=beta, gamma=gamma, scale=True) # Get lammps units lammps_units = lmp.style.unit(potential.units) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='atom.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info # Write lammps input script lammps_script = 'run0.in' template = read_calc_file('iprPy.calculation.E_vs_r_scan', 'run0.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run lammps and extract data try: output = lmp.run(lammps_command, script_name=lammps_script, mpi_command=mpi_command) except: Ecoh_values[i] = np.nan else: thermo = output.simulations[0]['thermo'] if output.lammps_date < datetime.date(2016, 8, 1): Ecoh_values[i] = uc.set_in_units(thermo.peatom.values[-1], lammps_units['energy']) else: Ecoh_values[i] = uc.set_in_units(thermo.v_peatom.values[-1], lammps_units['energy']) # Rename log.lammps try: shutil.move('log.lammps', 'run0-' + str(i) + '-log.lammps') except: pass if len(Ecoh_values[np.isfinite(Ecoh_values)]) == 0: raise ValueError( 'All LAMMPS runs failed. Potential likely invalid or incompatible.' ) # Find unit cell systems at the energy minimums min_cells = [] for i in range(1, rsteps - 1): if (Ecoh_values[i] < Ecoh_values[i - 1] and Ecoh_values[i] < Ecoh_values[i + 1]): a = a_values[i] cell = deepcopy(ucell) cell.box_set(a=a, b=a * ucell.box.b / ucell.box.a, c=a * ucell.box.c / ucell.box.a, alpha=alpha, beta=beta, gamma=gamma, scale=True) min_cells.append(cell) # Collect results results_dict = {} results_dict['r_values'] = r_values results_dict['a_values'] = a_values results_dict['Ecoh_values'] = Ecoh_values results_dict['min_cell'] = min_cells return results_dict
def dislocationarraystress(lammps_command, system, potential, temperature, mpi_command=None, sigma_xz=0.0, sigma_yz=0.0, runsteps=100000, thermosteps=100, dumpsteps=None, randomseed=None, bwidth=None, rigidbounds=False): """ Applies a constant external shearing stress to a periodic array of dislocations atomic system. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The bulk system to add the defect to. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. temperature : float The temperature to run the simulation at. mpi_command : str or None, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. sigma_xz : float, optional The xz shear stress to apply to the system through the boundary atoms. Default value is 0.0. sigma_yz : float, optional The yz shear stress to apply to the system through the boundary atoms. Default value is 0.0. runsteps : int, optional The total number of steps to run the simulation for. Default value is 100000. thermosteps : int, optional The system-wide thermo data will be outputted every this many steps. Default value is 100. dumpsteps : int, optional The atomic configurations will be saved to LAMMPS dump files every this many steps. Default value is equal to runsteps, which will only save the initial and final configurations. randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities. Default is None which will select a random int between 1 and 900000000. bwidth : float, optional The thickness of the boundary region. Default value is 10 Angstroms. rigidbounds : bool, optional If True, the atoms in the boundary regions will be treated as a rigid block such that they move as one and do not allow internal atomic relaxations. Default value is False, in which case the boundaries will be free surfaces. Returns ------- dict Dictionary of results consisting of keys: - **'dumpfile_base'** (*str*) - The filename of the LAMMPS dump file for the relaxed base system. - **'symbols_base'** (*list of str*) - The list of element-model symbols for the Potential that correspond to the base system's atypes. - **'Stroh_preln'** (*float*) - The pre-logarithmic factor in the dislocation's self-energy expression. - **'Stroh_K_tensor'** (*numpy.array of float*) - The energy coefficient tensor based on the dislocation's Stroh solution. - **'dumpfile_disl'** (*str*) - The filename of the LAMMPS dump file for the relaxed dislocation monopole system. - **'symbols_disl'** (*list of str*) - The list of element-model symbols for the Potential that correspond to the dislocation monopole system's atypes. - **'E_total_disl'** (*float*) - The total potential energy of the dislocation monopole system. """ try: # Get script's location if __file__ exists script_dir = Path(__file__).parent except: # Use cwd otherwise script_dir = Path.cwd() # Set default values if bwidth is None: bwidth = uc.set_in_units(10, 'angstrom') if randomseed is None: randomseed = random.randint(1, 900000000) # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='initial.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['temperature'] = temperature stress_unit = lammps_units['force'] + '/' + lammps_units['length'] + '^2' lammps_variables['sigma_xz'] = uc.get_in_units(sigma_xz, stress_unit) lammps_variables['sigma_yz'] = uc.get_in_units(sigma_yz, stress_unit) lammps_variables['dumpsteps'] = dumpsteps lammps_variables['runsteps'] = runsteps lammps_variables['thermosteps'] = thermosteps lammps_variables['randomseed'] = randomseed lammps_variables['bwidth'] = uc.get_in_units(bwidth, lammps_units['length']) lammps_variables['tdamp'] = 100 * lmp.style.timestep(potential.units) lammps_variables['timestep'] = lmp.style.timestep(potential.units) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script if rigidbounds is True: template_file = os.path.join(script_dir, 'dislarray_rigid_stress.template') else: template_file = os.path.join(script_dir, 'dislarray_free_stress.template') lammps_script = 'dislarray_stress.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, mpi_command) thermo = output.simulations[-1]['thermo'] steps = thermo.Step.values times = uc.set_in_units(steps * lmp.style.timestep(potential.units), lammps_units['time']) # Read user-defined thermo data if output.lammps_date < datetime.date(2016, 8, 1): strains_xz = thermo['strain_xz'].values strains_yz = thermo['strain_yz'].values else: strains_xz = thermo['v_strain_xz'].values strains_yz = thermo['v_strain_yz'].values # Compute average strain rates strainrate_xz, b = np.polyfit(times, strains_xz, 1) strainrate_yz, b = np.polyfit(times, strains_yz, 1) # Extract output values results_dict = {} results_dict['times'] = times results_dict['strains_xz'] = strains_xz results_dict['strains_yz'] = strains_yz results_dict['strainrate_xz'] = strainrate_xz results_dict['strainrate_yz'] = strainrate_yz return results_dict
def calc_cij(lammps_exe, ucell, potential, symbols, p_xx=0.0, p_yy=0.0, p_zz=0.0): """Runs cij_script and returns current Cij, stress, Ecoh, and new ucell guess.""" #setup system and pair info system_info = lmp.sys_gen(units = potential.units, atom_style = potential.atom_style, ucell = ucell, size = np.array([[0,3], [0,3], [0,3]])) pair_info = potential.pair_info(symbols) #create script and run with open('cij.in','w') as f: f.write(cij_script(system_info, pair_info)) data = lmp.run(lammps_exe, 'cij.in') #get units for pressure and energy used by LAMMPS simulation lmp_units = lmp.style.unit(potential.units) p_unit = lmp_units['pressure'] e_unit = lmp_units['energy'] #Extract thermo values. Each term ranges i=0-12 where i=0 is undeformed #The remaining values are for -/+ strain pairs in the six unique directions lx = np.array(data.finds('Lx')) ly = np.array(data.finds('Ly')) lz = np.array(data.finds('Lz')) xy = np.array(data.finds('Xy')) xz = np.array(data.finds('Xz')) yz = np.array(data.finds('Yz')) pxx = uc.set_in_units(np.array(data.finds('Pxx')), p_unit) pyy = uc.set_in_units(np.array(data.finds('Pyy')), p_unit) pzz = uc.set_in_units(np.array(data.finds('Pzz')), p_unit) pxy = uc.set_in_units(np.array(data.finds('Pxy')), p_unit) pxz = uc.set_in_units(np.array(data.finds('Pxz')), p_unit) pyz = uc.set_in_units(np.array(data.finds('Pyz')), p_unit) pe = uc.set_in_units(np.array(data.finds('peatom')), e_unit) #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.tools.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 = ucell.box.a / (S[0,0]*s_xx + S[0,1]*s_yy + S[0,2]*s_zz + 1) new_b = ucell.box.b / (S[1,0]*s_xx + S[1,1]*s_yy + S[1,2]*s_zz + 1) new_c = ucell.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) ucell_new = deepcopy(ucell) ucell_new.box_set(vects=newbox.vects, scale=True) return {'C':C, 'stress':stress, 'ecoh':pe[0], 'ucell_new':ucell_new}
def phononcalc(lammps_command, ucell, potential, mpi_command=None, a_mult=3, b_mult=3, c_mult=3, distance=0.01, symprec=1e-5, savefile='phonopy_params.yaml', plot=True, lammps_date=None): """ Uses phonopy to compute the phonons for a unit cell structure using a LAMMPS interatomic potential. Parameters ---------- lammps_command :str Command for running LAMMPS. ucell : atomman.System The unit cell system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. a_mult : int, optional The a size multiplier to use on ucell before running the phonon calculation. Must be an int and not a tuple. Default value is 3. b_mult : int, optional The b size multiplier to use on ucell before running the phonon calculation. Must be an int and not a tuple. Default value is 3. c_mult : int, optional The c size multiplier to use on ucell before running the phonon calculation. Must be an int and not a tuple. Default value is 3. distance : float, optional The atomic displacement distance used for computing the phonons. Default value is 0.01. symprec : float, optional Absolute length tolerance to use in identifying symmetry of atomic sites and system boundaries. Default value is 1e-5. savefile: str, optional The name of the phonopy yaml backup file. Default value is 'phonopy_params.yaml'. plot : bool, optional Flag indicating if band structure and DOS figures are to be generated. Default value is True. lammps_date : datetime.date, optional The version date associated with lammps_command. If not given, the version will be identified. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date if lammps_date is None: lammps_date = lmp.checkversion(lammps_command)['date'] # Use spglib to find primitive unit cell of ucell convcell = ucell.dump('spglib_cell') primcell = spglib.find_primitive(convcell, symprec=symprec) primucell = am.load('spglib_cell', primcell, symbols=ucell.symbols).normalize() # Initialize Phonopy object phonon = phonopy.Phonopy(primucell.dump('phonopy_Atoms', symbols=potential.elements( primucell.symbols)), [[a_mult, 0, 0], [0, b_mult, 0], [0, 0, c_mult]], factor=phonopy.units.VaspToTHz) phonon.generate_displacements(distance=distance) # Loop over displaced supercells to compute forces forcearrays = [] for supercell in phonon.supercells_with_displacements: # Save to LAMMPS data file system = am.load('phonopy_Atoms', supercell, symbols=primucell.symbols) system_info = system.dump('atom_data', f='disp.dat', potential=potential) # Define lammps variables lammps_variables = {} lammps_variables['atomman_system_pair_info'] = system_info # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script lammps_script = 'phonon.in' template = read_calc_file('iprPy.calculation.phonon', 'phonon.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run LAMMPS lmp.run(lammps_command, script_name=lammps_script, mpi_command=mpi_command) # Extract forces from dump file forcestructure = am.load('atom_dump', 'forces.dump') forces = uc.set_in_units(forcestructure.atoms.force, lammps_units['force']) forcearrays.append(forces) results = {} # Set computed forces phonon.set_forces(forcearrays) # Save to yaml file phonon.save(savefile) # Compute band structure phonon.produce_force_constants() phonon.auto_band_structure(plot=plot) results['band_structure'] = phonon.get_band_structure_dict() if plot: plt.ylabel('Frequency (THz)') plt.savefig(Path('.', 'band.png'), dpi=400) plt.close() # Compute density of states phonon.auto_total_dos(plot=False) phonon.auto_projected_dos(plot=False) dos = phonon.get_total_dos_dict() dos['frequency'] = uc.set_in_units(dos.pop('frequency_points'), 'THz') dos['projected_dos'] = phonon.get_projected_dos_dict()['projected_dos'] results['dos'] = dos # Compute thermal properties phonon.run_thermal_properties() results['thermal_properties'] = phonon.get_thermal_properties_dict() results['phonon'] = phonon return results
def relax_system(lammps_command, system, potential, mpi_command=None, etol=0.0, ftol=0.0, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom')): """ Sets up and runs the min.in LAMMPS script for performing an energy/force minimization to relax a system. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'logfile'** (*str*) - The name of the LAMMPS log file. - **'initialdatafile'** (*str*) - The name of the LAMMPS data file used to import an inital configuration. - **'initialdumpfile'** (*str*) - The name of the LAMMPS dump file corresponding to the inital configuration. - **'finaldumpfile'** (*str*) - The name of the LAMMPS dump file corresponding to the relaxed configuration. - **'potentialenergy'** (*float*) - The total potential energy of the relaxed system. """ # Ensure all atoms are within the system's box system.wrap() # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} # Generate system and pair info system_info = system.dump('atom_data', f='system.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) # Pass in run parameters lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length']) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%i %i %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'min.template' lammps_script = 'min.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, mpi_command) # Extract output values thermo = output.simulations[-1]['thermo'] results = {} results['logfile'] = 'log.lammps' results['initialdatafile'] = 'system.dat' results['initialdumpfile'] = 'atom.0' results['finaldumpfile'] = 'atom.%i' % thermo.Step.values[-1] results['potentialenergy'] = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) return results
def phonon_quasiharmonic(lammps_command: str, ucell: am.System, potential: lmp.Potential, mpi_command: Optional[str] = None, a_mult: int = 3, b_mult: int = 3, c_mult: int = 3, distance: float = 0.01, symprec: float = 1e-5, strainrange: float = 0.01, numstrains: int = 5) -> dict: """ Function that performs phonon and quasiharmonic approximation calculations using phonopy and LAMMPS. Parameters ---------- lammps_command :str Command for running LAMMPS. ucell : atomman.System The unit cell system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. a_mult : int, optional The a size multiplier to use on ucell before running the phonon calculation. Must be an int and not a tuple. Default value is 3. b_mult : int, optional The b size multiplier to use on ucell before running the phonon calculation. Must be an int and not a tuple. Default value is 3. c_mult : int, optional The c size multiplier to use on ucell before running the phonon calculation. Must be an int and not a tuple. Default value is 3. distance : float, optional The atomic displacement distance used for computing the phonons. Default value is 0.01. symprec : float, optional Absolute length tolerance to use in identifying symmetry of atomic sites and system boundaries. Default value is 1e-5. strainrange : float, optional The range of strains to apply to the unit cell to use with the quasiharmonic calculations. Default value is 0.01. numstrains : int, optional The number of strains to use for the quasiharmonic calculations. Must be an odd integer. If 1, then the quasiharmonic calculations will not be performed. Default value is 5. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) # Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Get original box vectors vects = ucell.box.vects # Generate the range of strains if numstrains == 1: zerostrain = phononcalc(lammps_command, ucell, potential, mpi_command=mpi_command, a_mult=a_mult, b_mult=b_mult, c_mult=c_mult, distance=distance, symprec=symprec, lammps_date=lammps_date) phonons = [zerostrain['phonon']] qha = None elif numstrains % 2 == 0 or numstrains < 5: raise ValueError( 'Invalid number of strains: must be odd and 1 or >= 5') else: strains = np.linspace(-strainrange, strainrange, numstrains) istrains = np.linspace(-(numstrains - 1) / 2, (numstrains - 1) / 2, numstrains, dtype=int) volumes = [] energies = [] phonons = [] temperatures = None free_energy = None heat_capacity = None entropy = None # Loop over all strains for istrain, strain in zip(istrains, strains): # Identify the zero strain run if istrain == 0: zerostrainrun = True savefile = 'phonopy_params.yaml' else: zerostrainrun = False savefile = f'phonopy_params_{istrain}.yaml' # Generate system at the strain newvects = vects * (1 + strain) ucell.box_set(vects=newvects, scale=True) volumes.append(ucell.box.volume) system = ucell.supersize(a_mult, b_mult, c_mult) # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='disp.dat', potential=potential) lammps_variables['atomman_system_pair_info'] = system_info # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script lammps_script = 'phonon.in' template = read_calc_file('iprPy.calculation.phonon', 'phonon.template') with open(lammps_script, 'w') as f: f.write(filltemplate(template, lammps_variables, '<', '>')) # Run LAMMPS output = lmp.run(lammps_command, script_name='phonon.in', mpi_command=mpi_command) # Extract system energy thermo = output.simulations[0]['thermo'] energy = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) # Scale energy by sizemults and append to list energies.append(energy / (a_mult * b_mult * c_mult)) # Compute phonon info for ucell phononinfo = phononcalc(lammps_command, ucell, potential, mpi_command=mpi_command, a_mult=a_mult, b_mult=b_mult, c_mult=c_mult, distance=distance, symprec=symprec, savefile=savefile, plot=zerostrainrun, lammps_date=lammps_date) phonons.append(phononinfo['phonon']) # Extract temperature values from the first run if temperatures is None: temperatures = phononinfo['thermal_properties']['temperatures'] # Initialize QHA input arrays free_energy = np.empty((len(temperatures), len(strains))) heat_capacity = np.empty((len(temperatures), len(strains))) entropy = np.empty((len(temperatures), len(strains))) # Get values for zerostrainrun if zerostrainrun is True: zerostrain = phononinfo # Copy values to qha input arrays free_energy[:, istrain] = phononinfo['thermal_properties'][ 'free_energy'] entropy[:, istrain] = phononinfo['thermal_properties']['entropy'] heat_capacity[:, istrain] = phononinfo['thermal_properties'][ 'heat_capacity'] # Compute qha try: qha = phonopy.PhonopyQHA(volumes=volumes, electronic_energies=energies, temperatures=temperatures, free_energy=free_energy, cv=heat_capacity, entropy=entropy) except: qha = None results = {} # Add phonopy objects results['phonon_objects'] = phonons results['qha_object'] = qha # Extract zerostrain properties results['band_structure'] = zerostrain['band_structure'] results['density_of_states'] = zerostrain['dos'] # Convert units on thermal properties results['thermal_properties'] = zerostrain['thermal_properties'] results['thermal_properties']['temperature'] = results[ 'thermal_properties'].pop('temperatures') results['thermal_properties']['Helmholtz'] = uc.set_in_units( results['thermal_properties'].pop('free_energy'), 'kJ/mol') results['thermal_properties']['entropy'] = uc.set_in_units( results['thermal_properties'].pop('entropy'), 'J/K/mol') results['thermal_properties']['heat_capacity_v'] = uc.set_in_units( results['thermal_properties'].pop('heat_capacity'), 'J/K/mol') if qha is not None: # Create QHA plots qha.plot_bulk_modulus() plt.xlabel('Volume ($Å^3$)', size='large') plt.ylabel('Energy ($eV$)', size='large') plt.savefig('bulk_modulus.png', dpi=400, bbox_inches='tight') plt.close() qha.plot_helmholtz_volume() plt.savefig('helmholtz_volume.png', dpi=400) plt.close() # Package volume vs energy scans results['volume_scan'] = {} results['volume_scan']['volume'] = np.array(volumes) results['volume_scan']['strain'] = strains results['volume_scan']['energy'] = np.array(energies) # Compute and add QHA properties properties = qha.get_bulk_modulus_parameters() results['E0'] = uc.set_in_units(properties[0], 'eV') results['B0'] = uc.set_in_units(properties[1], 'eV/angstrom^3') results['B0prime'] = uc.set_in_units(properties[2], 'eV/angstrom^3') results['V0'] = uc.set_in_units(properties[3], 'angstrom^3') results['thermal_properties']['volume'] = uc.set_in_units( np.hstack([qha.volume_temperature, np.nan]), 'angstrom^3') results['thermal_properties']['thermal_expansion'] = np.hstack( [qha.thermal_expansion, np.nan]) results['thermal_properties']['Gibbs'] = uc.set_in_units( np.hstack([qha.gibbs_temperature, np.nan]), 'eV') results['thermal_properties']['bulk_modulus'] = uc.set_in_units( np.hstack([qha.bulk_modulus_temperature, np.nan]), 'GPa') results['thermal_properties'][ 'heat_capacity_p_numerical'] = uc.set_in_units( np.hstack([qha.heat_capacity_P_numerical, np.nan]), 'J/K/mol') results['thermal_properties'][ 'heat_capacity_p_polyfit'] = uc.set_in_units( np.hstack([qha.heat_capacity_P_polyfit, np.nan]), 'J/K/mol') results['thermal_properties']['gruneisen'] = np.hstack( [qha.gruneisen_temperature, np.nan]) return results
def disl_relax(lammps_command, system, potential, mpi_command=None, annealtemp=0.0, randomseed=None, etol=0.0, ftol=1e-6, maxiter=10000, maxeval=100000, dmax=uc.set_in_units(0.01, 'angstrom')): """ Sets up and runs the disl_relax.in LAMMPS script for relaxing a dislocation monopole system. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. annealtemp : float, optional The temperature to perform a dynamic relaxation at. (Default is 0.0, which will skip the dynamic relaxation.) randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities and with the Langevin thermostat. (Default is None which will select a random int between 1 and 900000000.) etol : float, optional The energy tolerance for the structure minimization. This value is unitless. (Default is 0.0). ftol : float, optional The force tolerance for the structure minimization. This value is in units of force. (Default is 0.0). maxiter : int, optional The maximum number of minimization iterations to use (default is 10000). maxeval : int, optional The maximum number of minimization evaluations to use (default is 100000). dmax : float, optional The maximum distance in length units that any atom is allowed to relax in any direction during a single minimization iteration (default is 0.01 Angstroms). Returns ------- dict Dictionary of results consisting of keys: - **'logfile'** (*str*) - The name of the LAMMPS log file. - **'dumpfile'** (*str*) - The name of the LAMMPS dump file for the relaxed system. - **'E_total'** (*float*) - The total potential energy for the relaxed system. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='system.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) lammps_variables['anneal_info'] = anneal_info(annealtemp, randomseed, potential.units) lammps_variables['etol'] = etol lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force']) lammps_variables['maxiter'] = maxiter lammps_variables['maxeval'] = maxeval lammps_variables['dmax'] = dmax lammps_variables['group_move'] = ' '.join( np.array(range(1, system.natypes // 2 + 1), dtype=str)) # Set dump_modify format based on dump_modify_version if lammps_date < datetime.date(2016, 8, 3): lammps_variables[ 'dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'disl_relax.template' lammps_script = 'disl_relax.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, mpi_command) thermo = output.simulations[-1]['thermo'] # Extract output values results = {} results['logfile'] = 'log.lammps' results['dumpfile'] = '%i.dump' % thermo.Step.values[-1] results['E_total'] = uc.set_in_units(thermo.PotEng.values[-1], lammps_units['energy']) return results
def relax_dynamic(lammps_command, system, potential, mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0, p_xy=0.0, p_xz=0.0, p_yz=0.0, temperature=0.0, integrator=None, runsteps=220000, thermosteps=100, dumpsteps=None, equilsteps=20000, randomseed=None): """ Performs a full dynamic relax on a given system at the given temperature to the specified pressure state. Parameters ---------- lammps_command :str Command for running LAMMPS. system : atomman.System The system to perform the calculation on. potential : atomman.lammps.Potential The LAMMPS implemented potential to use. symbols : list of str The list of element-model symbols for the Potential that correspond to system's atypes. mpi_command : str, optional The MPI command for running LAMMPS in parallel. If not given, LAMMPS will run serially. p_xx : float, optional The value to relax the x tensile pressure component to (default is 0.0). p_yy : float, optional The value to relax the y tensile pressure component to (default is 0.0). p_zz : float, optional The value to relax the z tensile pressure component to (default is 0.0). temperature : float, optional The temperature to relax at (default is 0.0). runsteps : int, optional The number of integration steps to perform (default is 220000). integrator : str or None, optional The integration method to use. Options are 'npt', 'nvt', 'nph', 'nve', 'nve+l', 'nph+l'. The +l options use Langevin thermostat. (Default is None, which will use 'nph+l' for temperature == 0, and 'npt' otherwise.) thermosteps : int, optional Thermo values will be reported every this many steps (default is 100). dumpsteps : int or None, optional Dump files will be saved every this many steps (default is None, which sets dumpsteps equal to runsteps). equilsteps : int, optional The number of timesteps at the beginning of the simulation to exclude when computing average values (default is 20000). randomseed : int or None, optional Random number seed used by LAMMPS in creating velocities and with the Langevin thermostat. (Default is None which will select a random int between 1 and 900000000.) Returns ------- dict Dictionary of results consisting of keys: - **'relaxed_system'** (*float*) - The relaxed system. - **'E_coh'** (*float*) - The mean measured cohesive energy. - **'measured_pxx'** (*float*) - The measured x tensile pressure of the relaxed system. - **'measured_pyy'** (*float*) - The measured y tensile pressure of the relaxed system. - **'measured_pzz'** (*float*) - The measured z tensile pressure of the relaxed system. - **'measured_pxy'** (*float*) - The measured xy shear pressure of the relaxed system. - **'measured_pxz'** (*float*) - The measured xz shear pressure of the relaxed system. - **'measured_pyz'** (*float*) - The measured yz shear pressure of the relaxed system. - **'temp'** (*float*) - The mean measured temperature. - **'E_coh_std'** (*float*) - The standard deviation in the measured cohesive energy values. - **'measured_pxx_std'** (*float*) - The standard deviation in the measured x tensile pressure of the relaxed system. - **'measured_pyy_std'** (*float*) - The standard deviation in the measured y tensile pressure of the relaxed system. - **'measured_pzz_std'** (*float*) - The standard deviation in the measured z tensile pressure of the relaxed system. - **'measured_pxy_std'** (*float*) - The standard deviation in the measured xy shear pressure of the relaxed system. - **'measured_pxz_std'** (*float*) - The standard deviation in the measured xz shear pressure of the relaxed system. - **'measured_pyz_std'** (*float*) - The standard deviation in the measured yz shear pressure of the relaxed system. - **'temp_std'** (*float*) - The standard deviation in the measured temperature values. """ # Get lammps units lammps_units = lmp.style.unit(potential.units) #Get lammps version date lammps_date = lmp.checkversion(lammps_command)['date'] # Handle default values if dumpsteps is None: dumpsteps = runsteps # Define lammps variables lammps_variables = {} system_info = system.dump('atom_data', f='init.dat', units=potential.units, atom_style=potential.atom_style) lammps_variables['atomman_system_info'] = system_info lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols) integ_info = integrator_info(integrator=integrator, p_xx=p_xx, p_yy=p_yy, p_zz=p_zz, p_xy=p_xy, p_xz=p_xz, p_yz=p_yz, temperature=temperature, randomseed=randomseed, units=potential.units) lammps_variables['integrator_info'] = integ_info lammps_variables['thermosteps'] = thermosteps lammps_variables['runsteps'] = runsteps lammps_variables['dumpsteps'] = dumpsteps # Set compute stress/atom based on LAMMPS version if lammps_date < datetime.date(2014, 2, 12): lammps_variables['stressterm'] = '' else: lammps_variables['stressterm'] = 'NULL' # Set dump_modify_format based on lammps_date if lammps_date < datetime.date(2016, 8, 3): lammps_variables['dump_modify_format'] = '"%d %d %.13e %.13e %.13e %.13e"' else: lammps_variables['dump_modify_format'] = 'float %.13e' # Write lammps input script template_file = 'full_relax.template' lammps_script = 'full_relax.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, mpi_command) # Extract LAMMPS thermo data. results = {} thermo = output.simulations[0]['thermo'] results['dumpfile_initial'] = '0.dump' results['symbols_initial'] = system.symbols # Load relaxed system from dump file last_dump_file = str(thermo.Step.values[-1])+'.dump' results['dumpfile_final'] = last_dump_file system = am.load('atom_dump', last_dump_file, symbols=system.symbols) results['symbols_final'] = system.symbols # Only consider values where Step >= equilsteps thermo = thermo[thermo.Step >= equilsteps] results['nsamples'] = len(thermo) # Get cohesive energy estimates natoms = system.natoms results['E_coh'] = uc.set_in_units(thermo.PotEng.mean() / natoms, lammps_units['energy']) results['E_coh_std'] = uc.set_in_units(thermo.PotEng.std() / natoms, lammps_units['energy']) results['lx'] = uc.set_in_units(thermo.Lx.mean(), lammps_units['length']) results['lx_std'] = uc.set_in_units(thermo.Lx.std(), lammps_units['length']) results['ly'] = uc.set_in_units(thermo.Ly.mean(), lammps_units['length']) results['ly_std'] = uc.set_in_units(thermo.Ly.std(), lammps_units['length']) results['lz'] = uc.set_in_units(thermo.Lz.mean(), lammps_units['length']) results['lz_std'] = uc.set_in_units(thermo.Lz.std(), lammps_units['length']) results['xy'] = uc.set_in_units(thermo.Xy.mean(), lammps_units['length']) results['xy_std'] = uc.set_in_units(thermo.Xy.std(), lammps_units['length']) results['xz'] = uc.set_in_units(thermo.Xz.mean(), lammps_units['length']) results['xz_std'] = uc.set_in_units(thermo.Xz.std(), lammps_units['length']) results['yz'] = uc.set_in_units(thermo.Yz.mean(), lammps_units['length']) results['yz_std'] = uc.set_in_units(thermo.Yz.std(), lammps_units['length']) results['measured_pxx'] = uc.set_in_units(thermo.Pxx.mean(), lammps_units['pressure']) results['measured_pxx_std'] = uc.set_in_units(thermo.Pxx.std(), lammps_units['pressure']) results['measured_pyy'] = uc.set_in_units(thermo.Pyy.mean(), lammps_units['pressure']) results['measured_pyy_std'] = uc.set_in_units(thermo.Pyy.std(), lammps_units['pressure']) results['measured_pzz'] = uc.set_in_units(thermo.Pzz.mean(), lammps_units['pressure']) results['measured_pzz_std'] = uc.set_in_units(thermo.Pzz.std(), lammps_units['pressure']) results['measured_pxy'] = uc.set_in_units(thermo.Pxy.mean(), lammps_units['pressure']) results['measured_pxy_std'] = uc.set_in_units(thermo.Pxy.std(), lammps_units['pressure']) results['measured_pxz'] = uc.set_in_units(thermo.Pxz.mean(), lammps_units['pressure']) results['measured_pxz_std'] = uc.set_in_units(thermo.Pxz.std(), lammps_units['pressure']) results['measured_pyz'] = uc.set_in_units(thermo.Pyz.mean(), lammps_units['pressure']) results['measured_pyz_std'] = uc.set_in_units(thermo.Pyz.std(), lammps_units['pressure']) results['temp'] = thermo.Temp.mean() results['temp_std'] = thermo.Temp.std() return results