def wrongbox(self): box = mbuild.Compound() box.box = mbuild.Box([5.0, 5.0, 5.0]) return box
def test_init_with_subcompounds1(self, ethane): compound = mb.Compound(ethane) assert compound.n_particles == 8 assert compound.n_bonds == 7
def test_init_with_subcompounds3(self, ethane, h2o): compound = mb.Compound([ethane, [h2o, mb.clone(h2o)]]) assert compound.n_particles == 8 + 2 * 3 assert compound.n_bonds == 7 + 2 * 2
def test_clone_outside_containment(self, ch2, ch3): compound = mb.Compound() compound.add(ch2) mb.force_overlap(ch3, ch3['up'], ch2['up']) with pytest.raises(MBuildError): ch3_clone = mb.clone(ch3)
def __init__(self, lipids, ref_atoms, n_lipids_x=10, n_lipids_y=10, area_per_lipid=1.0, solvent=None, lipid_box=None, spacing_z=0.5, solvent_per_lipid=None, n_solvent=None, random_seed=12345, mirror=True): super(Bilayer, self).__init__() # Santitize inputs. if sum([lipid[1] for lipid in lipids]) != 1.0: raise ValueError('Lipid fractions do not add up to 1.') assert len(ref_atoms) == len(lipids) self.lipids = lipids self.ref_atoms = ref_atoms self._lipid_box = lipid_box # 2D Lipid locations. self.n_lipids_x = n_lipids_x self.n_lipids_y = n_lipids_y self.apl = area_per_lipid self.n_lipids_per_layer = self.n_lipids_x * self.n_lipids_y self.pattern = mb.Grid2DPattern(n_lipids_x, n_lipids_y) self.pattern.scale(np.sqrt(self.apl * self.n_lipids_per_layer)) # Solvent info. self.solvent = solvent self.n_solvent = n_solvent self.solvent_per_lipid = solvent_per_lipid # Other inputs. self.spacing = np.array([0, 0, spacing_z]) self.random_seed = random_seed self.mirror = mirror self._number_of_each_lipid_per_layer = [] self._solvent_per_layer = None # Containers for lipids and solvent. self.lipid_components = mb.Compound() self.solvent_components = mb.Compound() # Assemble the lipid layers seed(self.random_seed) top_layer, top_lipid_labels = self.create_layer() self.lipid_components.add(top_layer) if self.mirror == True: bottom_layer, bottom_lipid_labels = self.create_layer( lipid_indices=top_lipid_labels, flip_orientation=True) else: bottom_layer, bottom_lipid_labels = self.create_layer( flip_orientation=True) self.lipid_components.add(bottom_layer) # solvate the lipids #self.solvate_bilayer() # TODO: needs fixing # add everything to the big list self.add(self.lipid_components) self.add(self.solvent_components) print(self.number_of_each_lipid_per_layer)
def test_batch_add(self, ethane, h2o): compound = mb.Compound() compound.add([ethane, h2o]) assert compound.n_particles == 8 + 3 assert compound.n_bonds == 7 + 2
def test_parmed_box(self, h2o): compound = mb.Compound() compound.add(h2o) tilted_box = mb.Box(lengths=[2.0, 2.0, 2.0], angles=[60.0, 80.0, 100.0]) structure = compound.to_parmed(box=tilted_box) assert all(structure.box == [20.0, 20.0, 20.0, 60.0, 80.0, 100.0])
def main(): # Create a CG methane, load and apply ff methane = mbuild.Compound(name="_CH4") ff_path = resource_filename( "mc_examples", "realistic_workflows/zeolite_adsorption/resources/ffxml/adsorbates.xml", ) ff_ads = foyer.Forcefield(ff_path) methane_ff = ff_ads.apply(methane) # Define a few keyword args that will be the # same for all fluid phase simulations custom_args = { "charge_style": "none", "vdw_cutoff": 14.0 * u.angstrom, "prop_freq": 10, } # Define temperatures and chemical potential values # for the single phase GCMC simulations temperatures = [298 * u.K, 309 * u.K, 350 * u.K] mus = np.arange(-49, -30, 3) * u.Unit("kJ/mol") # Loop over temperatures and mus and run simulations for temperature in temperatures: for mu in mus: # For each simulation -- first estimate # the box volume to target ~40 molecules n_methane_target = 40 beta = 1.0 / (u.kb * temperature) mass = 16.04 * u.amu debroglie = np.sqrt(2 * np.pi * u.hbar**2 * beta / mass) vol = n_methane_target * debroglie**3 * np.exp( -beta.to("mol/kJ") * mu) boxl = (vol**(1.0 / 3.0)).to_value("nm") if boxl < 2.0 * custom_args["vdw_cutoff"].to_value("nm"): boxl = 2.0 * custom_args["vdw_cutoff"].to_value("nm") # Define the species list, box list, system, moveset # We start with an empty box species_list = [methane_ff] box_list = [mbuild.Box([boxl, boxl, boxl])] system = mc.System(box_list, species_list) moveset = mc.MoveSet("gcmc", species_list) # Create a new directory, temporary cd, and run # the equilibration and production simulations! print(f"\nRun simulation: T = {temperature}, mu = {mu}\n") dirname = f"fluid_T_{temperature:0.1f}_mu_{mu:.1f}".replace( " ", "_").replace("/", "-") if not os.path.isdir(dirname): os.mkdir(dirname) else: pass with temporary_cd(dirname): mc.run( system=system, moveset=moveset, run_type="equil", run_length=50000, temperature=temperature, run_name="equil", chemical_potentials=[mu], **custom_args, ) mc.restart( restart_from="equil", run_name="prod", run_type="prod", total_run_length=400000, )
def __init__(self, radius=2, angle=90.0, fluid=None, density=None, lattice=None, lattice_compound=None, x=None, y=None): super(Droplet, self).__init__() if fluid is None: raise ValueError('Fluid droplet compounds must be specified') if density is None: raise ValueError('Fluid density must be specified (units kg/m^3)') if x: if x < radius * 4: raise ValueError( 'Dimension x of sheet must be at least radius * 4') elif x > 100: raise ValueError( 'Dimension x of sheet must be less than 100 nm') else: x = radius * 4 if y: if y < radius * 4: raise ValueError( 'Dimension y of sheet must be at least radius * 4') elif y > 100: raise ValueError( 'Dimension y of sheet must be less than 100 nm') else: y = radius * 4 # Default to graphene lattice if lattice is None: if lattice_compound is not None: raise ValueError( 'If Lattice is None, defaults to a Graphene surface. ' + 'In this case, do not specify lattice_compound.') lattice_compound = mbuild.Compound(name='C') lattice_spacing = [0.2456, 0.2456, 0.335] angles = [90.0, 90.0, 120.0] carbon_locations = [[0, 0, 0], [2 / 3, 1 / 3, 0]] basis = {lattice_compound.name: carbon_locations} lattice = mbuild.Lattice(lattice_spacing=lattice_spacing, angles=angles, lattice_points=basis) compound_dict = {lattice_compound.name: lattice_compound} factor = np.cos(np.pi / 6) # fixes non-cubic lattice # Estimate the number of lattice repeat units replicate = [int(x / 0.2456), int(y / 0.2456) * (1 / factor)] lat = lattice.populate(compound_dict=compound_dict, x=replicate[0], y=replicate[1], z=3) for particle in lat.particles(): if particle.xyz[0][0] < 0: particle.xyz[0][0] += lat.periodicity[0] lat.periodicity[1] *= factor else: if lattice_compound is None: raise ValueError('Lattice compounds must be specified') if not np.all(lattice.angles == 90.0): raise ValueError( 'Currently, only cubic lattices are supported. ' + 'If using Graphene, do not pass in a Lattice.') compound_dict = {lattice_compound.name: lattice_compound} lat = lattice.populate(compound_dict=compound_dict, x=int(x / lattice.lattice_spacing[0]), y=int(y / lattice.lattice_spacing[1]), z=int(1.5 / lattice.lattice_spacing[2])) sheet = mbuild.clone(lat) self.surface_height = np.max(sheet.xyz, axis=0)[2] coords = list(sheet.periodicity) height = get_height(radius, angle) sphere_coords = [coords[0] / 2, coords[1] / 2, radius, radius] sphere = mbuild.fill_sphere(compound=fluid, sphere=sphere_coords, density=density) to_remove = [] for child in sphere.children: for atom_coords in child.xyz: if height > radius: if atom_coords[2] < height - radius: to_remove += child break else: if atom_coords[2] < height: to_remove += child break sphere.remove(to_remove) sheet.name = 'LAT' sphere.name = 'FLD' sphere.xyz -= [0, 0, np.min(sphere.xyz, axis=0)[2]] sphere.xyz += [0, 0, self.surface_height + 0.3] self.add(sheet) self.add(sphere) self.periodicity[0] = sheet.periodicity[0] self.periodicity[1] = sheet.periodicity[1] self.periodicity[2] = radius * 5
from dropletbuilder.dropletbuilder import GrapheneDroplet import mbuild from mbuild.examples.alkane.alkane import Alkane from dropletbuilder.utils.io_tools import get_fn from foyer import Forcefield # build the lattice lattice_compound = mbuild.Compound(name='Au') lattice_spacing = [0.40788, 0.40788, 0.40788] lattice_vector = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] gold_locations = [[0., 0., 0.], [.5, .5, 0.], [.5, 0., .5], [0, .5, .5]] basis = {lattice_compound.name: gold_locations} gold_lattice = mbuild.Lattice(lattice_spacing=lattice_spacing, lattice_vectors=lattice_vector, lattice_points=basis) # hexane compound hexane = Alkane(n=6) hexane.name = 'HEX' # build the system system = GrapheneDroplet(radius=3, angle=90, fluid=hexane, density=655, lattice=gold_lattice, lattice_compound=lattice_compound) # get and apply forcefields AU = Forcefield(get_fn('heinz2008.xml')) OPLSAA = Forcefield(name='oplsaa')
index = 0 # Loop through each type of molecule (DSPC, DPPC, etc.) for i, lipid_type in enumerate(lipid_system_info): # Loop through the quantity of that particular molecule for n in range(int(lipid_type[1])): lipid_molecule = lipid_type[0] lipid_offset = lipid_type[2] top_lipids.append([lipid_molecule, lipid_offset]) bot_lipids.append([lipid_molecule, lipid_offset]) index += 1 if len(bot_lipids) != n_lipid: sys.exit('Error setting up system components') # Generate bottom layer randomly bot_layer = mb.Compound() for i in range(n_x): for j in range(n_y): # Randomly select a lipid that has not yet been selected random_lipid = np.random.randint(0, len(bot_lipids)) # Create the mbuild Molecule for this lipid molecule_i = bot_lipids.pop(random_lipid) molecule_to_add = mb.clone(molecule_i[0]) # Apply tilt angle mb.spin_y(molecule_to_add, tilt_angle) # Apply z_offset z_offset = molecule_i[1] #z_offset = 0 # Apply APL and z_offset to identify the position for the molecule in the grid position = [i * spacing, j * spacing, z_offset] mb.translate(molecule_to_add, position)
def make_leaflet(leaflet_info, n_x=8, n_y=8, tilt_angle=0, spacing=0, random_z_displacement=0): """ Generate a leaflet by laying down molecules in a 2D grid at random grid points Parameters --------- n_x : int Number of lipids in x direction n_y : int Number of lipids in y direction leaflet_info : n x 3 array Each row corresponds to a molecule First column is the mB.compound Second column is the number of that molecule Third column is a z-offset specific to molecules of that type (positive means closer to the solvent, negative means deeper inside the bilayer) tilt_angle : float (rad) tilt angle (spun around y-axis) spacing : float (nm) spacing between leaflets, based on area per lipid random_z_displacement : float (nm) Randomly offset molecules by a small amount Returns ------- leaflet : mb.Compound() Leaflet of molecules """ _validate_leaflet_info(leaflet_info, n_x, n_y) leaflet = mb.Compound() # Create ordered pairs ordered_pairs = [] for i, j in product(range(n_x), range(n_y)): ordered_pairs.append((i, j)) # Randomly assign ordered pairs to each lipid # based on the way lipids is set, all of one molecule is listed first # before getting to the next one # Loop through each type of molecule (DSPC, DPPC, etc.) for i, lipid_type in enumerate(leaflet_info): # Loop through the system's quantity of that particular molecule for n in range(lipid_type[1]): random_index = np.random.randint(0, len(ordered_pairs)) (i, j) = ordered_pairs.pop(random_index) # Do geometry transformations molecule_to_add = mb.clone(lipid_type[0]) # Apply tilt angle molecule_to_add.spin(tilt_angle, [0, 1, 0]) # Apply z_offset z_offset = lipid_type[2] # Apply APL and z_offset to identify the position for the # molecule in the grid position = [ i * spacing, j * spacing, z_offset + (-1 * np.random.random() * random_z_displacement) ] molecule_to_add.translate(position) # Add the new molecule to the leaflet leaflet.add(molecule_to_add) return leaflet
self.add_bond([n, c5]) self.add_bond([c5, c6]) self.add(mb.Port(anchor=c5), 'up') self.add(mb.Port(anchor=c6), 'down') # Implicit hydrogens # XYZ doesn't matter, we just need bonds and particle names # So we can upload to charmm-gui cap_with = 'H' pvp = mb.Polymer(mvp(), n=2) if cap_with == 'C': c_top = mb.Particle(name='C') cap_top = mb.Compound() cap_top.add(c_top) cap_top.add(mb.Port(anchor=c_top), 'down') mb.force_overlap(cap_top, cap_top['down'], pvp['up']) c_bot = mb.Particle(name='C') cap_bot = mb.Compound() cap_bot.add(c_bot) cap_bot.add(mb.Port(anchor=c_bot), 'up') mb.force_overlap(cap_bot, cap_bot['up'], pvp['down']) pvp.add(cap_top) pvp.add(cap_bot) elif cap_with == 'H': pass
import mbuild import foyer import unyt as u import mosdef_cassandra as mc # Load the force field from foyer ff = foyer.forcefields.load_TRAPPE_UA() # Create a single site methane molecule methane = mbuild.Compound(name="_CH4") # Apply the force field methane_ff = ff.apply(methane) # Create an empty 3x3x3 nm^3 simulation box box = mbuild.Box([3., 3., 3.]) # Define the box/species lists box_list = [box] species_list = [methane_ff] # Tell Cassandra to add 100 methane at the start mols_to_add = [[100]] # Create the System and MoveSet system = mc.System(box_list, species_list, mols_to_add=mols_to_add) moveset = mc.MoveSet("npt", species_list) # Run the Monte Carlo simulation mc.run( system=system,
def populate(self, compound_dict=None, x=1, y=1, z=1): """Expand lattice and create compound from lattice. Expands lattice based on user input. The user must also pass in a dictionary that contains the keys that exist in the basis_dict. The corresponding Compound will be the full lattice returned to the user. If no dictionary is passed to the user, Dummy Compounds will be used. Parameters ---------- x : int, optional, default=1 How many iterations in the x direction. y : int, optional, default=1 How many iterations in the y direction. z : int, optional, default=1 How many iterations in the z direction. compound_dict : dictionary, optional, default=None Link between basis_dict and Compounds. Exceptions Raised ----------------- ValueError : incorrect x,y, or z values. TypeError : incorrect type for basis vector Call Restrictions ----------------- Called after constructor by user. """ x, y, z = self._sanitize_populate_args(x=x, y=y, z=z) if ((isinstance(compound_dict, dict)) or (compound_dict is None)): pass else: raise TypeError('Compound dictionary is not of type dict. ' '{} was passed.'.format(type(compound_dict))) cell = defaultdict(list) [a, b, c] = self.lattice_spacing transform_mat = self.lattice_vectors # Unit vectors transform_mat = np.asarray(transform_mat, dtype=np.float64) transform_mat = np.reshape(transform_mat, newshape=(3,3)) norms = np.linalg.norm(transform_mat, axis=1) # Normalized vectors for change of basis unit_vecs = np.divide(transform_mat.transpose(), norms) # Generate new coordinates for key, locations in self.lattice_points.items(): for coords in locations: for replication in it.product(range(x), range(y), range(z)): new_coords = np.asarray(coords, dtype=np.float64) new_coords = np.reshape(new_coords, (1, 3), order='C') new_coords[0][0] = new_coords[0][0] + replication[0] new_coords[0][1] = new_coords[0][1] + replication[1] new_coords[0][2] = new_coords[0][2] + replication[2] # Change of basis to cartesian new_coords = np.dot(unit_vecs, new_coords.transpose()) new_coords[0] = new_coords[0] * a new_coords[1] = new_coords[1] * b new_coords[2] = new_coords[2] * c new_coords = np.reshape(new_coords, (1, 3), order='C') tuple_of_coords = tuple(new_coords.flatten()) cell[key].append(tuple_of_coords) ret_lattice = mb.Compound() # Create (clone) a mb.Compound for the newly generate positions if compound_dict is None: for key_id, all_pos in cell.items(): particle = mb.Compound(name=key_id, pos=[0, 0, 0]) for pos in all_pos: particle_to_add = mb.clone(particle) particle_to_add.translate_to(list(pos)) ret_lattice.add(particle_to_add) else: for key_id, all_pos in cell.items(): if isinstance(compound_dict[key_id], mb.Compound): compound_to_move = compound_dict[key_id] for pos in all_pos: tmp_comp = mb.clone(compound_to_move) tmp_comp.translate_to(list(pos)) ret_lattice.add(tmp_comp) else: err_type = type(compound_dict.get(key_id)) raise TypeError('Invalid type in provided Compound ' 'dictionary. For key {}, type: {} was ' 'provided, not mbuild.Compound.' .format(key_id, err_type)) # set periodicity, currently assuming rectangular system if not np.all(np.allclose(self.angles, [90.0, 90.0, 90.0])): warn('Periodicity of non-rectangular lattices are not valid with ' 'default boxes. Only rectangular lattices are valid ' 'at this time.') ret_lattice.periodicity = np.asarray([a * x, b * y, c * z], dtype=np.float64) # if coordinates are below a certain threshold, set to 0 tolerance = 1e-12 ret_lattice.xyz_with_ports[ret_lattice.xyz_with_ports <= tolerance] = 0. return ret_lattice
""" def __init__(self, lattice_spacing=None, compound_to_add=None, x=1, y=1, z=1): super(FCC, self).__init__() lattice_points = { 'A': [[0, 0, 0], [0, 0.5, 0.5], [0.5, 0.5, 0], [0.5, 0, 0.5]] } angles = [90, 90, 90] fcc_lattice = mbuild.Lattice(lattice_spacing=lattice_spacing, angles=angles, lattice_points=lattice_points) self.add( fcc_lattice.populate(x=x, y=y, z=z, compound_dict={'A': compound_to_add})) if __name__ == "__main__": au_fcc_lattice = FCC(lattice_spacing=0.40782, compound_to_add=mbuild.Compound(name="Au"), x=5, y=5, z=1) print(au_fcc_lattice)
def test_incorrect_populate_inputs(self, x, y, z): with pytest.raises(ValueError): test_lattice = mb.Lattice(lattice_spacing=[1, 1, 1]) test_lattice.populate( compound_dict={"id": mb.Compound()}, x=x, y=y, z=z )
def create_system( pore_width, n_ion_pairs, n_water, pve_ion=mbuild.Compound(name="Na"), nve_ion=mbuild.Compound(name="Cl"), engine="cassandra", ): """Create a system with a graphene pore filled with n_ion_pairs, (na, cl), and n_water spce water molecules. Parameters ---------- pore_width : u.unyt_quantity (length) width of pore for restricted insertions n_ion_pairs : int number of na, cl ion pairs n_water : int number of water molecules pve_ion : mbuild.Compound, optional, default=Na positive ion nve_ion : mbuild.Compound, optional, default=Cl negative ion engine : str, optional, default="cassandra" engine system is being initialized for, determines how box is created Returns ------- filled_pore : mbuild.Compound """ if n_ion_pairs == 0: filled_pore = mbuild.recipes.GraphenePoreSolvent( pore_length=2.3, pore_depth=2.2, pore_width=pore_width.to_value("nm"), n_sheets=3, slit_pore_dim=2, x_bulk=0, solvent=spce_water, n_solvent=n_water, ) else: # Create pore system filled_pore = mbuild.recipes.GraphenePoreSolvent( pore_length=2.3, pore_depth=2.2, pore_width=pore_width.to_value("nm"), n_sheets=3, slit_pore_dim=2, x_bulk=0, solvent=[pve_ion, nve_ion, spce_water], n_solvent=[n_ion_pairs, n_ion_pairs, n_water], ) # Translate to centered at 0,0,0 and make box larger in z if engine == 'cassandra': box_center = filled_pore.periodicity / 2.0 filled_pore.translate(-box_center) return filled_pore
def test_remove_no_bond_graph(self): compound = mb.Compound() particle = mb.Compound(name='C', pos=[0, 0, 0]) compound.add(particle, 'test-particle') compound.remove(particle) assert particle not in compound.particles()
import mbuild as mb from mbuild.formats.lammpsdata import write_lammpsdata import scripts.bilayer as bilayer # Import statements for molecule prototypes import atomistic.dppc.DPPC as DPPC import atomistic.c24ffa.ffa24 as ffa24 import atomistic.tip3p.SOL as SOL ################### ## Sample script to convert a GROMACS structure to a ## fully-parameterized LAMMPS system #################### system = mb.Compound() for i in range(72): system.add(DPPC.DPPC(use_atom_name=False)) 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()]))
def test_min_periodic_dist(self, ethane): compound = mb.Compound(ethane) C_pos = np.array([atom.pos for atom in list(compound.particles_by_name('C'))]) assert round(compound.min_periodic_distance(C_pos[0], C_pos[1]), 2) == 0.14 compound.periodicity = np.array([0.2, 0.2, 0.2]) assert round(compound.min_periodic_distance(C_pos[0], C_pos[1]), 2) == 0.06
def methane_trappe(self): trappe = foyer.forcefields.load_TRAPPE_UA() methane = mbuild.Compound(pos=[0.0, 0.0, 0.0], name="_CH4") methane = trappe.apply(methane) return methane
def test_save_resnames_single(self, c3, n4): system = mb.Compound([c3, n4]) system.save('resnames_single.gro', residues=['C3', 'N4']) struct = pmd.load_file('resnames_single.gro') assert struct.residues[0].number == 1 assert struct.residues[1].number == 2
def wrongbox(self): box = mbuild.Compound() box.boundingbox.lengths = [5.0, 5.0, 5.0] return box
def methane_ua_gomc(self): methane_ua_gomc = mb.Compound(name="_CH4") return methane_ua_gomc
def from_mbuild(compound, box=None, search_method=element_by_symbol): """Convert an mbuild.Compound to a gmso.Topology. This conversion makes the following assumptions about the inputted `Compound`: * All positional and box dimension values in compound are in nanometers. * If the `Compound` has 4 or more levels of hierarchy, these are\ compressed to 3 levels of hierarchy in the resulting `Topology`. The\ top level `Compound` becomes the `Topology`, the second level\ Compounds become `SubTopologies`, and each particle becomes a `Site`,\ which are added to their corresponding `SubTopologies`. * Furthermore, `Sites` that do not belong to a sub-`Compound` are\ added to a single-`Site` `SubTopology`. * The box dimension are extracted from `compound.periodicity`. If\ the `compound.periodicity` is `None`, the box lengths are the lengths of\ the bounding box + a 0.5 nm buffer. * Only `Bonds` are added for each bond in the `Compound`. If `Angles`\ and `Dihedrals` are desired in the resulting `Topology`, they must be\ added separately from this function. Parameters ---------- compound : mbuild.Compound mbuild.Compound instance that need to be converted box : mbuild.Box, optional, default=None Box information to be loaded to a gmso.Topology search_method : function, optional, default=element_by_symbol Searching method used to assign element from periodic table to particle site. The information specified in the `search_method` argument is extracted from each `Particle`'s `name` attribute. Valid functions are element_by_symbol, element_by_name, element_by_atomic_number, and element_by_mass, which can be imported from `gmso.core.element' Returns ------- top : gmso.Topology """ msg = "Argument compound is not an mbuild.Compound" assert isinstance(compound, mb.Compound), msg top = Topology() top.typed = False # Keep the name if it is not the default mBuild Compound name if compound.name != mb.Compound().name: top.name = compound.name site_map = dict() for child in compound.children: if len(child.children) == 0: continue else: subtop = SubTopology(name=child.name) top.add_subtopology(subtop, update=False) for particle in child.particles(): pos = particle.xyz[0] * u.nanometer ele = search_method(particle.name) site = Atom(name=particle.name, position=pos, element=ele) site_map[particle] = site subtop.add_site(site, update_types=False) for particle in compound.particles(): already_added_site = site_map.get(particle, None) if already_added_site: continue pos = particle.xyz[0] * u.nanometer ele = search_method(particle.name) site = Atom(name=particle.name, position=pos, element=ele) site_map[particle] = site # If the top has subtopologies, then place this particle into # a single-site subtopology -- ensures that all sites are in the # same level of hierarchy. if len(top.subtops) > 0: subtop = SubTopology(name=particle.name) top.add_subtopology(subtop) subtop.add_site(site, update_types=False) else: top.add_site(site, update_types=False) for b1, b2 in compound.bonds(): new_bond = Bond(connection_members=[site_map[b1], site_map[b2]], bond_type=None) top.add_connection(new_bond, update_types=False) top.update_topology() if box: top.box = from_mbuild_box(box) # Assumes 2-D systems are not supported in mBuild # if compound.periodicity is None and not box: else: if compound.box: top.box = from_mbuild_box(compound.box) else: top.box = from_mbuild_box(compound.get_boundingbox()) top.periodicity = compound.periodicity return top
def test_init_with_subcompounds2(self, ethane, h2o): compound = mb.Compound([ethane, h2o]) assert compound.n_particles == 8 + 3 assert compound.n_bonds == 7 + 2
def run_gemc(**custom_args): # Use mbuild to create molecules methane = mbuild.Compound(name="_CH4") # Create two empty mbuild.Box # (vapor = larger, liquid = smaller) liquid_box = mbuild.Box(lengths=[3.0, 3.0, 3.0]) vapor_box = mbuild.Box(lengths=[4.0, 4.0, 4.0]) # Load forcefields trappe = foyer.forcefields.load_TRAPPE_UA() # Use foyer to apply forcefields typed_methane = trappe.apply(methane) # Create box and species list box_list = [liquid_box, vapor_box] species_list = [typed_methane] mols_to_add = [[350], [100]] system = mc.System(box_list, species_list, mols_to_add=mols_to_add) moveset = mc.MoveSet("gemc", species_list) moveset.prob_volume = 0.010 moveset.prob_swap = 0.11 thermo_props = [ "energy_total", "energy_intervdw", "pressure", "volume", "nmols", "mass_density", ] default_args = { "run_name": "equil", "charge_style": "none", "rcut_min": 2.0 * u.angstrom, "vdw_cutoff": 14.0 * u.angstrom, "units": "sweeps", "steps_per_sweep": 450, "coord_freq": 50, "prop_freq": 10, "properties": thermo_props, } # Combine default/custom args and override default custom_args = {**default_args, **custom_args} mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=250, temperature=151.0 * u.K, **custom_args, ) # Update run_name and restart_name custom_args["run_name"] = "prod" custom_args["restart_name"] = "equil" mc.restart( system=system, moveset=moveset, run_type="production", run_length=750, temperature=151.0 * u.K, **custom_args, )
def test_init_with_bad_name(self): with pytest.raises(ValueError): mb.Compound(name=1)
def construct_system(dist_from_sheet=0.7, box_thickness=0.5, n_load_per_side=10, bilayer_center=[5.387, 5.347, 3.26]): """ Build graphene + sds + bilayer + ions The idea is to pack a box below the sheet and below the sheet. The density of SDS is 1.01 g/cm$^3$, which equates to 2.109 molecules/nm$^3$ The box we are filling is about 5nm x 5nm x 0.635nm. At max SDS density, this is 33.5 molecules of SDS Parameters --------- dist_from_sheet : float, default 0.7 nm When defining the box above/below the sheet, specify how far above/below box_thickness : float: default 0.5nm When defining the box to fill, the X and Y dimensions take from the graphene sheet, but the Z dimensions (thickness) is defined in box_thickneess n_load_per_side : int, default 10 Important for packing the boxes and specifying number of SDS (and Na ions) to add to the system """ header = """; Include forcefield parameters #include "/raid6/homes/ahy3nz/Programs/graphene_build/force-field/ffmix.itp" #include "/raid6/homes/ahy3nz/Programs/graphene_build/force-field/molecules.itp" #include "/raid6/homes/ahy3nz/Programs/graphene_build/force-field/ions.itp """ gra = mb.load(os.path.join(PATH_TO_MOLECULES, 'sheet.gro')) gra.name = 'GRA_5' sds = mb.load(os.path.join(PATH_TO_MOLECULES, 'SDS.gro')) sds.name = 'SDS' # The SDS molecules are initially aligned with the Z-axis, so do a rotation sds.spin(np.pi / 2, [1, 0, 0]) na_part = mb.Particle(name="NA") na = mb.Compound() na.name = "NA" na.add(na_part) above_box = mb.Box(mins=np.min(gra.xyz, axis=0) + [0, 0, dist_from_sheet], maxs=np.max(gra.xyz, axis=0) + [0, 0, dist_from_sheet + box_thickness]) fill_above = fill_box([sds, na], n_compounds=[n_load_per_side, n_load_per_side], box=above_box, edge=0.1, overlap=0.1) below_box = mb.Box(mins=np.min(gra.xyz, axis=0) - [0, 0, dist_from_sheet + box_thickness], maxs=np.max(gra.xyz, axis=0) - [0, 0, dist_from_sheet]) fill_below = fill_box([sds, na], n_compounds=[n_load_per_side, n_load_per_side], box=below_box, edge=0.1, overlap=0.1) sys = mb.Compound() sys.add([gra, fill_above, fill_below]) sys.spin(np.pi / 2, [1, 0, 0]) # Do some rotations to get it corner first sys.spin(np.pi / 4, [0, 1, 0]) sys.translate_to(bilayer_center) # This is the bilayer center sys.translate([0, 0, 6]) # Shift the loaded GNF up to be above the bialyer # For the sake of writing, we will be using a lot of mdtraj functionality traj = sys.to_trajectory(residues=['GRA_5', 'SDS', 'NA']) bilayer = mdtraj.load(os.path.join(PATH_TO_MOLECULES, 'bilayer.gro')) composite_traj = traj.stack(bilayer) composite_traj.unitcell_lengths = bilayer.unitcell_lengths composite_traj.unitcell_lengths[0, 2] = 13 composite_traj[0].save('composite.gro') write_gmx_topology('topol.top', composite_traj, header=header) # Use external module to perform rotations and write pulling MDP graphene_rotations.rotate_gnf_write_mdp(gro_file='composite.gro', angle_of_attack=0, force_constant=50, outgro='composite_rotated.gro')