def __init__(self, chain_length, internal_group, locations): super(Alkylsilane, self).__init__() hmodule = __import__('atools.lib.moieties.multiple_ports.' + internal_group) hclass_ = getattr(hmodule.lib.moieties.multiple_ports, internal_group.title()) hgroup = hclass_() # Determine alkane segments if isinstance(locations, int): locations = [locations] locations.sort() silane = Silane() self.add(silane, 'silane') self.add(silane['down'], 'down', containment=False) if 0 in locations: ''' self.add(hgroup, 'hgroup') mb.force_overlap(self['silane'], self['silane']['up'], self['hgroup']['down']) ''' current_segment = silane else: first_length = locations[0] first_segment = Alkane(first_length, cap_front=False, cap_end=False) self.add(first_segment, 'bottom_chain') mb.force_overlap(self['silane'], self['silane']['up'], self['bottom_chain']['down']) current_segment = first_segment c_remove = 0 if internal_group in ['amide', 'hemiacetal']: c_remove += 1 for i, loc in enumerate(locations[1:]): hgroup_clone = mb.clone(hgroup) self.add(hgroup_clone, 'hgroup{}'.format(i + 1)) mb.force_overlap(self['hgroup{}'.format(i + 1)], self['hgroup{}'.format(i + 1)]['down'], current_segment['up']) current_segment = hgroup_clone length = loc - locations[i] - 1 - c_remove if length > 0: segment = Alkane(length, cap_front=False, cap_end=False) self.add(segment, 'internal_chain{}'.format(i + 1)) current_segment = segment mb.force_overlap( self['internal_chain{}'.format(i + 1)], self['internal_chain{}'.format(i + 1)]['down'], self['hgroup{}'.format(i + 1)]['up']) self.add(hgroup, 'hgroup') mb.force_overlap(self['hgroup'], self['hgroup']['down'], current_segment['up']) last_length = chain_length - locations[-1] - 1 - c_remove if last_length: last_segment = Alkane(last_length, cap_front=True, cap_end=False) self.add(last_segment, 'top_chain') mb.force_overlap(self['top_chain'], self['top_chain']['down'], self['hgroup']['up']) else: hydrogen = H() self.add(hydrogen, 'H-cap') mb.force_overlap(self['H-cap'], self['H-cap']['up'], self['hgroup']['up'])
def initialize(job): "Initialize the simulation configuration." ''' --------------------------- Read statepoint information --------------------------- ''' chainlength = job.statepoint()['chainlength'] n_chains = job.statepoint()['n'] seed = job.statepoint()['seed'] terminal_group = job.statepoint()['terminal_group'] ''' ----------------------------------- Generate amorphous silica interface ----------------------------------- ''' surface = SilicaInterface(thickness=1.2, seed=seed) ''' ------------------------------------------------------ Generate prototype of functionalized alkylsilane chain ------------------------------------------------------ ''' chain_prototype = Alkylsilane(chain_length=chainlength, terminal_group=terminal_group) ''' ---------------------------------------------------------- Create monolayer on surface, backfilled with hydrogen caps ---------------------------------------------------------- ''' monolayer = SurfaceMonolayer(surface=surface, chains=chain_prototype, n_chains=n_chains, seed=seed, backfill=H(), rotate=False) ''' ------------------------------------------ Duplicate to yield two opposing monolayers ------------------------------------------ ''' dual_monolayer = DualSurface(monolayer, 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. ------------------------------------------------------------------- ''' forcefield_dir = resource_filename('atools', 'forcefields') dual_monolayer.save('init.gro', overwrite=True) dual_monolayer.save('init.top', forcefield_files=os.path.join(forcefield_dir, 'oplsaa.xml'), combining_rule='geometric', overwrite=True) dual_monolayer.save('init.lammps', forcefield_files=os.path.join(forcefield_dir, 'oplsaa.xml'), combining_rule='geometric', overwrite=True) ''' -------------------------------------- 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')
def hydrogen(self): from mbuild.lib.atoms import H return H()
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")
surface.translate_to([0, 0, 0]) surface.translate([0, 0, -1 * min(surface.xyz[:,2]) - shift]) radius = max(surface.xyz[:,2]) - min(surface.xyz[:,2]) pattern = RandomHemispherePattern(n=n_chains, seed=seed) pattern.scale(radius) elif surface.name == 'SilicaAsperity': pass else: pattern = mb.Random2DPattern(n_chains, seed=seed) if chains and n_chains > 0: monolayer = Monolayer(surface=surface, chains=chains, pattern=pattern, fractions=fractions, backfill=backfill, **kwargs) else: monolayer = Monolayer(surface=surface, chains=backfill, guest_port_name='up', **kwargs) self.add(monolayer) if __name__ == "__main__": from alkylsilane import Alkylsilane from silica_interface import SilicaInterface from mbuild.lib.atoms import H hydrogen = H() seed = 12345 chain = Alkylsilane(chain_length=6, terminal_group='methyl') planar_surface = SilicaInterface(seed=seed) planar_monolayer = SurfaceMonolayer(surface=planar_surface, chains=chain, n_chains=100, seed=seed, backfill=hydrogen)
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(self, n, sequence="A", add_hydrogens=True): """Connect one or more components in a specified sequence. Uses the compounds that are stored in Polymer.monomers and Polymer.end_groups. Parameters ---------- n : int The number of times to replicate the sequence. sequence : str, optional, default 'A' A string of characters where each unique character represents one repetition of a monomer. Characters in `sequence` are assigned to monomers in the order they appear in `Polymer.monomers`. The characters in `sequence` are assigned to the compounds in the in the order that they appear in the Polymer.monomers list. For example, 'AB' where 'A'corresponds to the first compound added to Polymer.monomers and 'B' to the second compound. add_hydrogens : bool, default True If True and an end group compound is None, then the head or tail of the polymer will be capped off with hydrogen atoms. If end group compounds exist, then they will be used. If False and an end group compound is None, then the head or tail port will be exposed in the polymer. """ if n < 1: raise ValueError("n must be 1 or more") n_monomers = n * len(sequence) for monomer in self._monomers: for label in self._port_labels: assert_port_exists(label, monomer) unique_seq_ids = sorted(set(sequence)) if len(self._monomers) != len(unique_seq_ids): raise ValueError( "Number of monomers passed to `Polymer` class must match " "number of unique entries in the specified sequence.") # 'A': monomer_1, 'B': monomer_2.... seq_map = dict(zip(unique_seq_ids, self._monomers)) last_part = None for n_added, seq_item in enumerate(it.cycle(sequence)): this_part = clone(seq_map[seq_item]) self.add(this_part, "monomer[$]") if last_part is None: first_part = this_part else: # Transform this part, such that its bottom port is rotated # and translated to the last parts top port. force_overlap( this_part, this_part.labels[self._port_labels[0]], last_part.labels[self._port_labels[1]], ) last_part = this_part if n_added == n * len(sequence) - 1: break # Add the end groups head = self["monomer[0]"] # First monomer tail = self["monomer[{}]".format(n_monomers - 1)] # Last monomer if not head["up"].used: head_port = head["up"] else: head_port = None if not tail["down"].used: tail_port = tail["down"] else: tail_port = None head_tail = [head_port, tail_port] for i, compound in enumerate(self._end_groups): if compound is not None: if self._headtail[i] is not None: head_tail[i].update_separation(self._headtail[i]) self.add(compound) force_overlap(compound, compound.labels["up"], head_tail[i]) else: if add_hydrogens: hydrogen = H() # Defaut to 1/2 H-C bond len head_tail[i].update_separation(0.0547) hydrogen["up"].update_separation(0.0547) self.add(hydrogen) force_overlap(hydrogen, hydrogen["up"], head_tail[i]) else: # if None, hoist port to polymer level self.add(head_tail[i], self._port_labels[i], containment=False) for port in self.all_ports(): if port not in self.available_ports(): self.remove(port)
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')