def __init__(self, chain_length): """Initialize an Alkane Compound. Parameters ---------- chain_length : int Length of the alkane chain (in number of carbons) """ # Make sure the user inputs a chain length of at least 1 if chain_length < 1: raise ValueError('Chain length must be greater than 1') super(Alkane, self).__init__() # Create a polymer of CH2 units chain = mb.recipes.Polymer(CH2(), n=chain_length, port_labels=('up', 'down')) self.add(chain, 'chain') # Cap one end of the polymer with a hydrogen self.add(H(), 'up_cap') mb.force_overlap(move_this=self['up_cap'], from_positions=self['up_cap']['up'], to_positions=self['chain']['up']) # Cap the other end of the polymer with a hydrogen self.add(H(), 'down_cap') mb.force_overlap(move_this=self['down_cap'], from_positions=self['down_cap']['up'], to_positions=self['chain']['down'])
def __init__(self, pattern, tile_x=1, tile_y=1, chain_length=10): """Create an alkylsilane monolayer on beta-cristobalite. Parameters ---------- pattern : np.ndarray, shape=(n, 3), optional, default=None An array of planar binding locations. If not provided, the entire surface will be filled with `chain`. tile_x : int, optional, default=1 Number of times to replicate substrate in x-direction. tile_y : int, optional, default=1 Number of times to replicate substrate in y-direction. chain_length : int, optional, default=10 Number of carbon atoms per chain. """ surface = Betacristobalite() alkylsilane = AlkylSilane(chain_length) hydrogen = H() super(AlkaneMonolayer, self).__init__(surface, alkylsilane, backfill=hydrogen, pattern=pattern, tile_x=tile_x, tile_y=tile_y) # -- ==alkane_monolayer== --
def test_monolayer(self, ch2): n = 8 m = 8 pattern = mb.Grid2DPattern(n, m) chain = mb.Polymer(ch2, n=10) monolayer = mb.Monolayer(surface=Betacristobalite(), chains=chain, backfill=H(), pattern=pattern) assert monolayer.n_particles == 1900 + n * m * (10 * 3) + (100 - n * m) assert monolayer.n_bonds == 2400 + n * m * (10 * 2 + 9 + 1) + (100 - n * m)
def __init__(self, pattern, tile_x=1, tile_y=1, chain_length=4, alpha=pi / 4): surface = Betacristobalite() brush = Brush(chain_length=chain_length, alpha=alpha) hydrogen = H() super(PMPCLayer, self).__init__(surface, brush, backfill=hydrogen, pattern=pattern, tile_x=tile_x, tile_y=tile_y)
def main(args): length = 2 backbone = args.backbone locations = [0] terminal_group = args.terminal_group cpa = AlkylsilaneInternal(chain_length=length, internal_group=backbone, locations=locations, terminal_group=terminal_group) h = H() compound = mb.Compound() compound.add(cpa, 'cpa') compound.add(h, 'h') mb.force_overlap(compound['cpa'], compound['cpa'].all_ports()[0], compound['h'].all_ports()[0]) structure = cpa.to_parmed(box=None, residues=['chain']) ff = Forcefield(forcefield_files='../shearing-code/src/util/forcefield/oplsaa.xml') structure_ = ff.apply(structure)
def test_monolayer(self, ch2): n = 8 m = 8 pattern = mb.Grid2DPattern(n, m) chain = mb.recipes.Polymer(monomers=[ch2]) chain.build(n=10, add_hydrogens=False) monolayer = mb.recipes.Monolayer( surface=Betacristobalite(), chains=chain, backfill=H(), pattern=pattern, ) assert monolayer.n_particles == 2000 + n * m * 29 assert monolayer.n_bonds == 2500 + n * m * 29
def test_pattern_kwargs(self, ch2): n = 8 m = 8 pattern = mb.Grid2DPattern(n, m) chain = mb.Polymer(ch2, n=10) monolayer = mb.Monolayer(surface=Betacristobalite(), chains=H(), guest_port_name='up', backfill=chain, backfill_port_name='down', pattern=pattern) chains = 100 - (n * m) assert monolayer.n_particles == 1900 + chains * (10 * 3) + (100 - chains) assert monolayer.n_bonds == 2400 + chains * (10 * 2 + 9 + 1) + (100 - chains)
def initialize(job): "Initialize the simulation configuration." from pkg_resources import resource_filename from mbuild.lib.atoms import H from atools.fileio import write_monolayer_ndx from atools.lib.chains import Alkylsilane from atools.recipes import DualSurface, SilicaInterface, SurfaceMonolayer from atools.structure import identify_rigid_groups with job: chainlength = job.statepoint()['chainlength'] n_chains = job.statepoint()['n'] seed = job.statepoint()['seed'] terminal_group = job.statepoint()['terminal_group'] surface = SilicaInterface(thickness=1.2, seed=seed) chain_proto = Alkylsilane(chain_length=chainlength, terminal_group=terminal_group) monolayer = SurfaceMonolayer(surface=surface, chains=chain_proto, n_chains=n_chains, seed=seed, backfill=H()) dual_monolayer = DualSurface(monolayer) box = dual_monolayer.boundingbox dual_monolayer.periodicity += np.array([0, 0, 5. * box.lengths[2]]) forcefield_dir = resource_filename('atools', 'forcefields') dual_monolayer.save('init.gro', forcefield_files=os.path.join( forcefield_dir, 'oplsaa-silica.xml'), overwrite=True) dual_monolayer.save('init.top', forcefield_files=os.path.join( forcefield_dir, 'oplsaa-silica.xml'), overwrite=True) rigid_groups = identify_rigid_groups(monolayer=dual_monolayer, terminal_group=terminal_group, freeze_thickness=0.5) write_monolayer_ndx(rigid_groups=rigid_groups, filename='init.ndx')
def test_mixed_monolayer(self, ch2): n = 8 m = 8 pattern = mb.Grid2DPattern(n, m) fractions = [0.75, 0.25] chain_a = mb.Polymer(ch2, n=5) chain_b = mb.Polymer(ch2, n=15) monolayer = mb.Monolayer(surface=Betacristobalite(), chains=[chain_a, chain_b], fractions=fractions, backfill=H(), pattern=pattern) n_a = round(n * m * 0.75) n_b = round(n * m * 0.25) assert monolayer.n_particles == 1900 + n_a * 5 * 3 + n_b * 15 * 3 + ( 100 - (n_a + n_b)) assert monolayer.n_bonds == 2400 + n_a * (5 * 2 + 4 + 1) + n_b * ( 15 * 2 + 14 + 1) + (100 - (n_a + n_b))
def test_pattern_kwargs(self, ch2): n = 8 m = 8 pattern = mb.Grid2DPattern(n, m) chain = mb.recipes.Polymer(monomers=[ch2]) chain.build(n=10, add_hydrogens=False) monolayer = mb.recipes.Monolayer( surface=Betacristobalite(), chains=H(), guest_port_name="up", backfill=chain, backfill_port_name="down", pattern=pattern, ) chains = 100 - (n * m) assert monolayer.n_particles == 2000 + chains * 29 assert monolayer.n_bonds == 2500 + chains * 29
def test_mixed_monolayer(self, ch2): n = 8 m = 8 pattern = mb.Grid2DPattern(n, m) fractions = [0.75, 0.25] chain_a = mb.recipes.Polymer(monomers=[ch2]) chain_a.build(n=5, add_hydrogens=False) chain_b = mb.recipes.Polymer(monomers=[ch2]) chain_b.build(n=15, add_hydrogens=False) monolayer = mb.recipes.Monolayer( surface=Betacristobalite(), chains=[chain_a, chain_b], fractions=fractions, backfill=H(), pattern=pattern, ) n_a = round(n * m * 0.75) n_b = round(n * m * 0.25) assert monolayer.n_particles == 2000 + n_a * 14 + n_b * 44 assert monolayer.n_bonds == 2500 + n_a * 14 + n_b * 44
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 hydrogen(self): from mbuild.lib.atoms import H return H()
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 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")
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 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
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 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')