Skip to content

Commit d234dd8

Browse files
Merge branch 'master' into add-37
2 parents af66133 + 761fa1c commit d234dd8

File tree

22 files changed

+394
-101
lines changed

22 files changed

+394
-101
lines changed

.coveragerc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ exclude_lines =
1111
# Don't complain if non-runnable code isn't run:
1212
if 0:
1313
if __name__ == .__main__.:
14+
def __repr__
15+
except ImportError

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
'nglview',
2828
'oset',
2929
'parmed',
30+
'parmed.parameters',
3031
'parmed.periodic_table',
3132
'scipy',
3233
'scipy.spatial',

mbuild/box.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from warnings import warn
2+
13
import numpy as np
24

35

@@ -15,19 +17,25 @@ class Box(object):
1517
1618
"""
1719
def __init__(self, lengths=None, mins=None, maxs=None, angles=None):
18-
if lengths is not None:
19-
assert mins is None and maxs is None
20-
self._mins = np.array([0.0, 0.0, 0.0])
21-
self._maxs = np.array(lengths, dtype=np.float)
22-
self._lengths = np.array(lengths, dtype=np.float)
23-
elif maxs is not None:
24-
assert mins is not None and lengths is None
20+
if lengths is None:
21+
if mins is None or maxs is None:
22+
raise ValueError(
23+
"Either provide `lengths` or `mins` and `maxs`. "
24+
"You provided: "
25+
"lengths={} mins={} maxs={}".format(lengths, mins, maxs)
26+
)
2527
self._mins = np.array(mins, dtype=np.float)
2628
self._maxs = np.array(maxs, dtype=np.float)
2729
self._lengths = self.maxs - self.mins
2830
else:
29-
raise ValueError("Either provide `lengths` or `mins` and `maxs`."
30-
"You provided: lengths={} mins={} maxs={}".format(lengths, mins, maxs))
31+
warn(
32+
"Provided `lengths` and `mins` and/or `maxs`. Only `lengths` "
33+
"is being used. You provided: "
34+
"lengths={} mins={} maxs={}".format(lengths, mins, maxs)
35+
)
36+
self._mins = np.array([0.0, 0.0, 0.0])
37+
self._maxs = np.array(lengths, dtype=np.float)
38+
self._lengths = np.array(lengths, dtype=np.float)
3139
if angles is None:
3240
angles = np.array([90.0, 90.0, 90.0])
3341
elif isinstance(angles, (list, np.ndarray)):

mbuild/compound.py

Lines changed: 136 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,55 +1153,147 @@ def particles_in_range(
11531153
particle_array = np.array(list(self.particles()))
11541154
return particle_array[idxs]
11551155

1156-
def visualize(self, show_ports=False):
1157-
"""Visualize the Compound using nglview.
1156+
def visualize(self, show_ports=False,
1157+
backend='py3dmol', color_scheme={}): # pragma: no cover
1158+
"""Visualize the Compound using py3dmol (default) or nglview.
11581159
11591160
Allows for visualization of a Compound within a Jupyter Notebook.
11601161
11611162
Parameters
11621163
----------
11631164
show_ports : bool, optional, default=False
11641165
Visualize Ports in addition to Particles
1166+
backend : str, optional, default='py3dmol'
1167+
Specify the backend package to visualize compounds
1168+
Currently supported: py3dmol, nglview
1169+
color_scheme : dict, optional
1170+
Specify coloring for non-elemental particles
1171+
keys are strings of the particle names
1172+
values are strings of the colors
1173+
i.e. {'_CGBEAD': 'blue'}
11651174
11661175
"""
1167-
nglview = import_('nglview')
1168-
from mdtraj.geometry.sasa import _ATOMIC_RADII
1176+
viz_pkg = {'nglview': self._visualize_nglview,
1177+
'py3dmol': self._visualize_py3dmol}
11691178
if run_from_ipython():
1170-
remove_digits = lambda x: ''.join(i for i in x if not i.isdigit()
1171-
or i == '_')
1172-
for particle in self.particles():
1173-
particle.name = remove_digits(particle.name).upper()
1174-
if not particle.name:
1175-
particle.name = 'UNK'
1176-
tmp_dir = tempfile.mkdtemp()
1177-
self.save(os.path.join(tmp_dir, 'tmp.mol2'),
1178-
show_ports=show_ports,
1179-
overwrite=True)
1180-
widget = nglview.show_file(os.path.join(tmp_dir, 'tmp.mol2'))
1181-
widget.clear()
1182-
widget.add_ball_and_stick(cylinderOnly=True)
1183-
elements = set([particle.name for particle in self.particles()])
1184-
scale = 50.0
1185-
for element in elements:
1186-
try:
1187-
widget.add_ball_and_stick('_{}'.format(
1188-
element.upper()), aspect_ratio=_ATOMIC_RADII[element.title()]**1.5 * scale)
1189-
except KeyError:
1190-
ids = [str(i) for i, particle in enumerate(self.particles())
1191-
if particle.name == element]
1192-
widget.add_ball_and_stick(
1193-
'@{}'.format(
1194-
','.join(ids)),
1195-
aspect_ratio=0.17**1.5 * scale,
1196-
color='grey')
1197-
if show_ports:
1198-
widget.add_ball_and_stick('_VS',
1199-
aspect_ratio=1.0, color='#991f00')
1200-
return widget
1179+
if backend.lower() in viz_pkg:
1180+
return viz_pkg[backend.lower()](show_ports=show_ports,
1181+
color_scheme=color_scheme)
1182+
else:
1183+
raise RuntimeError("Unsupported visualization " +
1184+
"backend ({}). ".format(backend) +
1185+
"Currently supported backends include nglview and py3dmol")
1186+
12011187
else:
12021188
raise RuntimeError('Visualization is only supported in Jupyter '
12031189
'Notebooks.')
12041190

