-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add export to RDKIT to allow for chemdraw style visualization. #1137
Changes from 12 commits
cf759f1
457b6ad
2f35d1a
0096908
5302b09
ec1a58f
332205b
fd1ed75
127be7d
fa7046d
7d75821
acba7c3
0e8cbe7
3adb518
457ae50
a4b3921
fc023c1
510f27d
2ef402c
c580b00
fa6135f
4b14683
0dd8fa6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1189,9 +1189,16 @@ | |
for b1, b2 in self.root.bond_graph.edges(self): | ||
yield b2 | ||
|
||
def bonds(self): | ||
def bonds(self, return_bond_order=False): | ||
"""Return all bonds in the Compound and sub-Compounds. | ||
|
||
Parameters | ||
---------- | ||
return_bond_order : bool, optional, default=False | ||
Return the bond order of the bond as the 3rd argument in the tuple. | ||
bond order is returned as a dictionary with 'bo' as the key. | ||
If bond order is not set, the value will be set to 'default'. | ||
|
||
Yields | ||
------ | ||
tuple of mb.Compound | ||
|
@@ -1204,9 +1211,11 @@ | |
""" | ||
if self.root.bond_graph: | ||
if self.root == self: | ||
return self.root.bond_graph.edges() | ||
return self.root.bond_graph.edges(data=return_bond_order) | ||
else: | ||
return self.root.bond_graph.subgraph(self.particles()).edges() | ||
return self.root.bond_graph.subgraph(self.particles()).edges( | ||
data=return_bond_order | ||
) | ||
else: | ||
return iter(()) | ||
|
||
|
@@ -1246,18 +1255,23 @@ | |
) | ||
return sum(1 for _ in self.bonds()) | ||
|
||
def add_bond(self, particle_pair): | ||
def add_bond(self, particle_pair, bond_order=None): | ||
"""Add a bond between two Particles. | ||
|
||
Parameters | ||
---------- | ||
particle_pair : indexable object, length=2, dtype=mb.Compound | ||
The pair of Particles to add a bond between | ||
bond_order : float, optional, default=None | ||
Bond order of the bond. | ||
""" | ||
if self.root.bond_graph is None: | ||
self.root.bond_graph = BondGraph() | ||
|
||
self.root.bond_graph.add_edge(particle_pair[0], particle_pair[1]) | ||
if bond_order is None: | ||
bond_order = "default" | ||
self.root.bond_graph.add_edge( | ||
particle_pair[0], particle_pair[1], bo=bond_order | ||
) | ||
|
||
def generate_bonds(self, name_a, name_b, dmin, dmax): | ||
"""Add Bonds between all pairs of types a/b within [dmin, dmax]. | ||
|
@@ -2654,7 +2668,7 @@ | |
particle._element = element_from_symbol(particle.name) | ||
except ElementError: | ||
try: | ||
element_from_name(particle.name) | ||
particle._element = element_from_name(particle.name) | ||
except ElementError: | ||
raise MBuildError( | ||
"No element assigned to {}; element could not be" | ||
|
@@ -3228,6 +3242,58 @@ | |
infer_hierarchy=infer_hierarchy, | ||
) | ||
|
||
def to_rdkit(self): | ||
chrisjonesBSU marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rdkit = import_("rdkit") | ||
|
||
from rdkit import Chem | ||
from rdkit.Chem import AllChem | ||
|
||
for particle in self.particles(): | ||
if particle.element is None: | ||
try: | ||
particle._element = element_from_symbol(particle.name) | ||
except ElementError: | ||
try: | ||
particle._element = element_from_name(particle.name) | ||
except ElementError: | ||
raise MBuildError( | ||
"No element assigned to {}; element could not be" | ||
"inferred from particle name {}. Cannot perform" | ||
"an energy minimization.".format( | ||
particle, particle.name | ||
chrisjonesBSU marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
) | ||
|
||
temp_mol = Chem.RWMol() | ||
p_dict = {particle: i for i, particle in enumerate(self.particles())} | ||
|
||
bo_dict = { | ||
1.0: Chem.BondType.SINGLE, | ||
2.0: Chem.BondType.DOUBLE, | ||
3.0: Chem.BondType.TRIPLE, | ||
1.5: Chem.BondType.AROMATIC, | ||
0.0: Chem.BondType.UNSPECIFIED, | ||
"default": Chem.BondType.SINGLE, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should raise a single warning here that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, it's not clear to me what the use of having |
||
} | ||
|
||
for particle in self.particles(): | ||
temp_atom = Chem.Atom(particle.element.atomic_number) | ||
|
||
# this next line is necessary to prevent rdkit from adding hydrogens | ||
# this will also set the label to be the lement with particle index | ||
chrisjonesBSU marked this conversation as resolved.
Show resolved
Hide resolved
|
||
temp_atom.SetProp( | ||
"atomLabel", f"{temp_atom.GetSymbol()}:{p_dict[particle]}" | ||
) | ||
|
||
temp_mol.AddAtom(temp_atom) | ||
|
||
for bond in self.bonds(return_bond_order=True): | ||
bond_indices = (p_dict[bond[0]], p_dict[bond[1]]) | ||
temp_mol.AddBond(*bond_indices) | ||
rdkit_bond = temp_mol.GetBondBetweenAtoms(*bond_indices) | ||
rdkit_bond.SetBondType(bo_dict[bond[2]["bo"]]) | ||
|
||
return temp_mol | ||
|
||
def to_parmed( | ||
self, | ||
box=None, | ||
|
@@ -3552,9 +3618,12 @@ | |
newone.bond_graph = BondGraph() | ||
for particle in self.particles(): | ||
newone.bond_graph.add_node(clone_of[particle]) | ||
for c1, c2 in self.bonds(): | ||
for c1, c2, data in self.bonds(return_bond_order=True): | ||
try: | ||
newone.add_bond((clone_of[c1], clone_of[c2])) | ||
# bond order is added to the data dictionary as 'bo' | ||
newone.add_bond( | ||
(clone_of[c1], clone_of[c2]), bond_order=data["bo"] | ||
) | ||
except KeyError: | ||
raise MBuildError( | ||
"Cloning failed. Compound contains bonds to " | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we need a type check here to make sure the bond_order provided is of the right type (not bogus string)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think hard checking these would be useful. The options should be:
"default", "single", "double", "triple", "aromatic", "unspecified". It seems the current options are:
"default", 1.0, 2.0, 3.0, 1.5, 0.0.
I think being cleaner with using all strings would be nice, since we wouldn't have to deal with odd behavior for floats vs ints.
Also, these options should be all listed in the doc strings to_rdkit(), regardless of what they are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a check for
bond_order
using the types you suggested.