Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions polyconf/polyconf/PDB.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ def _write(self, selection, name):
atoms = self.polymer.select_atoms(selection)
atoms.write(name)

def save(self, dummyAtoms="X*", fname="polymer", selectionString = None, gmx = False):
def save(self, dummies="X*", fname="polymer", selectionString = None, gmx = False):
"""
Save polymer as a PDB or GROMACS file with dummy atoms excluded.
Optionally, select a subset of the polymer to save.

:param dummyAtoms: names of all the dummy atoms, for use in the
:param dummies: names of all the dummy atoms, for use in the
selection string (e.g. 'CN CMA CP CQ' to exclude these
four dummy atom types), defaults to "X*"
:type dummyAtoms: str, optional
:type dummies: str, optional
:param fname: name of the output file, defaults to "polymer"
:type fname: str, optional
:param selectionString: MDAnalysis atom selection string, for more
Expand All @@ -55,14 +55,14 @@ def save(self, dummyAtoms="X*", fname="polymer", selectionString = None, gmx = F
"""
if selectionString:
if gmx:
self.select_atoms(f"{selectionString} and not name {dummyAtoms}")._write(f"{fname}.gro")
self.select_atoms(f"{selectionString} and not name {dummies}").atoms._write(f"{fname}.gro")
else:
self.select_atoms(f"{selectionString} and not name {dummyAtoms}")._write(f"{fname}.pdb")
self.select_atoms(f"{selectionString} and not name {dummies}").atoms._write(f"{fname}.pdb")
else:
if gmx:
self._write(f"not name {dummyAtoms}", f"{fname}.gro")
self._write(f"not name {dummies}", f"{fname}.gro")
else:
self._write(f"not name {dummyAtoms}", f"{fname}.pdb")
self._write(f"not name {dummies}", f"{fname}.pdb")

