def optimize_pm6(name, examples, param_string, starting_params, queue=None): from scipy.optimize import minimize examples = [structures.Struct(name=example, atoms=atoms(example)) for example in examples] for e in examples: e.bonds = [(b.atoms[0].index - 1, b.atoms[1].index - 1) for b in geometry.get_bonds(e.atoms)] n_bonds = sum([len(e.bonds) for e in examples]) counter = [0] def pm6_error(params): # Run Gaussian jobs with new parameters for i, example in enumerate(examples): running_jobs = [job('%s-%d-%d' % (name, counter[0], i), 'PM6=(Input,Print) Opt=Loose', example.atoms, extra_section=param_string % tuple(params), queue=queue, force=True)] # Wait for all jobs to finish for j in running_jobs: j.wait() # Get forces and energies resulting from new parameters geom_error = 0.0 for i, example in enumerate(examples): try: new_energy, new_atoms = parse_atoms( '%s-%d-%d' % (name, counter[0], i), check_convergence=False) except: print '%s-%d-%d' % (name, counter[0], i), 'has no data' exit() if parse_atoms('%s-%d-%d' % (name, counter[0], i)) is None: print '%s-%d-%d' % (name, counter[0], i),\ 'did not converge fully' # Compare results for b in example.bonds: d1 = geometry.dist(example.atoms[b[0]], example.atoms[b[1]]) d2 = geometry.dist(new_atoms[b[0]], new_atoms[b[1]]) geom_error += (d1 - d2)**2 error = geom_error / n_bonds print error**0.5, params counter[0] += 1 return error minimize(pm6_error, starting_params, method='Nelder-Mead', options={'disp': True})
def __init__(self, name, global_system=None, queue=None, procs=1, mem=1000, priority=100, xhosts=None): self.task_list = {} self.task_order = [] self.name = name self.global_system = global_system self.queue = queue self.procs = procs self.mem = mem self.priority = priority self.xhosts = xhosts self.parameters = structures.Struct() self.data = None
Cl_, Cl = 21, 344 Pb_, Pb = 111, 907 Cs_, Cs = 72, 352 Si_, Si = 112, 908 O_, O = 113, 909 H_ = 54 N_ = 53 HN = 233 tersoff_atoms = [Pb, Cl, Cs] extra_Pb = { Pb: structures.Struct(index=Pb, index2=Pb_, element_name='Pb', element=82, mass=207.2, charge=0.4, vdw_e=10.1, vdw_r=3.0), } extra_Si = { Si: structures.Struct(index=Si, index2=Si_, element_name='Si', element=14, mass=28.0855, charge=4, vdw_e=10.1, vdw_r=3.3), }
"DMF":{"density":0.95, "dielectric":36.7}, "DMSO":{"density":1.0, "dielectric":46.7}, "NMP":{"density":1.1, "dielectric":32.3}, "ACETONE":{"density":0.78, "dielectric":20.7}, "METHACROLEIN":{"density":0.85, "dielectric":10.9}, "NITROMETHANE":{"density":1.14, "dielectric":35.9}} for key in solvent.keys(): solvent[key.lower()] = solvent[key] extra = { #(47, 3, 46):(85.00, 120.00), (47, 47, 3, 46):(0.0, 14.0, 0.0, 0.0), #Pb: utils.Struct(index=Pb, index2=Pb_, element_name='Pb', element=82, mass=207.2, charge=2.0, vdw_e=0., vdw_r=4.0), #Cl: utils.Struct(index=Cl, index2=Cl_, element_name='Cl', element=17, mass=35.45, charge=-0.0, vdw_e=0.01, vdw_r=4.0), } default_angles = {"type":structures.Struct(), "angle":110.7, "style":"harmonic", "e":37.5, "index2s":(13, 13, 46)} # For debugging #default_routes = ["! HF SV ECP{def2-TZVP}", # "! OPT HF SV ECP{def2-TZVP} LooseOpt", # "! OPT B97-D3 SV GCP(DFT/TZ) ECP{def2-TZVP} Grid7 SlowConv LooseOpt", # "! OPT B97-D3 SV GCP(DFT/TZ) ECP{def2-TZVP} Grid7 SlowConv LooseOpt"] # For actual use default_routes = ["! OPT B97-D3 SV GCP(DFT/TZ) ECP{def2-TZVP} Grid7 SlowConv LooseOpt", "! OPT B97-D3 def2-TZVP GCP(DFT/TZ) ECP{def2-TZVP} Grid7 SlowConv", "! OPT PW6B95 def2-TZVP GCP(DFT/TZ) ECP{def2-TZVP} Grid7 SlowConv"]
def run_lammps(system, systems_by_composition, tersoff_atoms, lj_params, atom_list, tersoff_params, run_name): """ Run a single step calculation using the given parameters. **Parameters** system: systems_by_composition: tersoff_atoms: lj_params: atom_list: tersoff_params: run_name: **Returns** Stuff. """ # Ensure cwd/lammps/run_name exists directory_to_work = '%s/lammps/%s' % (os.getcwd(), run_name) directory_to_work = directory_to_work.split("/") for i, d in enumerate(directory_to_work): if d.strip() == "": continue if not os.path.isdir("/".join(directory_to_work[:i + 1])): os.mkdir("/".join(directory_to_work[:i + 1])) directory_to_work = "/".join(directory_to_work) os.chdir(directory_to_work) system.name = run_name # Make a file that has all the names of the systems we are using here files.write_lammps_data(system) # Begin code for the LAMMPS input file commands = (''' units real atom_style full pair_style hybrid/overlay lj/cut/coul/inout 0.2 3.5 15 tersoff bond_style harmonic angle_style harmonic dihedral_style opls special_bonds lj/coul 0.0 0.0 0.5 boundary f f f read_data ''' + run_name + '''.data ''').splitlines() # Indices of OPLS parameters tersoff_types = [t for t in system.atom_types if t.index in tersoff_atoms] charges = lj_params[0] lj_sigma = lj_params[1] lj_epsilon = lj_params[2] # This is how we are reading in the 104 tersoff parameters # (i.e. m,gamma,N,D...etc) tersoff_strings, i, j = [], 0, 0 # Concatenate the atom names and params while i < (len(tersoff_params) - 1): tmp = atom_list[j].split(",") for param in tersoff_params[i:i + 14]: tmp.append(str(param)) tersoff_strings.append(tmp) i += 14 j += 1 # R and D are the distances from the center of the first atom, so this is # how we get the cutoff distance between those inner_cutoffs = {} for type_i in tersoff_types: for type_j in tersoff_types: for s in tersoff_strings: types = s[:3] R, D = float(s[13]), float(s[14]) if types == (type_i.element_name, type_j.element_name, type_j.element_name): inner_cutoffs[(type_i, type_j)] = R + D index = 0 for t in system.atom_types: if t in tersoff_types: t.charge = charges[index] t.vdw_e = lj_epsilon[index] t.vdw_r = lj_sigma[index] index += 1 # Write to the lammps file the atom types and vdw radii for i in range(len(system.atom_types)): for j in range(i, len(system.atom_types)): type_i = system.atom_types[i] type_j = system.atom_types[j] commands.append( 'pair_coeff %d %d lj/cut/coul/inout %f %f %f' % (i + 1, j + 1, (type_i.vdw_e * type_j.vdw_e)**0.5, (type_i.vdw_r * type_j.vdw_r)**0.5, inner_cutoffs[(i, j)] if (i, j) in inner_cutoffs else 0.0)) commands.append('set type %d charge %f' % (i + 1, type_i.charge)) # Generate a lmp object to make the LAMMPS input file lmp = structures.Struct() lmp.file = open(run_name + '.in', 'w') def writeline(line): lmp.file.write(line + '\n') lmp.command = writeline for line in commands: lmp.command(line) # Write the pair_coeff command mcsmrff_files.write_params(lj_params, atom_list, tersoff_params, run_name, append="_input") mcsmrff_files.write_system_and_training_data(run_name, system, systems_by_composition) lmp.command('pair_coeff * * tersoff ' + run_name + '_input.tersoff ' + (' '.join([(t.element_name if t in tersoff_types else 'NULL') for t in system.atom_types]))) for t in system.bond_types: lmp.command('bond_coeff %d %f %f' % (t.lammps_type, t.e, t.r)) for t in system.angle_types: lmp.command('angle_coeff %d %f %f' % (t.lammps_type, t.e, t.angle)) for t in system.dihedral_types: lmp.command('dihedral_coeff %d %f %f %f %f' % ((t.lammps_type, ) + t.e)) commands = ''' compute atom_pe all pe/atom compute sum_pe all reduce sum c_atom_pe neigh_modify once yes dump 2 all xyz 1 ''' + run_name + '''.xyz dump 1 all custom 1 ''' + run_name + '''.dump id type x y z fx fy fz c_atom_pe fix temp all nvt temp 10.0 10.0 100.0 run 0 undump 1 ''' for line in commands.splitlines(): lmp.command(line) lmp.file.close() # Run the simulation the change directory back to the parent one os.system('%s -in %s.in -log %s.log >> out.log' % (mcsmrff_constants.lammps_mcsmrff, run_name, run_name)) os.chdir("../../")
def run_mcsmrff(run_name, system, parameters, tersoff_atoms, queue=None, procs=1, email=None, pair_coeffs_included=True, hybrid_pair=False, hybrid_angle=False, TIP4P=False, seed=None): if seed is None: seed = str(int(md5(run_name).hexdigest(), 16) % (2**16)) else: seed = str(seed) system.name = run_name # Begin generating string to hold LAMMPS input commands = ('''units real atom_style full pair_style hybrid/overlay lj/cut/coul/inout 0.2 3.5 15 tersoff bond_style harmonic angle_style harmonic dihedral_style opls special_bonds lj/coul 0.0 0.0 0.5 boundary p p p read_data ''' + run_name + '''.data ''').splitlines() # Removed HN for no H3 input types tersoff_types = [t for t in system.atom_types if t.index in tersoff_atoms] elems_by_index = [(t.lammps_type, t.element) for t in system.atom_types] elems_by_index = sorted(elems_by_index, key=lambda x: [0]) elems_by_index = ' '.join([units.elem_i2s(e[1]) for e in elems_by_index]) # Grab the parameters. Could in theory just use "parameters" variable, # but too lazy to change code for line in open('%s.tersoff' % run_name): if line.startswith('# Charges:'): charges = [float(x) for x in line.split()[2:]] if line.startswith('# LJ-sigma:'): lj_sigma = [float(x) for x in line.split()[2:]] if line.startswith('# LJ-epsilon:'): lj_epsilon = [float(x) for x in line.split()[2:]] tersoff_strings = findall('\n' + ('(\S+) +' * 9)[:-2] + ' *\n +' + ('(\S+) +' * 8)[:-2], open(run_name + '.tersoff').read()) inner_cutoffs = {} for type_i in tersoff_types: for type_j in tersoff_types: for s in tersoff_strings: types = s[:3] R, D = float(s[13]), float(s[14]) if types == (type_i.element_name, type_j.element_name, type_j.element_name): inner_cutoffs[(type_i, type_j)] = R + D index = 0 for t in system.atom_types: if t in tersoff_types: t.charge = charges[index] t.vdw_e = lj_epsilon[index] t.vdw_r = lj_sigma[index] index += 1 # Write out parameters to LAMMPS input string for i in range(len(system.atom_types)): for j in range(i, len(system.atom_types)): type_i = system.atom_types[i] type_j = system.atom_types[j] commands.append('pair_coeff %d %d lj/cut/coul/inout %f %f %f' % (i + 1, j + 1, (type_i.vdw_e * type_j.vdw_e)**0.5, (type_i.vdw_r * type_j.vdw_r)**0.5, inner_cutoffs[(i, j)] if (i, j) in inner_cutoffs else 0.0)) commands.append('set type %d charge %f' % (i + 1, type_i.charge)) # Generate a LAMMPS structure for an input file lmp = structures.Struct() lmp.file = open(run_name + '.in', 'w') def writeline(line): lmp.file.write(line + '\n') lmp.command = writeline for line in commands: lmp.command(line) commands.append('pair_coeff * * tersoff ' + run_name + '.tersoff ' + (' '.join([(t.element_name if t in tersoff_types else 'NULL') for t in system.atom_types]))) for t in system.bond_types: commands.append('bond_coeff %d %f %f' % (t.lammps_type, t.e, t.r)) for t in system.angle_types: commands.append('angle_coeff %d %f %f' % (t.lammps_type, t.e, t.angle)) for t in system.dihedral_types: commands.append('dihedral_coeff %d %f %f %f %f' % ((t.lammps_type,) + t.e)) commands.append(''' neigh_modify every 1 check yes delay 0 dump 1 all xyz 100 ''' + run_name + '''.xyz dump_modify 1 element ''' + elems_by_index + ''' dump 2 all custom 100 ''' + run_name + '''2.dump type xu yu zu thermo_style custom step temp press ke pe epair emol vol thermo 1000 group mobile id > 0 velocity all create 10.0 ''' + seed + ''' rot yes dist gaussian timestep 0.01 fix press all npt temp 10.0 10.0 10.0 iso 0.0 0.0 100.0 run 50000 unfix press fix motion all nvt temp 10.0 300.0 100.0 run 200000 ''') # job(run_name, commands, system, queue=None, hybrid_angle=False) J = job(run_name, "\n".join(commands), system, parameters, queue=queue, procs=procs, email=email, pair_coeffs_included=pair_coeffs_included, hybrid_pair=hybrid_pair, hybrid_angle=hybrid_angle, TIP4P=TIP4P) return J