1191+
def _visualize_py3dmol(self, show_ports=False, color_scheme={}):
1192+
"""Visualize the Compound using py3Dmol.
1193+
1194+
Allows for visualization of a Compound within a Jupyter Notebook.
1195+
1196+
Parameters
1197+
----------
1198+
show_ports : bool, optional, default=False
1199+
Visualize Ports in addition to Particles
1200+
color_scheme : dict, optional
1201+
Specify coloring for non-elemental particles
1202+
keys are strings of the particle names
1203+
values are strings of the colors
1204+
i.e. {'_CGBEAD': 'blue'}
1205+
1206+
1207+
Returns
1208+
------
1209+
view : py3Dmol.view
1210+
1211+
"""
1212+
py3Dmol = import_('py3Dmol')
1213+
remove_digits = lambda x: ''.join(i for i in x if not i.isdigit()
1214+
or i == '_')
1215+
1216+
modified_color_scheme = {}
1217+
for name, color in color_scheme.items():
1218+
# Py3dmol does some element string conversions,
1219+
# first character is as-is, rest of the characters are lowercase
1220+
new_name = name[0] + name[1:].lower()
1221+
modified_color_scheme[new_name] = color
1222+
modified_color_scheme[name] = color
1223+
1224+
for particle in self.particles():
1225+
particle.name = remove_digits(particle.name).upper()
1226+
if not particle.name:
1227+
particle.name = 'UNK'
1228+
tmp_dir = tempfile.mkdtemp()
1229+
self.save(os.path.join(tmp_dir, 'tmp.mol2'),
1230+
show_ports=show_ports,
1231+
overwrite=True)
1232+
1233+
view = py3Dmol.view()
1234+
view.addModel(open(os.path.join(tmp_dir, 'tmp.mol2'), 'r').read(),
1235+
'mol2', keepH=True)
1236+
view.setStyle({'stick': {'radius': 0.2,
1237+
'color':'grey'},
1238+
'sphere': {'scale': 0.3,
1239+
'colorscheme':modified_color_scheme}})
1240+
if show_ports:
1241+
for p in self.particles(include_ports=True):
1242+
if p.port_particle:
1243+
view.addSphere({
1244+
'center': {'x':p.pos[0], 'y':p.pos[1], 'z':p.pos[2]},
1245+
'radius' :0.4,
1246+
'color': '0x991f00',
1247+
'alpha': 0.9})
1248+
view.zoomTo()
1249+
view.show()
1250+
1251+
return view
1252+
1253+
def _visualize_nglview(self, show_ports=False, color_scheme={}):
1254+
"""Visualize the Compound using nglview.
1255+
1256+
Allows for visualization of a Compound within a Jupyter Notebook.
1257+
1258+
Parameters
1259+
----------
1260+
show_ports : bool, optional, default=False
1261+
Visualize Ports in addition to Particles
1262+
"""
1263+
nglview = import_('nglview')
1264+
from mdtraj.geometry.sasa import _ATOMIC_RADII
1265+
remove_digits = lambda x: ''.join(i for i in x if not i.isdigit()
1266+
or i == '_')
1267+
for particle in self.particles():
1268+
particle.name = remove_digits(particle.name).upper()
1269+
if not particle.name:
1270+
particle.name = 'UNK'
1271+
tmp_dir = tempfile.mkdtemp()
1272+
self.save(os.path.join(tmp_dir, 'tmp.mol2'),
1273+
show_ports=show_ports,
1274+
overwrite=True)
1275+
widget = nglview.show_file(os.path.join(tmp_dir, 'tmp.mol2'))
1276+
widget.clear()
1277+
widget.add_ball_and_stick(cylinderOnly=True)
1278+
elements = set([particle.name for particle in self.particles()])
1279+
scale = 50.0
1280+
for element in elements:
1281+
try:
1282+
widget.add_ball_and_stick('_{}'.format(
1283+
element.upper()), aspect_ratio=_ATOMIC_RADII[element.title()]**1.5 * scale)
1284+
except KeyError:
1285+
ids = [str(i) for i, particle in enumerate(self.particles())
1286+
if particle.name == element]
1287+
widget.add_ball_and_stick(
1288+
'@{}'.format(
1289+
','.join(ids)),
1290+
aspect_ratio=0.17**1.5 * scale,
1291+
color='grey')
1292+
if show_ports:
1293+
widget.add_ball_and_stick('_VS',
1294+
aspect_ratio=1.0, color='#991f00')
1295+
return widget
1296+
12051297
def update_coordinates(self, filename, update_port_locations=True):
12061298
"""Update the coordinates of this Compound from a file.
12071299
@@ -2112,7 +2204,8 @@ def from_parmed(self, structure, coords_only=False):
21122204
else:
21132205
self.periodicity = np.array([0., 0., 0.])
21142206

2115-
def to_parmed(self, box=None, title='', residues=None, show_ports=False):
2207+
def to_parmed(self, box=None, title='', residues=None, show_ports=False,
2208+
infer_residues=False):
21162209
"""Create a ParmEd Structure from a Compound.
21172210
21182211
Parameters
@@ -2130,6 +2223,8 @@ def to_parmed(self, box=None, title='', residues=None, show_ports=False):
21302223
checking against Compound.name.
21312224
show_ports : boolean, optional, default=False
21322225
Include all port atoms when converting to a `Structure`.
2226+
infer_residues : bool, optional, default=False
2227+
Attempt to assign residues based on names of children.
21332228
21342229
Returns
21352230
-------
@@ -2146,6 +2241,9 @@ def to_parmed(self, box=None, title='', residues=None, show_ports=False):
21462241
atom_mapping = {} # For creating bonds below
21472242
guessed_elements = set()
21482243