def crudesave(self,fname="polymer_crude"):
"""
Expand Down
222 changes: 117 additions & 105 deletions polyconf/polyconf/Polymer.py

Large diffs are not rendered by default.

290 changes: 173 additions & 117 deletions polyconf_examples/build_PEI_linear.py

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions polyconf_examples/build_PMMA_01-isotactic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env python

from polyconf.Monomer import Monomer
from polyconf.Polymer import Polymer
from polyconf.PDB import PDB
import random
random.seed(1)

###############################################################################
# #
# Polymer one: Building an isotactic PMMA polymer #
# #
###############################################################################

print ('creating an isotactic PMMA polymer')

dummies="CMA CN CP CQ"

PMMA_isotactic=Polymer(Monomer('MMAD_bonds.pdb')) # initialise

adds=49 # we will lay 49 additional monomers

for i in range (0,adds):
PMMA_isotactic.extend( # extend with one monomer, aligned along this step's linearization vector
Monomer('MMAD_bonds.pdb'), # extend with this monomer
n=PMMA_isotactic.maxresid(), # extend existing residue i
nn=PMMA_isotactic.newresid(), # incoming monomer will have resid i+1
names=dict(Q='CA',P='CMA',S='C',R='CN',), # C1_i+1 fit to CX_i, then rotate so NX_i+1 fit to N1_i
joins=[('C','CA')],# new connection between N1_i and C1_i+1
#linearise=True,
#ortho=[1,0,0]
)

alkanes=PMMA_isotactic.gen_pairlist(J='C',K='CA',first_resid=1,same_res=False,last_resid=49,mult=3)
sidechains=PMMA_isotactic.gen_pairlist(J='CA',K='CB',first_resid=1,same_res=True,last_resid=50,mult=6)

Saver = PDB(PMMA_isotactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_isotactic_vanilla-extend') # save, excluding dummies atoms

PMMA_isotactic.dihedral_solver(alkanes,dummies=dummies,cutoff=0.8) # this converts the shuffled conformation into one without overlapping atoms
PMMA_isotactic.dihedral_solver(sidechains,dummies=dummies,cutoff=0.8) # this converts the shuffled conformation into one without overlapping atoms

Saver = PDB(PMMA_isotactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_isotactic_vanilla-solved') # save, excluding dummies atoms

PMMA_isotactic.shuffler(alkanes)
PMMA_isotactic.dihedral_solver(alkanes,dummies=dummies,cutoff=1.1) # this converts the shuffled conformation into one without overlapping atoms

Saver = PDB(PMMA_isotactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_isotactic_shuffled_and_solved') # save, excluding dummies atoms


64 changes: 64 additions & 0 deletions polyconf_examples/build_PMMA_02-syndiotactic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python

from polyconf.Monomer import Monomer
from polyconf.Polymer import Polymer
from polyconf.PDB import PDB
import random
random.seed(1)


###############################################################################
# #
# Polymer two: Building a syndiotactic PMMA polymer #
# #
###############################################################################

print ('creating a syndiotactic PMMA polymer')

dummies="CMA CN CP CQ"

Monomer_D='MMAD_bonds.pdb'
Monomer_L='MMAL_bonds.pdb'
alternator=True

PMMA_syndiotactic=Polymer(Monomer(Monomer_D)) # initialise

adds=49 # we will lay 49 additional monomers

for i in range (0,adds):
if alternator:
monomer=Monomer_L
else:
monomer=Monomer_D
alternator=not alternator
PMMA_syndiotactic.extend( # extend with one monomer, aligned along this step's linearization vector
Monomer(monomer), # extend with this monomer
n=PMMA_syndiotactic.maxresid(), # extend existing residue i
nn=PMMA_syndiotactic.newresid(), # incoming monomer will have resid i+1
names=dict(Q='CA',P='CMA',S='C',R='CN'), # C1_i+1 fit to CX_i
joins=[('C','CA')],# new connection between N1_i and C1_i+1
)

Saver = PDB(PMMA_syndiotactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_syndiotactic_vanilla-extend') # save, excluding dummies atoms

alkanes=PMMA_syndiotactic.gen_pairlist(J='C',K='CA',first_resid=1,same_res=False,last_resid=49,mult=3)
sidechains=PMMA_syndiotactic.gen_pairlist(J='CA',K='CB',first_resid=1,same_res=True,last_resid=50,mult=6)

PMMA_syndiotactic.dihedral_solver(alkanes,dummies=dummies,cutoff=1.1) # this converts the shuffled conformation into one without overlapping atoms
PMMA_syndiotactic.dihedral_solver(sidechains,dummies=dummies,cutoff=1.1) # this converts the shuffled conformation into one without overlapping atoms

Saver = PDB(PMMA_syndiotactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_syndiotactic_vanilla-solved') # save, excluding dummies atoms


PMMA_syndiotactic.shuffler(alkanes)
PMMA_syndiotactic.dihedral_solver(alkanes,dummies=dummies,cutoff=1.1) # this converts the shuffled conformation into one without overlapping atoms
PMMA_syndiotactic.shuffler(sidechains)
PMMA_syndiotactic.dihedral_solver(sidechains,dummies=dummies,cutoff=1.1) # this converts the shuffled conformation into one without overlapping atoms

Saver = PDB(PMMA_syndiotactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_syndiotactic_shuffled_and_solved') # save, excluding dummies atoms
122 changes: 122 additions & 0 deletions polyconf_examples/build_PMMA_03-atactic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env python

from polyconf.Monomer import Monomer
from polyconf.Polymer import Polymer
from polyconf.PDB import PDB
import random
random.seed(10)

###############################################################################
# #
# Polymer three: Building an atactic PMMA polymer #
# #
###############################################################################

print ('creating an atactic PMMA polymer')

dummies="CMA CN CP CQ"
Monomer_D='MMAD_bonds.pdb'
Monomer_L='MMAL_bonds.pdb'

composition=25*[Monomer_D] + 25*[Monomer_L] # a list containing 50 monomers, 25 with each taticity
composition = random.sample(composition,len(composition)) # randomise the order of the monomers

PMMA_atactic=Polymer(Monomer(composition[0])) # initialise with first monomer

for monomer in composition[1:]: # extend with the remain 49 monomers
PMMA_atactic.extend( # extend with one monomer, aligned along this step's linearization vector
Monomer(monomer), # extend with this monomer
n=PMMA_atactic.maxresid(), # extend existing residue i
nn=PMMA_atactic.newresid(), # incoming monomer will have resid i+1
names=dict(Q='CA',P='CMA',S='C',R='CN'), # C1_i+1 fit to CX_i,
joins=[('C','CA')],# new connection between N1_i and C1_i+1
)

Saver = PDB(PMMA_atactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_atactic_vanilla-extend') # save, excluding dummies atoms

# have a look at this initial polymer, compared to the vanilla isotactic and syndiotactic polymers
# because of the particular conformations of the two monomers, and the random order of the monomer composition
# the backbone of this polymer is much more coiled.absyou might think this is desifreable, as it reflects a less ordered starting conformation
# however, many monomers have overlapping atoms, and it is unlikely that we could minimise this starting confromation

alkanes=PMMA_atactic.gen_pairlist(J='CA',K='C',first_resid=1,same_res=True,last_resid=50,mult=6)
sidechains=PMMA_atactic.gen_pairlist(J='CA',K='CB',first_resid=1,same_res=True,last_resid=50,mult=6)

dh=[] #combine alkanes and sidechains into one list of dihedrals, so we can shuffle the alkane and dihedral in each monomer in order

for i in range(0,50):
dh += [alkanes[i]]
dh += [sidechains[i]]

print('attempting to solve initial conformation')

PMMA_atactic.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

# this failed due to overlapping atoms

# we can attempt to rotate and shuffle dihedrals to find a valid conformation
# however the brute force search of dihedral space used by dihedral_solver() will fail for this particular random
# it is likely that repeated applications of shuffle and dihedral_solver will eventually find a reasonable conformation
# but we cannot know how many attempts this will take

print('shuffle attempt 01')

PMMA_atactic.shuffler(dh)

PMMA_atactic.dihedral_solver(dh,dummies=dummies,cutoff=1.1 )

Saver = PDB(PMMA_atactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_atactic_shuffle_01') # save, excluding dummies atoms

print('shuffle attempt 02')

PMMA_atactic.shuffler(dh)
PMMA_atactic.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

Saver = PDB(PMMA_atactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_atactic_shuffle_02') # save, excluding dummies atoms

print('shuffle attempt 03')

PMMA_atactic.shuffler(dh)

PMMA_atactic.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

Saver = PDB(PMMA_atactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_atactic_shuffle_03') # save, excluding dummies atoms


print('shuffle attempt 04')

PMMA_atactic.shuffler(dh)

PMMA_atactic.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

Saver = PDB(PMMA_atactic)
Saver.cleanup() # center in box
Saver.save(dummies=dummies,fname='PMMA_atactic_shuffle_04') # save, excluding dummies atoms

# even after four steps, this is still unable to solve the conformation

# If your initial conformation contains many overlapping monomers, I have found you are much less likely to find valid starting conformations
# There are several steps we could take to resolve this
# One approach would be to reduce the cutoff, which allows conformations with smaller interatomic distances

# In this example, using a cutoff of 0.8 A will allow dihedral_solver() to generate a starting starting conformation after every step

# Reducing the cutoff means some atoms are likely to be unrealistically close, but an energy minimzation may address this and result in structures that can be used in molecular dynamics

# Another approach is to vary the multiplicity of your dihedrals, to alter the search parameters through dihedral space
# In this case the alkane dihedrals have been permitted to explore a multiplicity of 6, but changing it to 3 (restricting the search space) or to 12 (increasing the search space) may facilitate a solution

# You could also try solving the alkanes first, and then the sidechains, or doing the reverse

# By varying your approach, you will eventually stumble upon a method that identifies valid starting conformations

# However, I have found it is quite reliable to start by generating a psuedolinear conformation, and then shuffling and solving that conformation
# An example of this process is given in build_PMMA_04-atactic-linearized
106 changes: 106 additions & 0 deletions polyconf_examples/build_PMMA_04-atactic-linearized.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env python

from polyconf.Monomer import Monomer
from polyconf.Polymer import Polymer
from polyconf.PDB import PDB
import random
random.seed(0)

print ('creating an atactic PMMA polymer using a linear extend()')

dummies="CMA CN CP CQ"

Monomer_D='MMAD_bonds.pdb'
Monomer_L='MMAL_bonds.pdb'

composition=25*[Monomer_D] + 25*[Monomer_L] # a list containing 50 monomers, 25 with each taticity
composition = random.sample(composition,len(composition)) # randomise the order of the monomers

PMMA_atactic_linear=Polymer(Monomer(composition[0])) # initialise with first monomer

for monomer in composition[1:]: # extend with the remain 49 monomers
PMMA_atactic_linear.extend( # extend with one monomer, aligned along this step's linearization vector
Monomer(monomer), # extend with this monomer
n=PMMA_atactic_linear.maxresid(), # extend existing residue i
nn=PMMA_atactic_linear.newresid(), # incoming monomer will have resid i+1
names=dict(Q='CA',P='CMA',S='C',R='CN',V1='CN',V2='C'), # C1_i+1 fit to CX_i,
joins=[('C','CA')],# new connection between N1_i and C1_i+1
linearise=True,
ortho=[1,0,0]
)

Saver = PDB(PMMA_atactic_linear)
Saver.cleanup()
Saver.save(dummies=dummies,fname='PMMA_atactic_linear-extend') # save, excluding dummies atoms

# when you look at this polymer, you can see the alkane backbone is extremely regular
# while this is not realistic, we can use it to generate reasonable conformations

alkanes=PMMA_atactic_linear.gen_pairlist(J='CA',K='C',first_resid=1,same_res=True,last_resid=50,mult=6)
sidechains=PMMA_atactic_linear.gen_pairlist(J='CA',K='CB',first_resid=1,same_res=True,last_resid=50,mult=6)

dh=[] #combine alkanes and sidechains into one list of dihedrals, so we can shuffle the alkane and dihedral in each monomer in order

for i in range(0,50):
dh += [alkanes[i]]
dh += [sidechains[i]]

print ('solving pseudolinear atactic PMMA ')

PMMA_atactic_linear.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

# unsurprisingly it was very easy to solve this pseudolinear conformation

Saver = PDB(PMMA_atactic_linear)
Saver.cleanup()
Saver.save(dummies=dummies,fname='PMMA_atactic_linear-solved') # save, excluding dummies atoms

print ('shuffle attempt 01')

PMMA_atactic_linear_01 = PMMA_atactic_linear.copy()

PMMA_atactic_linear_01.shuffler(dh)
PMMA_atactic_linear_01.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

Saver = PDB(PMMA_atactic_linear_01)
Saver.cleanup()
Saver.save(dummies=dummies,fname='PMMA_atactic_linear-shuffled_and_solved_01') # save, excluding dummies atoms

# this generated a valid conformation
# lets repeat the process three more times

print ('shuffle attempt 02')

PMMA_atactic_linear_02 = PMMA_atactic_linear.copy()

PMMA_atactic_linear_02.shuffler(dh)
PMMA_atactic_linear_02.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

Saver = PDB(PMMA_atactic_linear_02)
Saver.cleanup()
Saver.save(dummies=dummies,fname='PMMA_atactic_linear-shuffled_and_solved_02') # save, excluding dummies atoms


print ('shuffle attempt 03')

PMMA_atactic_linear_03 = PMMA_atactic_linear.copy()

PMMA_atactic_linear_03.shuffler(dh)
PMMA_atactic_linear_03.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

Saver = PDB(PMMA_atactic_linear_03)
Saver.cleanup()
Saver.save(dummies=dummies,fname='PMMA_atactic_linear-shuffled_and_solved_03') # save, excluding dummies atoms

print ('shuffle attempt 04')

PMMA_atactic_linear_04 = PMMA_atactic_linear.copy()

PMMA_atactic_linear_04.shuffler(dh)
PMMA_atactic_linear_04.dihedral_solver(dh,dummies=dummies,cutoff=1.1)

Saver = PDB(PMMA_atactic_linear_04)
Saver.cleanup()
Saver.save(dummies=dummies,fname='PMMA_atactic_linear-shuffled_and_solved_04') # save, excluding dummies atoms

# all four attempts were able to be solved, generating four possible starting conformations for energy minimzation
Loading