def generate_frames(): ''' This function generates the NEB pathway we want to study. **Returns** frames: *list, list,* :class:`structures.Atom` MEP reaction coordinate. ''' PROXIMITY = 3.0 DELTA = 0.5 NFRAMES = 10 minimize_benzene() mol1 = files.read_cml("benzene_opt.cml", return_molecules=True)[0] mol2 = files.read_cml("benzene_opt.cml", return_molecules=True)[0] mol1.set_center((0.0, 0.0, 0.0)) mol1.rotate(geometry.rotation_matrix((0, 0, 1), 30)) mol2.set_center((0.0, 0.0, PROXIMITY)) frames = [] for i in range(NFRAMES): mol2.set_center((0.0, 0.0, PROXIMITY + i * DELTA)) frames.append(copy.deepcopy(mol1.atoms + mol2.atoms)) return frames
def minimize_benzene(): ''' This function will use LAMMPs minimize to ensure that our endpoints are minimized. ''' P, mol1 = files.read_cml("benzene.cml", new_method=True) box = structures.System(name="benz", box_size=(20, 20, 20), periodic=True) mol1 = mol1[0] box.add(mol1) box.set_types(P) input_script = """units real atom_style full pair_style lj/cut/coul/cut 10.0 bond_style harmonic angle_style harmonic dihedral_style opls boundary p p p read_data benz.data pair_modify mix geometric """ + box.dump_pair_coeffs() + """ dump 1 all xyz 1 benzene.xyz dump_modify 1 element """ + ' '.join(box.get_elements(P)) + """ minimize 1.0e-4 1.0e-6 1000 10000 """ input_script = input_script.strip() j = lammps_job.job("benz", input_script, system=box, procs=1, queue=None, hybrid_angle=False, params=P, pair_coeffs_included=False, no_echo=True) j.wait(1) new_atoms = files.read_xyz("lammps/benz/benzene.xyz")[-1] for a, b in zip(mol1.atoms, new_atoms): a.x, a.y, a.z = b.x, b.y, b.z files.write_cml(mol1, name="benzene_opt")
def test_read_cml(): # atoms, bonds, angles, dihedrals = files.read_cml("misc/acetone.cml", new_method=False) P, molecs = files.read_cml("misc/acetone.cml", new_method=True) P.set_opls_mask() # print P.dump_style("opls") # print P.dihedral_params # print P.dihedral_params.index(('4', '3', '3', '13')) # print molecs[0].bonds[0].type test_sys = structures.System() test_sys.add(molecs[0]) files.write_lammps_data(test_sys, new_method=True, params=P) return False
from squid import files from squid import lammps from squid import geometry from squid import structures if __name__ == "__main__": # Step 1 - Generate the system world = structures.System("solv_box", box_size=(15.0, 15.0, 15.0), periodic=True) # Step 2 - Get any molecules you want mol1 = files.read_cml("benzene.cml")[0] mol2 = mol1 + (10, 10, 10) solv = files.read_cml("acetone.cml")[0] # Step 3 - In the case that we do not know the atom types, but we still # want to generate a lammps data file, we can still do so! We must first # in this example strip away all relevant bonding information. Further, # and this is important: YOU MUST SET a.label and a.charge to the element # and some value (in this example I set it to 0.0). for mol in [mol1, mol2, solv]: for a in mol.atoms: a.label = a.element a.charge = 0.0 mol.bonds = [] mol.angles = [] mol.dihedrals = [] # Step 4 - Add them however you want world.add(mol1)
def run_simulation(NEB, i, state, charge, multiplicity, procs, queue, initial_guess, extra_section, mem, priority): ''' This function will, given the coordinates from NEB, run a LAMMPs simulation with a solvated system. **Parameters** NEB: :class:`NEB` An NEB container holding the main NEB simulation i: *int* The index corresponding to which image on the frame is to be simulated. state: *list,* :class:`structures.Atom` A list of atoms describing the image on the frame associated with index *i*. charge: *int* Charge of the system. multiplicity: *int* Multiplicity of the system. procs: *int* The number of processors to use during calculations. queue: *str* Which queue to submit the simulation to (this is queueing system dependent). initial_guess: *str* The name of a previous simulation for which we can read in a hessian. extra_section: *str* Extra settings for this DFT method. mem: *int* How many Mega Words (MW) you wish to have as dynamic memory. priority: *int* Whether to submit the job with a given priority (NBS). Not setup for this function yet. **Returns** lmp_job: :class:`jobs.Job` A job container holding the simulation. ''' theory, density = NEB.theory step = NEB.step if not theory.endswith(".cml"): theory += ".cml" if not os.path.exists(theory): raise Exception( "Cannot find desired solvent molecule in the folder (%s)." % theory) P1, solv = files.read_cml(theory, new_method=True) P2, benz1 = files.read_cml("benzene.cml", new_method=True) _, benz2 = files.read_cml("benzene.cml", new_method=True) solv, benz1, benz2 = solv[0], benz1[0], benz2[0] P = P1 + P2 solv.set_types(P) benz1.set_types(P) benz2.set_types(P) # First, pack into benz1 and benz2 the coodinates new_benz_1 = np.array([s.flatten() for s in state[:len(state) / 2]]) new_benz_2 = np.array([s.flatten() for s in state[len(state) / 2:]]) benz1.set_positions(new_benz_1) benz2.set_positions(new_benz_2) # Generate our system BOX_SIZE = (10.0, 10.0, 15.0) box = structures.System("solv_box-%d-%d" % (step, i), box_size=BOX_SIZE, periodic=True) box.add(benz1) box.add(benz2) box.packmol([solv], density=density, new_method=True, tolerance=1.0) box.set_types(P) # Run the simulation input_script = """units real atom_style full pair_style lj/cut/coul/cut 10.0 bond_style harmonic angle_style harmonic dihedral_style opls boundary p p p read_data solv_box-""" + str(step) + """-""" + str(i) + """.data pair_modify mix geometric """ + box.dump_pair_coeffs() + """ group neb id <= """ + str(len(state)) + """ group solvent subtract all neb #dump 1 all xyz 1000 solv_box_""" + str(i) + """.xyz #dump_modify 1 element """ + ' '.join(box.get_elements(P)) + """ #dump 2 neb xyz 100 neb.xyz thermo_style custom ke pe temp press thermo 1000 velocity neb zero linear fix freeze neb setforce 0.0 0.0 0.0 minimize 1.0e-4 1.0e-6 1000 10000 velocity all create 300.0 23123 rot yes dist gaussian velocity neb set 0.0 0.0 0.0 timestep 1.0 fix energy neb ave/time 100 5 1000 c_thermo_pe file energy.profile fix motion_npt all npt temp 300.0 300.0 100.0 iso 0.0 0.0 1000.0 dilate solvent run 1000000 unfix motion_npt compute pe neb pe/atom dump forces neb custom 1 forces.dump id element x y z fx fy fz c_pe dump glance all xyz 1 solv_box_""" + str(i) + """.xyz dump_modify glance element """ + ' '.join(box.get_elements(P)) + """ unfix freeze run 0 """ return lammps_job.job("solv_box-%d-%d" % (step, i), input_script, system=box, procs=procs, queue=queue, params=P, pair_coeffs_included=False, no_echo=True)
def generate_ion_halide_cation(halide, cation, fname, route, extra_section, ion="Pb", run_opt=True, priority=None, walltime="3-0:0:0", procs=2): """ Check if a perovskite monomer system already exists. If so, then read in the CML and return it. If not, then generate the system, save it, and return the generated system. **Parameters** halide: *list, str or str* The halide combination in the perovskite. If a string is passed, all three are assumed to be the same cation: *str* The cation in the perovskite. ion: *str, optional* The ion to use within this perovskite. run_opt: *bool, optional* Whether to geometry optimize the system if it did not exist. priority: *int, optional* A queue priority to ensure the subjobs run. This may be necessary if many simulations are run in parallel and you are worried about locking the queue with too many parent jobs. **Returns** system: *Molecule* A molecule object holding the perovskite monomer system. """ if os.path.exists(WORLD_CONSTS.STRUCTURES_PATH + fname + ".cml"): system = structures.Molecule( files.read_cml(WORLD_CONSTS.STRUCTURES_PATH + fname + ".cml", test_charges=False, default_angles=WORLD_CONSTS.default_angles, allow_errors=True)[0]) return system def vdw(y): return constants.PERIODIC_TABLE[units.elem_s2i(y)]['vdw_r'] # Get the ionX3 system ionX3 = _generate_ion_halide(halide, ion=ion) # Get the cation from the cml file atoms, bonds, _, _ = files.read_cml( WORLD_CONSTS.STRUCTURES_PATH + cation + ".cml", test_charges=False, default_angles=WORLD_CONSTS.default_angles, allow_errors=True) system = structures.Molecule(atoms) # Align along X axis system.atoms = geometry.align_centroid(system.atoms)[0] # Rotate to Z axis # NOTE! In case of FA, we want flat so only translate to origin instead elems = [a.element for a in system.atoms] if cation == "FA": system.translate(system.get_center_of_mass()) else: R = geometry.rotation_matrix([0, 1, 0], 90, units="deg") system.rotate(R) # If N and C in system, ensure N is below C (closer to Pb) if "N" in elems and "C" in elems: N_index = [i for i, a in enumerate(system.atoms) if a.element == "N"][0] C_index = [i for i, a in enumerate(system.atoms) if a.element == "C"][0] if system.atoms[N_index].z > system.atoms[C_index].z: # Flip if needed R = geometry.rotation_matrix([0, 1, 0], 180, units="deg") system.rotate(R) # Offset system so lowest point is at 0 in the z dir z_offset = min([a.z for a in system.atoms]) * -1 system.translate([0, 0, z_offset]) # Add to the ionX3 system with an offset of vdw(Pb) system.translate([0, 0, vdw(ion)]) system.atoms += ionX3.atoms # Run a geometry optimization of this system if run_opt: ionXY = orca.job(fname, route, atoms=system.atoms, extra_section=extra_section, redundancy=True, queue=sysconst.default_queue, priority=priority, walltime=walltime, procs=procs) time.sleep(SLEEPER) ionXY.wait() time.sleep(SLEEPER) results = orca.read(fname) new_pos = results.atoms for a, b in zip(system.atoms, new_pos): a.x, a.y, a.z = [b.x, b.y, b.z] if not hasattr(ionXY, "redundancy"): dump_log(results, fname) # Set OPLS types for i, a in enumerate(system.atoms): a.index = i + 1 if a.element in WORLD_CONSTS.atom_types and a.type is None: a.type = structures.Struct() a.type.__dict__.update(WORLD_CONSTS.atom_types[a.element]) a.type_index = a.type.index # Write cml file so we don't re-generate, and return system files.write_cml(system, bonds=bonds, name=WORLD_CONSTS.STRUCTURES_PATH + fname + ".cml") return system
from squid.ff_params import Parameters # Generate the system object to hold our solvent solvent_box = structures.System(name="solv_box", box_size=(15.0, 15.0, 15.0), box_angles=(90.0, 90.0, 90.0), periodic=True) ########## OPTION 1 # Read in our molecule, with minimal parameter object, and assign types # P, acetone = files.read_cml("acetone.cml", new_method=True) # acetone = acetone[0] ########## OPTION 2 # Read in cml files normally acetone = files.read_cml("acetone.cml", return_molecules=True) acetone = acetone[0] # Get a parameter object, and assign to molecule P = Parameters(restrict=[a.label for a in acetone.atoms]) acetone.set_types(P) ################### # Using packmol, pack this box with acetic acids solvent_box.packmol([acetone], new_method=True, density=0.791, seed=21321) # Assign the types solvent_box.set_types(P) # Now we can run an NPT simulation using lammps # Get a list of elements for dump_modify. By default we organize types by heaviest to lightest, so do so here.