2244+
if not residues and infer_residues:
2245+
residues = list(set([child.name for child in self.children]))
2246+
21492247
if isinstance(residues, string_types):
21502248
residues = [residues]
21512249
if isinstance(residues, (list, set)):
@@ -2288,7 +2386,7 @@ def _iterate_children(self, nodes, edges, names_only=False):
22882386
nodes, edges = child._iterate_children(nodes, edges, names_only=names_only)
22892387
return nodes, edges
22902388

2291-
def to_intermol(self, molecule_types=None):
2389+
def to_intermol(self, molecule_types=None): # pragma: no cover
22922390
"""Create an InterMol system from a Compound.
22932391
22942392
Parameters
@@ -2341,7 +2439,7 @@ def to_intermol(self, molecule_types=None):
23412439
return intermol_system
23422440

23432441
@staticmethod
2344-
def _add_intermol_molecule_type(intermol_system, parent):
2442+
def _add_intermol_molecule_type(intermol_system, parent): # pragma: no cover
23452443
"""Create a molecule type for the parent and add bonds. """
23462444
from intermol.moleculetype import MoleculeType
23472445
from intermol.forces.bond import Bond as InterMolBond

mbuild/examples/alkane/alkane.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
from mbuild.lib.moieties import CH2
55
from mbuild.lib.moieties import CH3
6-
from mbuild.lib.recipes import Polymer
76

87

98
class Alkane(mb.Compound):

mbuild/examples/alkane_monolayer/alkane_monolayer.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from mbuild.lib.surfaces import Betacristobalite
88
from mbuild.lib.atoms import H
9-
from mbuild.lib.recipes import Monolayer
109
from mbuild.examples.alkane_monolayer.alkylsilane import AlkylSilane
1110

1211

mbuild/examples/bilayer/bilayer.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import numpy as np
88

99
import mbuild as mb
10-
from mbuild import clone
1110

1211
class Bilayer(mb.Compound):
1312
"""Create a lipid bilayer and add solvent above and below.
@@ -125,23 +124,25 @@ def create_layer(self, lipid_indices=None, flip_orientation=False):
125124
current_type = self.lipids[n_type][0]
126125
for n_this_type, n_this_lipid_type in enumerate(range(n_of_lipid_type)):
127126
lipids_placed = n_type + n_this_type
128-
new_lipid = clone(current_type)
127+
new_lipid = mb.clone(current_type)
129128
random_index = lipid_indices[lipids_placed]
130129
position = self.pattern[random_index]
131130

