def test_nbfix(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) # Add nbfixes types = list(set([a.atom_type for a in structure.atoms])) types[0].add_nbfix(types[1].name, 1.2, 2.1) types[1].add_nbfix(types[0].name, 1.2, 2.1) write_lammpsdata(filename="nbfix.lammps", structure=structure) checked_section = False with open("nbfix.lammps", "r") as fi: while not checked_section: line = fi.readline() if "PairIJ Coeffs" in line: fi.readline() line = fi.readline().partition("#")[0] assert np.allclose( np.asarray(line.split(), dtype=float), [1, 1, 0.066, 3.5], ) line = fi.readline().partition("#")[0] assert np.allclose( np.asarray(line.split(), dtype=float), [1, 2, 2.1, 1.06907846], ) line = fi.readline().partition("#")[0] assert np.allclose(np.asarray(line.split(), dtype=float), [2, 2, 0.03, 2.5]) line = fi.readline() checked_section = True # Break if PairIJ Coeffs is not found if "Atoms" in line: break
def test_save_charmm(self): cmpd = mb.load(get_fn('charmm_dihedral.mol2')) for i in cmpd.particles(): i.name = "_{}".format(i.name) structure = cmpd.to_parmed(box=cmpd.boundingbox, residues=set([p.parent.name for \ p in cmpd.particles()])) from foyer import Forcefield ff = Forcefield(forcefield_files=[get_fn('charmm_truncated.xml')]) structure = ff.apply(structure, assert_dihedral_params=False) from mbuild.formats.lammpsdata import write_lammpsdata write_lammpsdata(structure, 'charmm_dihedral.lammps') out_lammps = open('charmm_dihedral.lammps', 'r').readlines() for i, line in enumerate(out_lammps): if 'Angle Coeffs' in line: assert '# charmm' in line assert '#\tk(kcal/mol/rad^2)\t\ttheteq(deg)\tk(kcal/mol/angstrom^2)\treq(angstrom)\n' in out_lammps[ i + 1] assert len(out_lammps[i + 2].split('#')[0].split()) == 5 elif 'Dihedral Coeffs' in line: assert '# charmm' in line assert '#k, n, phi, weight' in out_lammps[i + 1] assert len(out_lammps[i + 2].split('#')[0].split()) == 5 else: pass
def test_singleterm_charmm(self): from foyer import Forcefield from mbuild.formats.lammpsdata import write_lammpsdata cmpd = mb.load(get_fn("charmm_dihedral.mol2")) for i in cmpd.particles(): i.name = "_{}".format(i.name) structure = cmpd.to_parmed( box=cmpd.get_boundingbox(), residues=set([p.parent.name for p in cmpd.particles()]), ) ff = Forcefield( forcefield_files=[get_fn("charmm_truncated_singleterm.xml")]) structure = ff.apply(structure, assert_dihedral_params=False) write_lammpsdata(structure, "charmm_dihedral_singleterm.lammps") out_lammps = open("charmm_dihedral_singleterm.lammps", "r").readlines() found_dihedrals = False for i, line in enumerate(out_lammps): if "Dihedral Coeffs" in line: assert "# charmm" in line assert "#k, n, phi, weight" in out_lammps[i + 1] assert len(out_lammps[i + 2].split("#")[0].split()) == 5 assert float( out_lammps[i + 2].split("#")[0].split()[4]) == float("1.0") found_dihedrals = True else: pass assert found_dihedrals
def test_save_forcefield_with_same_struct(self): from foyer import Forcefield from mbuild.formats.lammpsdata import write_lammpsdata system = mb.load("C1(=CC=CC=C1)F", smiles=True) ff = Forcefield(forcefield_files=[get_fn("gaff_test.xml")]) struc = ff.apply( system, assert_angle_params=False, assert_dihedral_params=False, assert_improper_params=False, ) write_lammpsdata(struc, "charmm_improper.lammps", zero_dihedral_weighting_factor=True) for i in range(3): xyz = struc.coordinates xyz = xyz + np.array([1, 1, 1]) struc.coordinates = xyz write_lammpsdata( struc, f"charmm_improper{i}.lammps", zero_dihedral_weighting_factor=True, )
def initialize(job): water = create_spce_water() water.name = 'SOL' pore = mb.recipes.GraphenePoreSolvent( pore_width=1.0, pore_length=1.0, pore_depth=1.1, n_sheets=1, slit_pore_dim=2, solvent=water, n_solvent=24, x_bulk=0, ) ff = foyer.Forcefield(get_ff("pore-spce.xml")) water = mb.Compound() gph = mb.Compound() for child in pore.children: if child.name == 'SOL': water.add(mb.clone(child)) else: gph.add(mb.clone(child)) typed_water = ff.apply(water, residues='SOL', combining_rule='lorentz') typed_gph = ff.apply(gph, combining_rule='lorentz') typed_pore = typed_gph + typed_water typed_pore.box[1] = 20 with job: write_lammpsdata(typed_pore, 'data.spce') typed_pore.save('init.mol2', overwrite=True) typed_pore.save('init.gro', combine='all', overwrite=True)
def test_save_charmm(self): from foyer import Forcefield cmpd = mb.load(get_fn("charmm_dihedral.mol2")) for i in cmpd.particles(): i.name = "_{}".format(i.name) structure = cmpd.to_parmed( box=cmpd.get_boundingbox(), residues=set([p.parent.name for p in cmpd.particles()]), ) ff = Forcefield(forcefield_files=[get_fn("charmm_truncated.xml")]) structure = ff.apply(structure, assert_dihedral_params=False) write_lammpsdata(structure, "charmm_dihedral.lammps") out_lammps = open("charmm_dihedral.lammps", "r").readlines() found_angles = False found_dihedrals = False for i, line in enumerate(out_lammps): if "Angle Coeffs" in line: assert "# charmm" in line assert ( "#\tk(kcal/mol/rad^2)\t\ttheteq(deg)\tk(kcal/mol/angstrom^2)\treq(angstrom)\n" in out_lammps[i + 1]) assert len(out_lammps[i + 2].split("#")[0].split()) == 5 found_angles = True elif "Dihedral Coeffs" in line: assert "# charmm" in line assert "#k, n, phi, weight" in out_lammps[i + 1] assert len(out_lammps[i + 2].split("#")[0].split()) == 5 found_dihedrals = True else: pass assert found_angles assert found_dihedrals
def _create_lammps(ethane, tmp): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) fn = tmpdir_factory.mktemp("data").join("lj.lammps") write_lammpsdata(filename=str(fn), structure=structure, unit_style="real") return str(fn)
def convert(correct_structure, forcefield_files=['foyer_charmm.xml', 'foyer_water.xml']): """ Convert gmx to lmp structure via foyer Parameters --------- correct_structure : str filename of the correct structure we are pulling xyz from forcefield_files : To be passed to foyer Notes ----- We are making a 'fake' mbuild compound and then updating the coordinates. This is done to preserve compound hierarchies and residue names Note the generation of an extra box according to the correct_structure's periodicity. This is because update_coordinates doesn't carry over box/periodicity information. The fake mbuild compound is then converted to parmed structure and then atomtyped It is *necessary* to update how we are making this fakae mbuild compound It will help to look at the gmx top file to see the order of the molecules Remember to specify `use_atom_name` to false in order for the ffxml to succesfully ientify atoms in the mb Compound and pmd Structure """ system = mb.Compound() for i in range(64): system.add(DSPC.DSPC(use_atom_name=False)) for i in range(1280): system.add(SOL.SOL(use_atom_name=False)) for i in range(64): system.add(DSPC.DSPC(use_atom_name=False)) for i in range(1280): system.add(SOL.SOL(use_atom_name=False)) system.update_coordinates(correct_structure) system_box = mb.Box(lengths=mb.load(correct_structure).periodicity) # In order to avoid using smarts, define custom elements in parmed # by adding underscores to mb particle names for num, i in enumerate(system.particles()): i.name = "_{}".format(i.name) structure = system.to_parmed( box=system_box, residues=set([p.parent.name for p in system.particles()])) ff = Forcefield(forcefield_files=forcefield_files) structure = ff.apply(structure, assert_dihedral_params=False) # Because mbuild compounds don't pass charges to parmed structures, need to # manuallly set the charges AFTER the force field has been applied for i, j in zip(system.particles(), structure.atoms): j.charge = i.charge write_lammpsdata(structure, correct_structure[:-4] + '.lammpsdata')
def build_tam_custom(periods, composition, bulk_gro, bulk_top, displacement=1.1): """ Initialize a system that uses a bulk system of TAM to fill the pores """ bulk_structure = pmd.load_file(bulk_top, xyz=bulk_gro) interlayer = mb.Compound() interlayer.from_parmed(bulk_structure) interlayer_2 = mb.clone(interlayer) lopes = get_ff('lopes') interlayer.translate_to([ interlayer.center[0], interlayer.center[1], (ti3c2.box[2] / 10 - 2 * displacement) / 2 + 0.15 ]) interlayer_2.translate_to([ interlayer_2.center[0], interlayer_2.center[1], (ti3c2.box[2] / 10 - 2 * displacement) + displacement + 0.15 ]) aa1PM = lopes.apply(interlayer, residues=['alkylam'], assert_dihedral_params=False) aa2PM = lopes.apply(interlayer_2, residues=['alkylam'], assert_dihedral_params=False) system = aa1PM + aa2PM + ti3c2 system = aa1PM + aa2PM + ti3c2 system = _apply_nbfixes(system) system = collapse_atomtypes(system) change_charge(system, new_charge=0) system.box = ti3c2.box for atom in system.atoms: if atom.name == 'C_E': atom.name = 'CE' elif atom.name == 'C_M': atom.name = 'CM' elif atom.name == 'C_B1': atom.name = 'CB1' elif atom.name == 'C_B2': atom.name = 'CB2' system.save('ti3c2.gro', combine='all', overwrite=True) system.save('ti3c2.top', combine='all', overwrite=True) write_lammpsdata(system, 'data.mxene')
def save_lammpsdata(self, filename, structure, forcefield_name, forcefield_files, box, **kwargs): """ """ forcefield = False if forcefield_name or forcefield_files: forcefield = True structure = self._apply_forcefield(structure, forcefield_files, forcefield_name) if box is None: box = self._gen_box() write_lammpsdata(structure, filename, forcefield, box, **kwargs)
def test_resid(self, ethane, methane): structure = ethane.to_parmed() + methane.to_parmed() n_atoms = len(structure.atoms) write_lammpsdata(structure, 'compound.lammps') res_list = list() with open('compound.lammps', 'r') as f: for i,line in enumerate(f): if 'Atoms' in line: break atom_lines = open('compound.lammps', 'r').readlines()[i+2:i+n_atoms+2] for line in atom_lines: res_list.append(line.rstrip().split()[1]) assert set(res_list) == set(['1', '0'])
def test_resid(self, offset, expected_value, ethane, methane): structure = ethane.to_parmed() + methane.to_parmed() n_atoms = len(structure.atoms) write_lammpsdata(structure, "compound.lammps", moleculeID_offset=offset) res_list = list() with open("compound.lammps", "r") as f: for i, line in enumerate(f): if "Atoms" in line: break atom_lines = open("compound.lammps", "r").readlines()[i + 2:i + n_atoms + 2] for line in atom_lines: res_list.append(line.rstrip().split()[1]) assert set(res_list) == set(expected_value)
def save_lammpsdata(self, filename, structure, forcefield, box=None, **kwargs): """ """ if forcefield: from foyer.forcefield import apply_forcefield structure = apply_forcefield(structure, forcefield=forcefield) if not box: box = self.boundingbox for dim, val in enumerate(self.periodicity): if val: box.lengths[dim] = val box.maxs[dim] = val box.mins[dim] = 0.0 if not val: box.maxs[dim] += 0.25 box.mins[dim] -= 0.25 box.lengths[dim] += 0.5 write_lammpsdata(structure, filename, forcefield, box, **kwargs)
def test_lj_masses(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) write_lammpsdata( filename="lj.lammps", structure=structure, unit_style="lj" ) checked_section = False with open("lj.lammps", "r") as fi: while not checked_section: line = fi.readline() if "Masses" in line: fi.readline() line = float(fi.readline().split()[1]) assert np.isclose(line, 1.00) checked_section = True
def test_amber(self): from foyer import Forcefield from mbuild.formats.lammpsdata import write_lammpsdata cmpd = mb.load("C1(=CC=CC=C1)F", smiles=True) ff = Forcefield(forcefield_files=[get_fn("gaff_test.xml")]) structure = ff.apply(cmpd) write_lammpsdata(structure, "amber.lammps", zero_dihedral_weighting_factor=True) out_lammps = open("amber.lammps", "r").readlines() found_angles = False found_dihedrals = False found_impropers = False for i, line in enumerate(out_lammps): if "Angle Coeffs" in line: assert "# harmonic" in line assert ("#\tk(kcal/mol/rad^2)\t\ttheteq(deg)" in out_lammps[i + 1]) assert len(out_lammps[i + 2].split("#")[0].split()) == 3 assert out_lammps[i + 2].split("#")[0].split()[0] == "1" found_angles = True elif "Dihedral Coeffs" in line: assert "# charmm" in line assert "#k, n, phi, weight" in out_lammps[i + 1] assert len(out_lammps[i + 2].split("#")[0].split()) == 5 assert float(out_lammps[i + 2].split("#")[0].split()[4]) == 0.0 assert out_lammps[i + 2].split("#")[0].split()[0] == "1" found_dihedrals = True elif "Improper Coeffs" in line: assert "# cvff" in line assert "#K, d, n" in out_lammps[i + 1] assert len(out_lammps[i + 2].split("#")[0].split()) == 4 assert out_lammps[i + 2].split("#")[0].split()[2] == "-1" assert out_lammps[i + 2].split("#")[0].split()[0] == "1" found_impropers = True else: pass assert found_angles assert found_dihedrals assert found_impropers
def _create_lammps(ethane, tmp, sigma=sigma, epsilon=epsilon, mass=mass): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) fn = tmpdir_factory.mktemp("data").join("lj.lammps") write_lammpsdata( filename=str(fn), structure=structure, unit_style="lj", sigma_conversion_factor=sigma, epsilon_conversion_factor=epsilon, mass_conversion_factor=mass, ) return str(fn)
def test_lj_dihedrals(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) write_lammpsdata( filename="lj.lammps", structure=structure, unit_style="lj" ) checked_section = False with open("lj.lammps", "r") as fi: while not checked_section: line = fi.readline() if "Dihedral Coeffs" in line: fi.readline() dihedrals = fi.readline().split()[1:5] dihedrals = [float(i) for i in dihedrals] assert np.allclose(dihedrals, [0.0005, 0.0, 4.5455, -0.0]) checked_section = True
def test_lj_bonds(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) write_lammpsdata( filename="lj.lammps", structure=structure, unit_style="lj" ) checked_section = False with open("lj.lammps", "r") as fi: while not checked_section: line = fi.readline() if "Bond Coeffs" in line: fi.readline() bonds = list() bonds.append(float(fi.readline().split()[1])) bonds.append(float(fi.readline().split()[1])) assert np.allclose(sorted(bonds), [49742.424, 63106.06]) checked_section = True
def test_lj_angles(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) write_lammpsdata( filename="lj.lammps", structure=structure, unit_style="lj" ) checked_section = False with open("lj.lammps", "r") as fi: while not checked_section: line = fi.readline() if "Angle Coeffs" in line: fi.readline() angles = list() angles.append(float(fi.readline().split()[1])) angles.append(float(fi.readline().split()[1])) assert np.allclose(sorted(angles), [6125.0, 6960.227]) checked_section = True
def test_lj_pairs(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name='oplsaa') structure = OPLSAA.apply(ethane) write_lammpsdata(filename='lj.lammps', structure=structure, unit_style='lj') checked_section = False with open('lj.lammps', 'r') as fi: while not checked_section: line = fi.readline() if 'Pair Coeffs' in line: fi.readline() line = fi.readline().split() epsilon = float(line[1]) sigma = float(line[2]) assert np.isclose(epsilon, 1.00) assert np.isclose(sigma, 1.00) checked_section = True
def test_lj_box(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name='oplsaa') structure = OPLSAA.apply(ethane) write_lammpsdata(filename='lj.lammps', structure=structure, unit_style='lj') checked_section = False with open('lj.lammps', 'r') as fi: while not checked_section: line = fi.readline() if 'dihedral types' in line: fi.readline() line = float(fi.readline().split()[1]) assert np.isclose(line, 2.04) line = float(fi.readline().split()[1]) assert np.isclose(line, 2.268) line = float(fi.readline().split()[1]) assert np.isclose(line, 1.898857) checked_section = True
def test_nbfix(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) structure.combining_rule = "lorentz" # Add nbfixes types = list(set([a.atom_type for a in structure.atoms])) types[0].add_nbfix(types[1].name, 1.2, 2.1) types[1].add_nbfix(types[0].name, 1.2, 2.1) write_lammpsdata(filename="nbfix.lammps", structure=structure) checked_section = False with open("nbfix.lammps", "r") as fi: while not checked_section: line = fi.readline() if "PairIJ Coeffs" in line: fi.readline() line = fi.readline().partition("#")[0] assert np.allclose( np.asarray(line.split(), dtype=float), [1, 1, 0.066, 3.5], ) line = fi.readline().partition("#")[0] assert np.allclose( np.asarray(line.split(), dtype=float), [1, 2, 2.1, 1.06907846], ) line = fi.readline().partition("#")[0] assert np.allclose(np.asarray(line.split(), dtype=float), [2, 2, 0.03, 2.5]) line = fi.readline() checked_section = True # Break if PairIJ Coeffs is not found if "Atoms" in line: break structure.combining_rule = "geometric" write_lammpsdata(filename="nbfix.lammps", structure=structure) write_lammpsdata( filename="nbfix.lammps", structure=structure, nbfix_in_data_file=False, ) with pytest.raises(ValueError) as exc_info: structure.combining_rule = "error" write_lammpsdata(filename="nbfix.lammps", structure=structure) assert str(exc_info.value).startswith("combining_rule must be")
def test_charmm_improper(self): from foyer import Forcefield import mbuild as mb from mbuild.formats.lammpsdata import write_lammpsdata system = mb.Compound() first = mb.Particle(name="_CTL2", pos=[-1, 0, 0]) second = mb.Particle(name="_CL", pos=[0, 0, 0]) third = mb.Particle(name="_OBL", pos=[1, 0, 0]) fourth = mb.Particle(name="_OHL", pos=[0, 1, 0]) system.add([first, second, third, fourth]) system.add_bond((first, second)) system.add_bond((second, third)) system.add_bond((second, fourth)) ff = Forcefield(forcefield_files=[get_fn("charmm36_cooh.xml")]) struc = ff.apply( system, assert_angle_params=False, assert_dihedral_params=False, assert_improper_params=False, ) write_lammpsdata(struc, "charmm_improper.lammps") out_lammps = open("charmm_improper.lammps", "r").readlines() found_impropers = False for i, line in enumerate(out_lammps): if "Improper Coeffs" in line: assert "# harmonic" in line assert "k, phi" in out_lammps[i + 1] assert len(out_lammps[i + 2].split("#")[0].split()) == 3 assert out_lammps[i + 2].split("#")[0].split()[0] == "1" found_impropers = True assert found_impropers
def test_nbfix(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name='oplsaa') structure = OPLSAA.apply(ethane) # Add nbfixes types = list(set([a.atom_type for a in structure.atoms])) types[0].add_nbfix(types[1].name, 1.2, 2.1) types[1].add_nbfix(types[0].name, 1.2, 2.1) write_lammpsdata(filename='nbfix.lammps', structure=structure) checked_section = False with open('nbfix.lammps', 'r') as fi: while not checked_section: line = fi.readline() if 'PairIJ Coeffs' in line: fi.readline() fi.readline() fi.readline() line = fi.readline().partition('#')[0] assert np.allclose( np.asarray(line.split(), dtype=float), [1, 1, 0.066, 3.5]) line = fi.readline().partition('#')[0] assert np.allclose( np.asarray(line.split(), dtype=float), [1, 2, 2.1, 1.06907846]) line = fi.readline().partition('#')[0] assert np.allclose( np.asarray(line.split(), dtype=float), [2, 2, 0.03, 2.5]) line = fi.readline() checked_section = True # Break if PairIJ Coeffs is not found if 'Atoms' in line: break
def test_box_bounds(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) box = mb.Box.from_mins_maxs_angles( mins=np.array([-1.0, -2.0, -3.0]), maxs=np.array([3.0, 2.0, 1.0]), angles=[90.0, 90.0, 90.0], ) # box = ethane.get_boundingbox() write_lammpsdata( filename="box.lammps", structure=structure, unit_style="real", mins=[0.0, 0.0, 0.0], maxs=[m for m in box.lengths], ) checked_section = False # NOTE, need to figure out how to handle lo and hi of a compound with open("box.lammps", "r") as fi: while not checked_section: line = fi.readline() if "xlo" in line: xlo = float(line.split()[0]) xhi = float(line.split()[1]) assert np.isclose(xlo, 0.0) assert np.isclose(xhi, 40.0) line = fi.readline() ylo = float(line.split()[0]) yhi = float(line.split()[1]) assert np.isclose(ylo, 0.0) assert np.isclose(yhi, 40.0) line = fi.readline() zlo = float(line.split()[0]) zhi = float(line.split()[1]) assert np.isclose(zlo, 0.0) assert np.isclose(zhi, 40.0) checked_section = True write_lammpsdata(filename="box.lammps", structure=structure, unit_style="real") checked_section = False with open("box.lammps", "r") as fi: while not checked_section: line = fi.readline() if "xlo" in line: xlo = float(line.split()[0]) xhi = float(line.split()[1]) assert np.isclose(xlo, 0.0) assert np.isclose(xhi, 7.13999987) line = fi.readline() ylo = float(line.split()[0]) yhi = float(line.split()[1]) assert np.isclose(ylo, 0.0) assert np.isclose(yhi, 7.93800011) line = fi.readline() zlo = float(line.split()[0]) zhi = float(line.split()[1]) assert np.isclose(zlo, 0.0) assert np.isclose(zhi, 6.646) checked_section = True
def system_builder(seed, chainlength=17, backbone=Alkylsilane, terminal_group='methyl', num_chains=100): """ Define system variable""" chainlength = chainlength backbone = backbone seed = seed pattern_type = "random" terminal_group = terminal_group num_chains = num_chains """ ----------------------------------- Generate amorphous silica interface ----------------------------------- """ surface_a = SilicaInterface(thickness=1.2, seed=seed) surface_b = SilicaInterface(thickness=1.2, seed=seed) """ ------------------------------------------------------ Generate prototype of functionalized alkylsilane chain ------------------------------------------------------ """ chain_prototype_A = backbone(chain_length=chainlength, terminal_group=terminal_group) chain_prototype_B = backbone(chain_length=chainlength, terminal_group=terminal_group) """ ---------------------------------------------------------- Create monolayer on surface, backfilled with hydrogen caps ---------------------------------------------------------- """ # bottom monolayer is backfilled with the other terminal group # num_chains = num_chains * a_fraction monolayer_a = SurfaceMonolayer( surface=surface_a, chains=chain_prototype_A, n_chains=num_chains, seed=seed, backfill=H(), rotate=False, ) monolayer_a.name = "Bottom" monolayer_b = SurfaceMonolayer( surface=surface_b, chains=chain_prototype_B, n_chains=num_chains, seed=seed, backfill=H(), rotate=False, ) monolayer_b.name = "Top" """ ---------------------- Create dual monolayers ---------------------- """ dual_monolayer = DualSurface(bottom=monolayer_a, top=monolayer_b, separation=2.0) """ -------------------------------------------------------- Make sure box is elongated in z to be pseudo-2D periodic -------------------------------------------------------- """ box = dual_monolayer.boundingbox dual_monolayer.periodicity += np.array([0, 0, 5.0 * box.lengths[2]]) """ ------------------------------------------------------------------- - Save to .GRO, .TOP, and .LAMMPS formats - Atom-type the system using Foyer, with parameters from the OPLS force field obtained from GROMACS. Parameters are located in a Foyer XML file in "../util/forcefield/oplsaa.xml". ------------------------------------------------------------------- """ if os.path.isfile("../util/forcefield/oplsaa.xml"): forcefield_filepath = "../util/forcefield/oplsaa.xml" elif os.path.isfile("../../../util/forcefield/oplsaa.xml"): forcefield_filepath = "../../../util/forcefield/oplsaa.xml" else: raise Exception('Forcefield file is not found') dual_monolayer.save("init.gro", residues=["Top", "Bottom"], overwrite=True) structure = dual_monolayer.to_parmed(box=None, residues=["Top", "Bottom"]) ff = Forcefield(forcefield_files=forcefield_filepath) structure = ff.apply(structure) structure.combining_rule = "geometric" structure.save("init.top", overwrite=True) write_lammpsdata(filename="init.lammps", structure=structure) """ -------------------------------------- Specify index groups and write to file -------------------------------------- """ index_groups = generate_index_groups( system=dual_monolayer, terminal_group=terminal_group, freeze_thickness=0.5, ) write_monolayer_ndx(rigid_groups=index_groups, filename="init.ndx") return dual_monolayer
def build_alkylammonium_mxene(n_compounds, composition, periods, chain_length=12, displacement=1.1): ti3c2 = build_structure(periods=periods, composition=composition, displacement=displacement, lateral_shift=True, atomtype=True) n_carbons = 'C' * chain_length aa = mb.load(f'{n_carbons}[N](C)(C)C', smiles=True) # Rename some carbons # CE = end carbon # CM = middle carbon # CB = branch carbon for idx, particle in enumerate(aa.particles()): if idx == 0: particle.name = 'C_E' if idx == chain_length / 2: particle.name = 'C_M' # TODO: Find way to get branch carbon index without # hardcoding if particle.name == 'N': n_index = idx try: if idx == n_index + 1: particle.name = 'C_B1' if idx == n_index + 2: particle.name = 'C_B2' except: continue aa.name = 'alkylam' lopes = get_ff('lopes') region1 = mb.Box( mins=[0, 0, (ti3c2.box[2] / 10 - 2 * displacement) / 2 + 0.15], maxs=[ ti3c2.box[0] / 10, ti3c2.box[1] / 10, (ti3c2.box[2] / 10 - 2 * displacement) / 2 + displacement ]) region2 = mb.Box(mins=[ 0, 0, (ti3c2.box[2] / 10 - 2 * displacement) + displacement + 0.15 ], maxs=[ ti3c2.box[0] / 10, ti3c2.box[1] / 10, (ti3c2.box[2] / 10 - 2 * displacement) + 2 + displacement ]) aa_1 = mb.fill_box(compound=aa, n_compounds=n_compounds, box=region1, fix_orientation=True) aa_2 = mb.fill_box(compound=aa, n_compounds=n_compounds, box=region2, fix_orientation=True) aa1PM = lopes.apply(aa_1, residues=['alkylam'], assert_dihedral_params=False) aa2PM = lopes.apply(aa_2, residues=['alkylam'], assert_dihedral_params=False) system = aa1PM + aa2PM + ti3c2 system = _apply_nbfixes(system) system = collapse_atomtypes(system) change_charge(system, new_charge=0) system.box = ti3c2.box for atom in system.atoms: if atom.name == 'C_E': atom.name = 'CE' elif atom.name == 'C_M': atom.name = 'CM' elif atom.name == 'C_B1': atom.name = 'CB1' elif atom.name == 'C_B2': atom.name = 'CB2' system.save('ti3c2.gro', combine='all', overwrite=True) system.save('ti3c2.top', combine='all', overwrite=True) write_lammpsdata(system, 'data.mxene')
def build_tam_emim_mxene(n_compounds, composition, periods, chain_length=12, displacement=1.1): """Build a MXene with TAM and EMIM in the interlayer Parameters ---------- n_compounds : list List of [TAM, EMIM] compounds composition : dict Composition of MXene surface groups periods : list Periods of MXene crystal chain_length : int Chain length of TAM displacement : float Interlayer spacing (nm) """ ti3c2 = build_structure(periods=periods, composition=composition, displacement=displacement, lateral_shift=True, atomtype=True) n_carbons = 'C' * chain_length aa = mb.load(f'{n_carbons}[N](C)(C)C', smiles=True) # Rename some carbons # CE = end carbon # CM = middle carbon # CB = branch carbon for idx, particle in enumerate(aa.particles()): if idx == 0: particle.name = 'C_E' if idx == chain_length / 2: particle.name = 'C_M' # TODO: Find way to get branch carbon index without # hardcoding if particle.name == 'N': n_index = idx try: if idx == n_index + 1: particle.name = 'C_B1' if idx == n_index + 2: particle.name = 'C_B2' except: continue emim = mb.load(get_il('emim')) emim.name = 'emim' aa.name = 'alkylam' lopes = get_ff('lopes') region1 = mb.Box( mins=[0, 0, (ti3c2.box[2] / 10 - 2 * displacement) / 2 + 0.15], maxs=[ ti3c2.box[0] / 10, ti3c2.box[1] / 10, (ti3c2.box[2] / 10 - 2 * displacement) / 2 + displacement ]) region2 = mb.Box(mins=[ 0, 0, (ti3c2.box[2] / 10 - 2 * displacement) + displacement + 0.15 ], maxs=[ ti3c2.box[0] / 10, ti3c2.box[1] / 10, (ti3c2.box[2] / 10 - 2 * displacement) + 2 + displacement ]) aa_1 = mb.fill_box(compound=[aa, emim], n_compounds=n_compounds, box=region1, fix_orientation=True) aa_2 = mb.fill_box(compound=[aa, emim], n_compounds=n_compounds, box=region2, fix_orientation=True) aa1PM = lopes.apply(aa_1, residues=['alkylam', 'emim'], assert_dihedral_params=False) aa2PM = lopes.apply(aa_2, residues=['alkylam', 'emim'], assert_dihedral_params=False) system = aa1PM + aa2PM + ti3c2 system = _apply_nbfixes(system) system = collapse_atomtypes(system) change_charge(system, new_charge=0) system.box = ti3c2.box for atom in system.atoms: if atom.name == 'C_E': atom.name = 'CE' elif atom.name == 'C_M': atom.name = 'CM' elif atom.name == 'C_B1': atom.name = 'CB1' elif atom.name == 'C_B2': atom.name = 'CB2' system.save('ti3c2.gro', combine='all', overwrite=True) system.save('ti3c2.top', combine='all', overwrite=True) write_lammpsdata(system, 'data.mxene')
def initialize_system(job): """ Generate the monolayer surfaces, parametrize, save LAMMPS, GRO, TOP. """ ''' --------------------------- Read statepoint information --------------------------- ''' chainlength = job.statepoint()['chainlength'] n_chains = job.statepoint()['n'] seed = job.statepoint()['seed'] terminal_groups = job.statepoint()['terminal_groups'] ''' ----------------------------------- Generate amorphous silica interface ----------------------------------- ''' surface_a = SilicaInterface(thickness=1.2, seed=seed) surface_b = SilicaInterface(thickness=1.2, seed=seed) ''' ------------------------------------------------------ Generate prototype of functionalized alkylsilane chain ------------------------------------------------------ ''' chain_prototype_a = Alkylsilane(chain_length=chainlength, terminal_group=terminal_groups[0]) chain_prototype_b = Alkylsilane(chain_length=chainlength, terminal_group=terminal_groups[1]) ''' ---------------------------------------------------------- Create monolayer on surface, backfilled with hydrogen caps ---------------------------------------------------------- ''' monolayer_a = SurfaceMonolayer(surface=surface_a, chains=chain_prototype_a, n_chains=n_chains, seed=seed, backfill=H(), rotate=False) monolayer_a.name = 'Bottom' monolayer_b = SurfaceMonolayer(surface=surface_b, chains=chain_prototype_b, n_chains=n_chains, seed=seed, backfill=H(), rotate=False) monolayer_b.name = 'Top' ''' ------------------------------------------ Duplicate to yield two opposing monolayers ------------------------------------------ ''' dual_monolayer = DualSurface(bottom=monolayer_a, top=monolayer_b, separation=2.0) ''' -------------------------------------------------------- Make sure box is elongated in z to be pseudo-2D periodic -------------------------------------------------------- ''' box = dual_monolayer.boundingbox dual_monolayer.periodicity += np.array([0, 0, 5. * box.lengths[2]]) ''' ------------------------------------------------------------------- - Save to .GRO, .TOP, and .LAMMPS formats - Atom-type the system using Foyer, with parameters from the OPLS force field obtained from GROMACS. Parameters are located in a Foyer XML file in the `atools` git repo, with references provided as well as notes where parameters have been added or altered to reflect the literature. ------------------------------------------------------------------- ''' # path for project root dir proj = signac.get_project() forcefield_filepath = pathlib.Path( proj.root_directory() + "/src/util/forcefield/oplsaa.xml") # change into job directoryA _switch_dir(job) logging.info("at dir: {}".format(job.ws)) dual_monolayer.save('init.gro', residues=['Top', 'Bottom'], overwrite=True) if not (job.isfile('init.top') and job.isfile('init.lammps') and job.isfile('init.gro')): structure = dual_monolayer.to_parmed(box=None, residues=['Top', 'Bottom']) ff = Forcefield(forcefield_files=forcefield_filepath.as_posix()) structure = ff.apply(structure) structure.combining_rule = 'geometric' structure.save('init.top', overwrite=True) write_lammpsdata(filename='init.lammps', structure=structure) ''' -------------------------------------- Specify index groups and write to file -------------------------------------- ''' index_groups = generate_index_groups(system=dual_monolayer, terminal_groups=terminal_groups, freeze_thickness=0.5) write_monolayer_ndx(rigid_groups=index_groups, filename='init.ndx')
def test_box_bounds(self, ethane): from foyer import Forcefield OPLSAA = Forcefield(name="oplsaa") structure = OPLSAA.apply(ethane) box = mb.Box( mins=np.array([-1.0, -2.0, -3.0]), maxs=np.array([3.0, 2.0, 1.0]) ) write_lammpsdata( filename="box.lammps", structure=structure, unit_style="real", mins=[m for m in box.mins], maxs=[m for m in box.maxs], ) checked_section = False with open("box.lammps", "r") as fi: while not checked_section: line = fi.readline() if "xlo" in line: xlo = float(line.split()[0]) xhi = float(line.split()[1]) assert np.isclose(xlo, -10.0) assert np.isclose(xhi, 30.0) line = fi.readline() ylo = float(line.split()[0]) yhi = float(line.split()[1]) assert np.isclose(ylo, -20.0) assert np.isclose(yhi, 20.0) line = fi.readline() zlo = float(line.split()[0]) zhi = float(line.split()[1]) assert np.isclose(zlo, -30.0) assert np.isclose(zhi, 10.0) checked_section = True write_lammpsdata( filename="box.lammps", structure=structure, unit_style="real" ) checked_section = False with open("box.lammps", "r") as fi: while not checked_section: line = fi.readline() if "xlo" in line: xlo = float(line.split()[0]) xhi = float(line.split()[1]) assert np.isclose(xlo, 0.0) assert np.isclose(xhi, 7.13999987) line = fi.readline() ylo = float(line.split()[0]) yhi = float(line.split()[1]) assert np.isclose(ylo, 0.0) assert np.isclose(yhi, 7.93800011) line = fi.readline() zlo = float(line.split()[0]) zhi = float(line.split()[1]) assert np.isclose(zlo, 0.0) assert np.isclose(zhi, 6.646) checked_section = True
for i in range(2160): system.add(SOL.SOL(use_atom_name=False)) system.update_coordinates('wrapped.gro') # In order to avoid using smarts, define custom elements in parmed # by adding underscores to mb particle names for num, i in enumerate(system.particles()): i.name = "_{}".format(i.name) structure = system.to_parmed(box=system.boundingbox, residues=set( [p.parent.name for p in system.particles()])) from foyer import Forcefield ff = Forcefield(forcefield_files=['foyer_water.xml', 'foyer_charmm.xml']) start = time.time() structure = ff.apply(structure, assert_dihedral_params=False) end = time.time() print("Applying FF took: {}".format(end - start)) # Because mbuild compounds don't pass charges to parmed structures, need to # manuallly set the charges AFTER the force field has been applied for i, j in zip(system.particles(), structure.atoms): j.charge = i.charge start = time.time() write_lammpsdata(structure, 'thing.lammps') end = time.time() print("Writing lammps structure took: {}".format(end - start))
def initialize_system(job): """ Generate the monolayer surfaces, parametrize, save LAMMPS, GRO, TOP. """ """ --------------------------- Read statepoint information --------------------------- """ chainlength_a = job.statepoint()["chainlength_a"] chainlength_b = job.statepoint()["chainlength_b"] chainlength_c = job.statepoint()["chainlength_c"] chainlength_d = job.statepoint()["chainlength_d"] seed = job.statepoint()["seed"] pattern_type = job.statepoint()["pattern_type"] terminal_groups = job.statepoint()["terminal_groups"] a_fraction = job.statepoint()["fraction_a"] c_fraction = job.statepoint()["fraction_c"] num_chains = job.statepoint()["n"] backbone_1 = job.statepoint()["backbone_1"] backbone_2 = job.statepoint()["backbone_2"] locations = job.statepoint()["locations"] """ ----------------------------------- Generate amorphous silica interface ----------------------------------- """ surface_a = SilicaInterface(thickness=1.2, seed=seed) surface_b = SilicaInterface(thickness=1.2, seed=seed) """ ------------------------------------------------------ Generate prototype of functionalized alkylsilane chain ------------------------------------------------------ """ chain_prototype_a = AlkylsilaneInternalplus( chain_length=chainlength_a, internal_group=backbone_1, locations=locations, terminal_group=terminal_groups[0] ) chain_prototype_b = AlkylsilaneInternalplus( chain_length=chainlength_b, internal_group=backbone_2, locations=locations, terminal_group=terminal_groups[1] ) chain_prototype_c = AlkylsilaneInternalplus( chain_length=chainlength_c, internal_group=backbone_1, locations=locations, terminal_group=terminal_groups[2] ) chain_prototype_d = AlkylsilaneInternalplus( chain_length=chainlength_d, internal_group=backbone_2, locations=locations, terminal_group=terminal_groups[3] ) """ ---------------------------------------------------------- Create monolayer on surface, backfilled with hydrogen caps ---------------------------------------------------------- """ # bottom monolayer is backfilled with the other terminal group # num_chains = num_chains * a_fraction monolayer_a = SurfaceMonolayer( surface=surface_a, chains=[chain_prototype_a, chain_prototype_b], n_chains=num_chains, seed=seed, backfill=H(), rotate=False, fractions=[a_fraction, 1.0 - a_fraction], ) monolayer_a.name = "Bottom" monolayer_b = SurfaceMonolayer( surface=surface_b, chains=[chain_prototype_c, chain_prototype_d], n_chains=num_chains, seed=seed, backfill=H(), rotate=False, fractions=[c_fraction, 1.0 - c_fraction], ) monolayer_b.name = "Top" """ ------------------------------------------ Duplicate to yield two opposing monolayers ------------------------------------------ """ dual_monolayer = DualSurface( bottom=monolayer_a, top=monolayer_b, separation=2.0 ) """ -------------------------------------------------------- Make sure box is elongated in z to be pseudo-2D periodic -------------------------------------------------------- """ box = dual_monolayer.boundingbox dual_monolayer.periodicity += np.array([0, 0, 5.0 * box.lengths[2]]) """ ------------------------------------------------------------------- - Save to .GRO, .TOP, and .LAMMPS formats - Atom-type the system using Foyer, with parameters from the OPLS force field obtained from GROMACS. Parameters are located in a Foyer XML file in the `atools` git repo, with references provided as well as notes where parameters have been added or altered to reflect the literature. ------------------------------------------------------------------- """ # path for project root dir proj = signac.get_project() forcefield_filepath = pathlib.Path( proj.root_directory() + "/src/util/forcefield/oplsaa.xml" ) # change into job directoryA _switch_dir(job) logging.info("at dir: {}".format(job.ws)) for p in dual_monolayer.particles(): if p.name == "OS": p.name = "O" dual_monolayer.save("init.gro", residues=["Top", "Bottom"], overwrite=True) if not ( job.isfile("init.top") and job.isfile("init.lammps") and job.isfile("init.gro") ): structure = dual_monolayer.to_parmed( box=None, residues=["Top", "Bottom"] ) ff = Forcefield(forcefield_files=forcefield_filepath.as_posix()) structure = ff.apply(structure) structure.combining_rule = "geometric" structure.save("init.top", overwrite=True) write_lammpsdata(filename="init.lammps", structure=structure, detect_forcefield_style=False) """ -------------------------------------- Specify index groups and write to file -------------------------------------- """ index_groups = generate_index_groups( system=dual_monolayer, terminal_groups=terminal_groups, freeze_thickness=0.5, ) write_monolayer_ndx(rigid_groups=index_groups, filename="init.ndx")