132131
# Zero and space in z-direction
133132
particles = list(new_lipid.particles())
134133
ref_atom = self.ref_atoms[n_type]
135-
new_lipid.translate(-particles[ref_atom].pos + self.spacing)
134+
new_lipid.translate(new_lipid, -particles[ref_atom].pos + self.spacing)
136135

137136
# Move to point on pattern
138137
if flip_orientation == True:
138+
# TODO: Function for this?
139+
# E.g., rotate_around_x_keep_com(compound, bool(3))
139140
center = new_lipid.center
140141
center[2] = 0.0
141-
new_lipid.translate(-center)
142-
new_lipid.rotate(np.pi, [1, 0, 0])
143-
new_lipid.translate(center)
144-
new_lipid.translate(position)
142+
new_lipid.translate(new_lipid, -center)
143+
mb.rotate_around_x(new_lipid, np.pi)
144+
new_lipid.translate(new_lipid, center)
145+
new_lipid.translate(new_lipid, position)
145146
layer.add(new_lipid)
146147
return layer, lipid_indices
147148

@@ -205,4 +206,4 @@ def lipid_box(self):
205206
0.5*np.sqrt(self.apl)])
206207
return self._lipid_box
207208

208-
# -- ==bilayer== --
209+
# -- ==bilayer== --

mbuild/examples/lennard_jones/monolj.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
# -- ==monolj== --
55
import mbuild as mb
6-
from mbuild import clone
76

87

98
class MonoLJ(mb.Compound):
@@ -15,7 +14,7 @@ def __init__(self):
1514
pattern.scale(5)
1615

1716
for pos in pattern:
18-
lj_particle = clone(lj_proto)
17+
lj_particle = mb.clone(lj_proto)
1918
lj_particle.translate(pos)
2019
self.add(lj_particle)
2120

mbuild/examples/pmpc/brush.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from mbuild.lib.moieties import Silane
66
from mbuild.lib.moieties import CH3
7-
from mbuild.lib.recipes import Polymer
87
from mbuild.examples.pmpc.mpc import MPC
98
from mbuild.examples.pmpc.initiator import Initiator
109

mbuild/examples/pmpc/pmpc_brush_layer.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import mbuild as mb
1010
from mbuild.lib.atoms import H
1111
from mbuild.lib.surfaces import Betacristobalite
12-
from mbuild.lib.recipes import Monolayer
1312
from mbuild.examples.pmpc.brush import Brush
1413

1514

0 commit comments

Comments
 (0)