From 5ba5bddb82bc3a44c24ed0330aae51bc952fee37 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Thu, 20 Apr 2023 23:08:13 -0700 Subject: [PATCH 01/25] updated add routine to compose bond graphs of a list together before composing with main compound --- mbuild/compound.py | 59 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index e39c03ac8..c2e4139de 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -790,6 +790,13 @@ def _reorder_rigid_ids(self): if self.rigid_id > missing_rigid_id: self.rigid_id -= 1 + def _flatten_list(self, c_list): + if isinstance(c_list, list): + for c in c_list: + if isinstance(c, list): + yield from self._flatten_list(c) + else: + yield c def add( self, new_child, @@ -811,8 +818,8 @@ def add( ---------- new_child : mb.Compound or list-like of mb.Compound The object(s) to be added to this Compound. - label : str, optional, default None - A descriptive string for the part. + label : str, or list-like of str, optional, default None + A descriptive string for the part; if a list, must be the same length/shape as new_child. containment : bool, optional, default=True Add the part to self.children. replace : bool, optional, default=True @@ -829,13 +836,48 @@ def add( to add Compounds to an existing rigid body. """ # Support batch add via lists, tuples and sets. + # If iterable, we will first compose all the bondgraphs of individual + # Compounds in the list for efficiency from mbuild.port import Port if isinstance(new_child, Iterable) and not isinstance(new_child, str): - for child in new_child: - self.add(child, reset_rigid_ids=reset_rigid_ids) - return + compound_list = [c for c in self._flatten_list(new_child)] + if label is not None and isinstance(label, Iterable): + label_list = [c for c in self._flatten_list(label)] + if len(label_list) != len(compound_list): + raise ValueError( + "The list-like object for label must be the same length as" + "the list-like object of child Compounds. " + f"label total length {len(label_list)}, new_child '{len(new_child)}'." + ) + temp_bond_graphs = [] + for child in compound_list: + # create a list of bond graphs of the children to add + if containment: + if child.bond_graph is not None and not isinstance(self, Port): + temp_bond_graphs.append(child.bond_graph) + # compose children bond_graphs; make sure we actually have graphs to compose + if len(temp_bond_graphs) != 0: + children_bond_graph = nx.compose_all(temp_bond_graphs) + + if len(temp_bond_graphs) != 0 and not isinstance(self, Port): + # If anything is added at self level, it is no longer a particle + # search for self in self.root.bond_graph and remove self + if self.root.bond_graph.has_node(self): + self.root.bond_graph.remove_node(self) + # compose the bond graph of all the children with the root + self.root.bond_graph = nx.compose( + self.root.bond_graph,children_bond_graph + ) + for i, child in enumerate(compound_list): + child.bond_graph = None + if label is not None: + self.add(child, label=label_list[i], reset_rigid_ids=reset_rigid_ids) + else: + self.add(child, reset_rigid_ids=reset_rigid_ids) + return + if not isinstance(new_child, Compound): raise ValueError( "Only objects that inherit from mbuild.Compound can be added " @@ -861,7 +903,8 @@ def add( self.children = OrderedSet() if self.labels is None: self.labels = OrderedDict() - + + if containment: if new_child.parent is not None: raise MBuildError( @@ -871,7 +914,7 @@ def add( ) self.children.add(new_child) new_child.parent = self - + if new_child.bond_graph is not None and not isinstance(self, Port): # If anything is added at self level, it is no longer a particle # search for self in self.root.bond_graph and remove self @@ -883,7 +926,7 @@ def add( ) new_child.bond_graph = None - + # Add new_part to labels. Does not currently support batch add. if label is None: label = "{0}[$]".format(new_child.__class__.__name__) From 3dfbfa514b377e5350be7b0e203f479dacc1ef74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 06:24:31 +0000 Subject: [PATCH 02/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/compound.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index c2e4139de..3812c9eb0 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -797,6 +797,7 @@ def _flatten_list(self, c_list): yield from self._flatten_list(c) else: yield c + def add( self, new_child, @@ -844,40 +845,46 @@ def add( compound_list = [c for c in self._flatten_list(new_child)] if label is not None and isinstance(label, Iterable): label_list = [c for c in self._flatten_list(label)] - if len(label_list) != len(compound_list): + if len(label_list) != len(compound_list): raise ValueError( - "The list-like object for label must be the same length as" - "the list-like object of child Compounds. " - f"label total length {len(label_list)}, new_child '{len(new_child)}'." + "The list-like object for label must be the same length as" + "the list-like object of child Compounds. " + f"label total length {len(label_list)}, new_child '{len(new_child)}'." ) temp_bond_graphs = [] for child in compound_list: # create a list of bond graphs of the children to add if containment: - if child.bond_graph is not None and not isinstance(self, Port): + if child.bond_graph is not None and not isinstance( + self, Port + ): temp_bond_graphs.append(child.bond_graph) # compose children bond_graphs; make sure we actually have graphs to compose if len(temp_bond_graphs) != 0: children_bond_graph = nx.compose_all(temp_bond_graphs) - + if len(temp_bond_graphs) != 0 and not isinstance(self, Port): # If anything is added at self level, it is no longer a particle # search for self in self.root.bond_graph and remove self if self.root.bond_graph.has_node(self): self.root.bond_graph.remove_node(self) # compose the bond graph of all the children with the root - self.root.bond_graph = nx.compose( - self.root.bond_graph,children_bond_graph - ) + self.root.bond_graph = nx.compose( + self.root.bond_graph, children_bond_graph + ) for i, child in enumerate(compound_list): child.bond_graph = None if label is not None: - self.add(child, label=label_list[i], reset_rigid_ids=reset_rigid_ids) + self.add( + child, + label=label_list[i], + reset_rigid_ids=reset_rigid_ids, + ) else: self.add(child, reset_rigid_ids=reset_rigid_ids) return - + if not isinstance(new_child, Compound): raise ValueError( "Only objects that inherit from mbuild.Compound can be added " @@ -903,8 +910,7 @@ def add( self.children = OrderedSet() if self.labels is None: self.labels = OrderedDict() - - + if containment: if new_child.parent is not None: raise MBuildError( @@ -914,7 +920,7 @@ def add( ) self.children.add(new_child) new_child.parent = self - + if new_child.bond_graph is not None and not isinstance(self, Port): # If anything is added at self level, it is no longer a particle # search for self in self.root.bond_graph and remove self @@ -926,7 +932,7 @@ def add( ) new_child.bond_graph = None - + # Add new_part to labels. Does not currently support batch add. if label is None: label = "{0}[$]".format(new_child.__class__.__name__) From 74085c76ff1c38214b038c2016127f4a8fed9675 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Fri, 21 Apr 2023 08:41:37 -0700 Subject: [PATCH 03/25] change flattening routine for list, as it was causing a failure in the add remove bond test --- mbuild/compound.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index c2e4139de..7c2982920 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -789,7 +789,7 @@ def _reorder_rigid_ids(self): if self.rigid_id: if self.rigid_id > missing_rigid_id: self.rigid_id -= 1 - + # helper function to flattening a list that may be nested, in particular used for a list of labels def _flatten_list(self, c_list): if isinstance(c_list, list): for c in c_list: @@ -797,6 +797,14 @@ def _flatten_list(self, c_list): yield from self._flatten_list(c) else: yield c + # helper function to flatten a list of Compounds that may be nested + def _flatten_compound_list(self, c_list): + if isinstance(c_list, Iterable): + for c in c_list: + if isinstance(c, Iterable): + yield from self._flatten_list(c) + else: + yield c def add( self, new_child, @@ -841,8 +849,8 @@ def add( from mbuild.port import Port if isinstance(new_child, Iterable) and not isinstance(new_child, str): - compound_list = [c for c in self._flatten_list(new_child)] - if label is not None and isinstance(label, Iterable): + compound_list = [c for c in self._flatten_compound_list(new_child)] + if label is not None and isinstance(label, list): label_list = [c for c in self._flatten_list(label)] if len(label_list) != len(compound_list): raise ValueError( @@ -860,7 +868,7 @@ def add( if len(temp_bond_graphs) != 0: children_bond_graph = nx.compose_all(temp_bond_graphs) - if len(temp_bond_graphs) != 0 and not isinstance(self, Port): + if len(temp_bond_graphs) != 0 and not isinstance(self, Port) and children_bond_graph is not None: # If anything is added at self level, it is no longer a particle # search for self in self.root.bond_graph and remove self if self.root.bond_graph.has_node(self): From 1fc6cc832439c93ad9b24c63fc11eeabfc5377ce Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 15:42:32 +0000 Subject: [PATCH 04/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/compound.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 93e6b4dee..b570aa454 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -871,7 +871,7 @@ def add( if len(temp_bond_graphs) != 0: children_bond_graph = nx.compose_all(temp_bond_graphs) <<<<<<< HEAD - + if len(temp_bond_graphs) != 0 and not isinstance(self, Port) and children_bond_graph is not None: ======= From 253092301be1acae02e6bd01419f27059f095111 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Fri, 21 Apr 2023 12:44:20 -0700 Subject: [PATCH 05/25] some how left a conflict statement in...not sure why it is causing a conflict to begin with --- mbuild/compound.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 93e6b4dee..c91499fc5 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -870,13 +870,8 @@ def add( # compose children bond_graphs; make sure we actually have graphs to compose if len(temp_bond_graphs) != 0: children_bond_graph = nx.compose_all(temp_bond_graphs) -<<<<<<< HEAD if len(temp_bond_graphs) != 0 and not isinstance(self, Port) and children_bond_graph is not None: -======= - - if len(temp_bond_graphs) != 0 and not isinstance(self, Port): ->>>>>>> 3dfbfa514b377e5350be7b0e203f479dacc1ef74 # If anything is added at self level, it is no longer a particle # search for self in self.root.bond_graph and remove self if self.root.bond_graph.has_node(self): From c85ec83593181fce0aaf6fe23ff8e79b06036bf5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 19:45:32 +0000 Subject: [PATCH 06/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/compound.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index e2f871990..802384fe8 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -789,6 +789,7 @@ def _reorder_rigid_ids(self): if self.rigid_id: if self.rigid_id > missing_rigid_id: self.rigid_id -= 1 + # helper function to flattening a list that may be nested, in particular used for a list of labels def _flatten_list(self, c_list): if isinstance(c_list, list): @@ -797,6 +798,7 @@ def _flatten_list(self, c_list): yield from self._flatten_list(c) else: yield c + # helper function to flatten a list of Compounds that may be nested def _flatten_compound_list(self, c_list): if isinstance(c_list, Iterable): @@ -871,7 +873,11 @@ def add( if len(temp_bond_graphs) != 0: children_bond_graph = nx.compose_all(temp_bond_graphs) - if len(temp_bond_graphs) != 0 and not isinstance(self, Port) and children_bond_graph is not None: + if ( + len(temp_bond_graphs) != 0 + and not isinstance(self, Port) + and children_bond_graph is not None + ): # If anything is added at self level, it is no longer a particle # search for self in self.root.bond_graph and remove self if self.root.bond_graph.has_node(self): From c808e400727314cf38e64e8528872c8a21989f54 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Fri, 21 Apr 2023 13:03:53 -0700 Subject: [PATCH 07/25] added in sped up routine for loading mdtraj trajectories --- mbuild/conversion.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/mbuild/conversion.py b/mbuild/conversion.py index e2341b349..0325fea47 100644 --- a/mbuild/conversion.py +++ b/mbuild/conversion.py @@ -650,19 +650,29 @@ def from_trajectory( compound = mb.Compound() atom_mapping = dict() + # temporary lists to speed up add to the compound + chains_list = [] + chains_list_label = [] + for chain in traj.topology.chains: if traj.topology.n_chains > 1: chain_compound = mb.Compound() - compound.add(chain_compound, "chain[$]") + chains_list.append(chain_compound) + chains_list_label.append("chain[$]") else: chain_compound = compound + + res_list = [] for res in chain.residues: if infer_hierarchy: res_compound = mb.Compound(name=res.name) - chain_compound.add(res_compound) parent_cmpd = res_compound + res_list.append(res_compound) else: parent_cmpd = chain_compound + + atom_list = [] + atom_label_list = [] for atom in res.atoms: try: element = element_from_atomic_number( @@ -675,9 +685,17 @@ def from_trajectory( pos=traj.xyz[frame, atom.index], element=element, ) - parent_cmpd.add(new_atom, label="{0}[$]".format(atom.name)) + atom_list.append(new_atom) + atom_label_list.append("{0}[$]".format(atom.name)) atom_mapping[atom] = new_atom - + + parent_cmpd.add(atom_list, label=atom_label_list) + + if infer_hierarchy: + chain_compound.add(res_list) + if traj.topology.n_chains > 1: + compound.add(chains_list, label=chains_list_label) + for mdtraj_atom1, mdtraj_atom2 in traj.topology.bonds: atom1 = atom_mapping[mdtraj_atom1] atom2 = atom_mapping[mdtraj_atom2] From d997f58d1f897096828a5f3eb27b262e8977f4b0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 20:04:15 +0000 Subject: [PATCH 08/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/conversion.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mbuild/conversion.py b/mbuild/conversion.py index 0325fea47..93978091a 100644 --- a/mbuild/conversion.py +++ b/mbuild/conversion.py @@ -653,7 +653,7 @@ def from_trajectory( # temporary lists to speed up add to the compound chains_list = [] chains_list_label = [] - + for chain in traj.topology.chains: if traj.topology.n_chains > 1: chain_compound = mb.Compound() @@ -661,7 +661,7 @@ def from_trajectory( chains_list_label.append("chain[$]") else: chain_compound = compound - + res_list = [] for res in chain.residues: if infer_hierarchy: @@ -670,7 +670,7 @@ def from_trajectory( res_list.append(res_compound) else: parent_cmpd = chain_compound - + atom_list = [] atom_label_list = [] for atom in res.atoms: @@ -688,14 +688,14 @@ def from_trajectory( atom_list.append(new_atom) atom_label_list.append("{0}[$]".format(atom.name)) atom_mapping[atom] = new_atom - + parent_cmpd.add(atom_list, label=atom_label_list) - + if infer_hierarchy: - chain_compound.add(res_list) + chain_compound.add(res_list) if traj.topology.n_chains > 1: compound.add(chains_list, label=chains_list_label) - + for mdtraj_atom1, mdtraj_atom2 in traj.topology.bonds: atom1 = atom_mapping[mdtraj_atom1] atom2 = atom_mapping[mdtraj_atom2] From c2a1ca9a6f9c419a647a72e326546022e6a574b1 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Fri, 21 Apr 2023 18:27:32 -0700 Subject: [PATCH 09/25] added in sped up routine for loading parmed trajectories --- mbuild/conversion.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/mbuild/conversion.py b/mbuild/conversion.py index 93978091a..a04f18491 100644 --- a/mbuild/conversion.py +++ b/mbuild/conversion.py @@ -554,19 +554,25 @@ def from_parmed( chains[residue.chain].append(residue) # Build up compound + chain_list = [] for chain, residues in chains.items(): if len(chain) > 1: chain_compound = mb.Compound() - compound.add(chain_compound, chain_id) + #compound.add(chain_compound, chain_id) + chain_list.append(chain_compound) else: chain_compound = compound + res_list = [] for residue in residues: if infer_hierarchy: residue_compound = mb.Compound(name=residue.name) - chain_compound.add(residue_compound) + #chain_compound.add(residue_compound) parent_compound = residue_compound + res_list.append(residue_compound) else: parent_compound = chain_compound + atom_list = [] + atom_label_list = [] for atom in residue.atoms: # Angstrom to nm pos = np.array([atom.xx, atom.xy, atom.xz]) / 10 @@ -577,9 +583,16 @@ def from_parmed( new_atom = mb.Particle( name=str(atom.name), pos=pos, element=element ) - parent_compound.add(new_atom, label="{0}[$]".format(atom.name)) + atom_list.append(new_atom) + atom_label_list.append("{0}[$]".format(atom.name)) + #parent_compound.add(new_atom, label="{0}[$]".format(atom.name)) atom_mapping[atom] = new_atom - + parent_compound.add(atom_list, label=atom_label_list) + if infer_hierarchy: + chain_compound.add(res_list) + if len(chain) > 1: + compound.add(chain_list) + # Infer bonds information for bond in structure.bonds: atom1 = atom_mapping[bond.atom1] @@ -864,13 +877,16 @@ def from_rdkit(rdkit_mol, compound=None, coords_only=False, smiles_seed=0): else: comp = compound + part_list = [] for i, atom in enumerate(mymol.GetAtoms()): part = mb.Particle( name=atom.GetSymbol(), element=element_from_atomic_number(atom.GetAtomicNum()), pos=xyz[i], ) - comp.add(part) + part_list.append(part) + + comp.add(part_list) for bond in mymol.GetBonds(): comp.add_bond( From 84ead2abc55e646ea9451fc21d0a18a0ffe7b77c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Apr 2023 01:27:56 +0000 Subject: [PATCH 10/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/conversion.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mbuild/conversion.py b/mbuild/conversion.py index a04f18491..bc1ead3db 100644 --- a/mbuild/conversion.py +++ b/mbuild/conversion.py @@ -558,7 +558,7 @@ def from_parmed( for chain, residues in chains.items(): if len(chain) > 1: chain_compound = mb.Compound() - #compound.add(chain_compound, chain_id) + # compound.add(chain_compound, chain_id) chain_list.append(chain_compound) else: chain_compound = compound @@ -566,7 +566,7 @@ def from_parmed( for residue in residues: if infer_hierarchy: residue_compound = mb.Compound(name=residue.name) - #chain_compound.add(residue_compound) + # chain_compound.add(residue_compound) parent_compound = residue_compound res_list.append(residue_compound) else: @@ -585,14 +585,14 @@ def from_parmed( ) atom_list.append(new_atom) atom_label_list.append("{0}[$]".format(atom.name)) - #parent_compound.add(new_atom, label="{0}[$]".format(atom.name)) + # parent_compound.add(new_atom, label="{0}[$]".format(atom.name)) atom_mapping[atom] = new_atom parent_compound.add(atom_list, label=atom_label_list) if infer_hierarchy: chain_compound.add(res_list) if len(chain) > 1: compound.add(chain_list) - + # Infer bonds information for bond in structure.bonds: atom1 = atom_mapping[bond.atom1] @@ -885,7 +885,7 @@ def from_rdkit(rdkit_mol, compound=None, coords_only=False, smiles_seed=0): pos=xyz[i], ) part_list.append(part) - + comp.add(part_list) for bond in mymol.GetBonds(): From 3633c8c25d76eb5cc3854034347a2157dffc1022 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Fri, 21 Apr 2023 20:14:45 -0700 Subject: [PATCH 11/25] added new tests --- mbuild/tests/test_compound.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index d82a88714..dbdf47dcd 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -621,6 +621,27 @@ def test_add_label_exists(self, ethane, h2o): with pytest.raises(MBuildError): ethane.add(mb.clone(h2o), label="water") + def test_add_by_list(self, h2o): + temp_comp = mb.Compound() + comp_list = [] + label_list = [] + for j in range(0,5): + comp_list.append(mb.clone(h2o)) + label_list.append("water[$]") + temp_comp.add(comp_list, label=label_list) + a = [k for k,v in temp_comp.labels.items()] + assert a == ['water', 'water[0]', 'water[1]', 'water[2]', 'water[3]', 'water[4]'] + + temp_comp = mb.Compound() + comp_list = [] + label_list = ['water'] + for j in range(0,5): + comp_list.append(mb.clone(h2o)) + + with pytest.raises(ValueError): + temp_comp.add(comp_list, label=label_list) + + def test_set_pos(self, ethane): with pytest.raises(MBuildError): ethane.pos = [0, 0, 0] From 8fe5bae10fffc7cc0ab8dc6db506835bfbda2e15 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Apr 2023 03:15:10 +0000 Subject: [PATCH 12/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/tests/test_compound.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index dbdf47dcd..bf04278a6 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -625,23 +625,29 @@ def test_add_by_list(self, h2o): temp_comp = mb.Compound() comp_list = [] label_list = [] - for j in range(0,5): + for j in range(0, 5): comp_list.append(mb.clone(h2o)) label_list.append("water[$]") temp_comp.add(comp_list, label=label_list) - a = [k for k,v in temp_comp.labels.items()] - assert a == ['water', 'water[0]', 'water[1]', 'water[2]', 'water[3]', 'water[4]'] + a = [k for k, v in temp_comp.labels.items()] + assert a == [ + "water", + "water[0]", + "water[1]", + "water[2]", + "water[3]", + "water[4]", + ] temp_comp = mb.Compound() comp_list = [] - label_list = ['water'] - for j in range(0,5): + label_list = ["water"] + for j in range(0, 5): comp_list.append(mb.clone(h2o)) - + with pytest.raises(ValueError): temp_comp.add(comp_list, label=label_list) - - + def test_set_pos(self, ethane): with pytest.raises(MBuildError): ethane.pos = [0, 0, 0] From a80c56839ec4dc89286d2e5b364b4d298a2fda70 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Sat, 22 Apr 2023 00:27:50 -0700 Subject: [PATCH 13/25] added tests for helper functions --- mbuild/tests/test_compound.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index bf04278a6..355acf0bb 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -621,6 +621,22 @@ def test_add_label_exists(self, ethane, h2o): with pytest.raises(MBuildError): ethane.add(mb.clone(h2o), label="water") + def test_list_flatten(self, h2o): + out = [a for a in h2o._flatten_list(['one', 'two', ['three', 'four']])] + assert out == ['one', 'two', 'three', 'four'] + + one = mb.clone(h2o) + one.name = 'one' + two = mb.clone(h2o) + two.name = 'two' + three = mb.clone(h2o) + three.name = 'three' + four = mb.clone(h2o) + four.name = 'four' + out = [a.name for a in h2o._flatten_compound_list([one, two, [three, four]] )] + + assert out == ['one', 'two', 'three', 'four'] + def test_add_by_list(self, h2o): temp_comp = mb.Compound() comp_list = [] From 5f3d2418de7915641accb73b8d8d90d8ef95314d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Apr 2023 07:28:13 +0000 Subject: [PATCH 14/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/tests/test_compound.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index 355acf0bb..e4fe87704 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -622,21 +622,24 @@ def test_add_label_exists(self, ethane, h2o): ethane.add(mb.clone(h2o), label="water") def test_list_flatten(self, h2o): - out = [a for a in h2o._flatten_list(['one', 'two', ['three', 'four']])] - assert out == ['one', 'two', 'three', 'four'] - + out = [a for a in h2o._flatten_list(["one", "two", ["three", "four"]])] + assert out == ["one", "two", "three", "four"] + one = mb.clone(h2o) - one.name = 'one' + one.name = "one" two = mb.clone(h2o) - two.name = 'two' + two.name = "two" three = mb.clone(h2o) - three.name = 'three' + three.name = "three" four = mb.clone(h2o) - four.name = 'four' - out = [a.name for a in h2o._flatten_compound_list([one, two, [three, four]] )] - - assert out == ['one', 'two', 'three', 'four'] - + four.name = "four" + out = [ + a.name + for a in h2o._flatten_compound_list([one, two, [three, four]]) + ] + + assert out == ["one", "two", "three", "four"] + def test_add_by_list(self, h2o): temp_comp = mb.Compound() comp_list = [] From 161c82a9aeba696d448a6ba21cf040bfbf56e796 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Tue, 25 Apr 2023 12:07:21 -0700 Subject: [PATCH 15/25] added condense function for Compounds --- mbuild/compound.py | 57 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 802384fe8..f53db3194 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -28,6 +28,8 @@ from mbuild.utils.io import import_, run_from_ipython from mbuild.utils.jsutils import overwrite_nglview_default from mbuild.utils.orderedset import OrderedSet +from boltons.setutils import IndexedSet + def clone(existing_compound, clone_of=None, root_container=None): @@ -1962,6 +1964,59 @@ def _visualize_nglview(self, show_ports=False, color_scheme={}): overwrite_nglview_default(widget) return widget + def condense(self, inplace=True): + """Condense the hierarchical structure of the Compound to the level of molecules. + + Modify the mBuild Compound to become a Compound with 3 distinct levels in the hierarchy. + The top level container (self), contains molecules (i.e., connected Compounds) and the + third level represents Particles (i.e., Compounds with no children). + If the system contains a Particle(s) without any connections to other Compounds, it will + appear in the 2nd level (with the top level self as a parent). + + Parameter + --------- + inplace : bool, optional, default=True + Option to perform the condense operation inplace or return a copy + + Return + ------ + self : mb.Compound or None + return a condensed Compound if inplace is False. + """ + # temporary list of components + comp_list = [] + connected_subgraph = self.root.bond_graph.connected_components() + + for molecule in connected_subgraph: + if len(molecule) == 1: + ancestors = [molecule[0]] + else: + ancestors = IndexedSet(molecule[0].ancestors()) + for particle in molecule[1:]: + # This works because the way in which particle.ancestors is + # traversed, the lower level will be in the front. + # The intersection will be left at the end, + # ancestor of the first particle is used as reference. + # Hence, this called will return the lowest-level Compound + # that is a molecule + ancestors = ancestors.intersection( + IndexedSet(particle.ancestors()) + ) + + + """Parse molecule information""" + molecule_tag = ancestors[0] + comp_list.append(clone(molecule_tag)) + if inplace: + for child in [self.children]: + # Need to handle the case when child is a port + self.remove(child) + self.add(comp_list) + else: + new_compound = Compound() + new_compound.add(comp_list) + return new_compound + def flatten(self, inplace=True): """Flatten the hierarchical structure of the Compound. @@ -1976,7 +2031,7 @@ def flatten(self, inplace=True): Return ------ self : mb.Compound or None - return a flatten Compound if inplace is False. + return a flattened Compound if inplace is False. """ ports_list = list(self.all_ports()) children_list = list(self.children) From e5a04bf720fdad2553641ed39b5bafd1df31f183 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 19:10:00 +0000 Subject: [PATCH 16/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/compound.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index f53db3194..7e2cbb28d 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -13,6 +13,7 @@ import ele import networkx as nx import numpy as np +from boltons.setutils import IndexedSet from ele.element import Element, element_from_name, element_from_symbol from ele.exceptions import ElementError from treelib import Tree @@ -28,8 +29,6 @@ from mbuild.utils.io import import_, run_from_ipython from mbuild.utils.jsutils import overwrite_nglview_default from mbuild.utils.orderedset import OrderedSet -from boltons.setutils import IndexedSet - def clone(existing_compound, clone_of=None, root_container=None): @@ -2003,7 +2002,6 @@ def condense(self, inplace=True): IndexedSet(particle.ancestors()) ) - """Parse molecule information""" molecule_tag = ancestors[0] comp_list.append(clone(molecule_tag)) From 00db4e0a582b5b6eea75a1c66f2e16e7b0377c14 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Tue, 25 Apr 2023 13:58:41 -0700 Subject: [PATCH 17/25] added tests to condense function --- mbuild/tests/test_compound.py | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index e4fe87704..aa099869c 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -923,6 +923,65 @@ def test_particle_in_particle(self): assert len(list(parent.ancestors())) == 0 assert next(parent.particles_by_name("A")) == part + def test_condense(self, ethane): + ethanes = mb.Compound() + ethanes.add(mb.clone(ethane)) + ethanes.add(mb.clone(ethane)) + system = mb.Compound() + system.add(ethanes) + system_hierarchy = system.print_hierarchy(show_tree=False) + + # Before we condese + assert len(system.children) == 1 + assert len(ethanes.children) == 2 + assert system.n_bonds == 14 + assert system.n_particles == 16 + assert system_hierarchy.depth() == 4 + + # Condense the Compound, returning a copy + condensed = system.condense(inplace=False) + condensed_hierarchy = condensed.print_hierarchy(show_tree=False) + + assert len(condensed.children) == 2 + assert condensed.n_bonds == 14 + assert condensed.n_particles == 16 + + assert condensed_hierarchy.depth() == 3 + assert condensed_hierarchy.to_json(with_data=False) == '{"Compound, 16 particles, 14 bonds, 2 children": {"children": [{"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' + + # Condense the Compound in place + system_copy = mb.clone(system) + system_copy.condense(inplace=True) + condensed_hierarchy2 = system_copy.print_hierarchy(show_tree=False) + + assert len(system_copy.children) == 2 + assert system_copy.n_bonds == 14 + assert system_copy.n_particles == 16 + assert condensed_hierarchy2.depth() == 3 + assert condensed_hierarchy2.to_json(with_data=False) == '{"Compound, 16 particles, 14 bonds, 2 children": {"children": [{"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' + + # add two particles that aren't bonded + system.add(mb.Compound(name='C')) + system.add(mb.Compound(name='C')) + system_hierarchy = system.print_hierarchy(show_tree=False) + + assert len(system.children) == 3 + assert len(ethanes.children) == 2 + assert system.n_bonds == 14 + assert system.n_particles == 18 + assert system_hierarchy.depth() == 4 + + # condense the system + condensed = system.condense(inplace=False) + condensed_hierarchy = condensed.print_hierarchy(show_tree=False) + + assert len(condensed.children) == 4 + assert condensed.n_bonds == 14 + assert condensed.n_particles == 18 + + assert condensed_hierarchy.depth() == 3 + assert condensed_hierarchy.to_json(with_data=False) == '{"Compound, 18 particles, 14 bonds, 4 children": {"children": ["[C x 2], 1 particles, 0 bonds, 0 children", {"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' + def test_flatten_eth(self, ethane): # Before flattening assert len(ethane.children) == 2 From ce117689a7dca77116bc1e52baee64468b5c9c7f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 20:59:27 +0000 Subject: [PATCH 18/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/tests/test_compound.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index aa099869c..3175e18b0 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -945,10 +945,13 @@ def test_condense(self, ethane): assert len(condensed.children) == 2 assert condensed.n_bonds == 14 assert condensed.n_particles == 16 - + assert condensed_hierarchy.depth() == 3 - assert condensed_hierarchy.to_json(with_data=False) == '{"Compound, 16 particles, 14 bonds, 2 children": {"children": [{"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' - + assert ( + condensed_hierarchy.to_json(with_data=False) + == '{"Compound, 16 particles, 14 bonds, 2 children": {"children": [{"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' + ) + # Condense the Compound in place system_copy = mb.clone(system) system_copy.condense(inplace=True) @@ -958,11 +961,14 @@ def test_condense(self, ethane): assert system_copy.n_bonds == 14 assert system_copy.n_particles == 16 assert condensed_hierarchy2.depth() == 3 - assert condensed_hierarchy2.to_json(with_data=False) == '{"Compound, 16 particles, 14 bonds, 2 children": {"children": [{"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' - + assert ( + condensed_hierarchy2.to_json(with_data=False) + == '{"Compound, 16 particles, 14 bonds, 2 children": {"children": [{"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' + ) + # add two particles that aren't bonded - system.add(mb.Compound(name='C')) - system.add(mb.Compound(name='C')) + system.add(mb.Compound(name="C")) + system.add(mb.Compound(name="C")) system_hierarchy = system.print_hierarchy(show_tree=False) assert len(system.children) == 3 @@ -970,7 +976,7 @@ def test_condense(self, ethane): assert system.n_bonds == 14 assert system.n_particles == 18 assert system_hierarchy.depth() == 4 - + # condense the system condensed = system.condense(inplace=False) condensed_hierarchy = condensed.print_hierarchy(show_tree=False) @@ -980,7 +986,10 @@ def test_condense(self, ethane): assert condensed.n_particles == 18 assert condensed_hierarchy.depth() == 3 - assert condensed_hierarchy.to_json(with_data=False) == '{"Compound, 18 particles, 14 bonds, 4 children": {"children": ["[C x 2], 1 particles, 0 bonds, 0 children", {"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' + assert ( + condensed_hierarchy.to_json(with_data=False) + == '{"Compound, 18 particles, 14 bonds, 4 children": {"children": ["[C x 2], 1 particles, 0 bonds, 0 children", {"[Ethane x 2], 8 particles, 7 bonds, 2 children": {"children": [{"[CH3 x 2], 4 particles, 3 bonds, 4 children": {"children": ["[C x 1], 1 particles, 4 bonds, 0 children", "[H x 3], 1 particles, 1 bonds, 0 children"]}}]}}]}}' + ) def test_flatten_eth(self, ethane): # Before flattening From a0e6932d73d601cd1833506bf0a49f1471123f11 Mon Sep 17 00:00:00 2001 From: Christopher Iacovella Date: Thu, 27 Apr 2023 12:16:51 -0700 Subject: [PATCH 19/25] addressed comments from cal --- mbuild/compound.py | 20 ++++++++------------ mbuild/conversion.py | 3 --- mbuild/tests/test_compound.py | 2 +- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 7e2cbb28d..365bc283b 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -791,24 +791,20 @@ def _reorder_rigid_ids(self): if self.rigid_id > missing_rigid_id: self.rigid_id -= 1 - # helper function to flattening a list that may be nested, in particular used for a list of labels def _flatten_list(self, c_list): - if isinstance(c_list, list): - for c in c_list: - if isinstance(c, list): - yield from self._flatten_list(c) - else: - yield c + """Flatten a list - # helper function to flatten a list of Compounds that may be nested - def _flatten_compound_list(self, c_list): - if isinstance(c_list, Iterable): + Helper function to flatten a list that may be nested, e.g. [comp1, [comp2, comp3]]. + """ + if isinstance(c_list, Iterable) and not isinstance(c_list, str): for c in c_list: - if isinstance(c, Iterable): + if isinstance(c, Iterable) and not isinstance(c, str): yield from self._flatten_list(c) else: yield c + + def add( self, new_child, @@ -853,7 +849,7 @@ def add( from mbuild.port import Port if isinstance(new_child, Iterable) and not isinstance(new_child, str): - compound_list = [c for c in self._flatten_compound_list(new_child)] + compound_list = [c for c in self._flatten_list(new_child)] if label is not None and isinstance(label, list): label_list = [c for c in self._flatten_list(label)] if len(label_list) != len(compound_list): diff --git a/mbuild/conversion.py b/mbuild/conversion.py index bc1ead3db..50e0f2bb8 100644 --- a/mbuild/conversion.py +++ b/mbuild/conversion.py @@ -558,7 +558,6 @@ def from_parmed( for chain, residues in chains.items(): if len(chain) > 1: chain_compound = mb.Compound() - # compound.add(chain_compound, chain_id) chain_list.append(chain_compound) else: chain_compound = compound @@ -566,7 +565,6 @@ def from_parmed( for residue in residues: if infer_hierarchy: residue_compound = mb.Compound(name=residue.name) - # chain_compound.add(residue_compound) parent_compound = residue_compound res_list.append(residue_compound) else: @@ -585,7 +583,6 @@ def from_parmed( ) atom_list.append(new_atom) atom_label_list.append("{0}[$]".format(atom.name)) - # parent_compound.add(new_atom, label="{0}[$]".format(atom.name)) atom_mapping[atom] = new_atom parent_compound.add(atom_list, label=atom_label_list) if infer_hierarchy: diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index 3175e18b0..80101f2d3 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -635,7 +635,7 @@ def test_list_flatten(self, h2o): four.name = "four" out = [ a.name - for a in h2o._flatten_compound_list([one, two, [three, four]]) + for a in h2o._flatten_list([one, two, [three, four]]) ] assert out == ["one", "two", "three", "four"] From 520f24305994f3e86c80ed9be127464b51e81a79 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 19:17:13 +0000 Subject: [PATCH 20/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/compound.py | 2 -- mbuild/tests/test_compound.py | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 365bc283b..ce9d87776 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -803,8 +803,6 @@ def _flatten_list(self, c_list): else: yield c - - def add( self, new_child, diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index 80101f2d3..1490721ac 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -633,10 +633,7 @@ def test_list_flatten(self, h2o): three.name = "three" four = mb.clone(h2o) four.name = "four" - out = [ - a.name - for a in h2o._flatten_list([one, two, [three, four]]) - ] + out = [a.name for a in h2o._flatten_list([one, two, [three, four]])] assert out == ["one", "two", "three", "four"] From 93b25a44d0a165d3eb8e18657ac9b64cc497e270 Mon Sep 17 00:00:00 2001 From: Co Quach Date: Fri, 28 Apr 2023 12:39:15 -0500 Subject: [PATCH 21/25] minor changes in codes and arrangmenet --- mbuild/compound.py | 65 +++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index ce9d87776..746796ed4 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -511,7 +511,8 @@ def mass(self): if self._contains_only_ports(): return self._particle_mass(self) else: - particle_masses = [self._particle_mass(p) for p in self.particles()] + particle_masses = [self._particle_mass( + p) for p in self.particles()] if None in particle_masses: warn( f"Some particle of {self} does not have mass." @@ -791,18 +792,6 @@ def _reorder_rigid_ids(self): if self.rigid_id > missing_rigid_id: self.rigid_id -= 1 - def _flatten_list(self, c_list): - """Flatten a list - - Helper function to flatten a list that may be nested, e.g. [comp1, [comp2, comp3]]. - """ - if isinstance(c_list, Iterable) and not isinstance(c_list, str): - for c in c_list: - if isinstance(c, Iterable) and not isinstance(c, str): - yield from self._flatten_list(c) - else: - yield c - def add( self, new_child, @@ -847,29 +836,29 @@ def add( from mbuild.port import Port if isinstance(new_child, Iterable) and not isinstance(new_child, str): - compound_list = [c for c in self._flatten_list(new_child)] - if label is not None and isinstance(label, list): - label_list = [c for c in self._flatten_list(label)] + compound_list = [c for c in _flatten_list(new_child)] + if label is not None and isinstance(label, (list, tuple)): + label_list = [c for c in _flatten_list(label)] if len(label_list) != len(compound_list): raise ValueError( "The list-like object for label must be the same length as" "the list-like object of child Compounds. " - f"label total length {len(label_list)}, new_child '{len(new_child)}'." + f"total length of labels: {len(label_list)}, new_child: {len(new_child)}." ) temp_bond_graphs = [] for child in compound_list: # create a list of bond graphs of the children to add if containment: - if child.bond_graph is not None and not isinstance( - self, Port - ): + if child.bond_graph and not isinstance(self, Port): temp_bond_graphs.append(child.bond_graph) + # compose children bond_graphs; make sure we actually have graphs to compose + children_bond_graph = None if len(temp_bond_graphs) != 0: children_bond_graph = nx.compose_all(temp_bond_graphs) if ( - len(temp_bond_graphs) != 0 + temp_bond_graphs and not isinstance(self, Port) and children_bond_graph is not None ): @@ -1917,7 +1906,7 @@ def _visualize_nglview(self, show_ports=False, color_scheme={}): mdtraj = import_("mdtraj") from mdtraj.geometry.sasa import _ATOMIC_RADII - remove_digits = lambda x: "".join( + def remove_digits(x): return "".join( i for i in x if not i.isdigit() or i == "_" ) for particle in self.particles(): @@ -2003,9 +1992,9 @@ def condense(self, inplace=True): for child in [self.children]: # Need to handle the case when child is a port self.remove(child) - self.add(comp_list) + self.add(comp_list) else: - new_compound = Compound() + new_compound = Compound(name=self.name) new_compound.add(comp_list) return new_compound @@ -2518,7 +2507,8 @@ def _check_openbabel_constraints( if not isinstance(part, Compound): raise MBuildError(f"{part} is not a Compound.") if id(part) != id(self) and id(part) not in successors_list: - raise MBuildError(f"{part} is not a member of Compound {self}.") + raise MBuildError( + f"{part} is not a member of Compound {self}.") if check_if_particle: if len(part.children) != 0: @@ -2664,8 +2654,10 @@ def _energy_minimize_openbabel( f"Cannot create a constraint between a Particle and itself: {p1} {p2} ." ) - pid_1 = particle_idx[id(p1)] + 1 # openbabel indices start at 1 - pid_2 = particle_idx[id(p2)] + 1 # openbabel indices start at 1 + # openbabel indices start at 1 + pid_1 = particle_idx[id(p1)] + 1 + # openbabel indices start at 1 + pid_2 = particle_idx[id(p2)] + 1 dist = ( con_temp[1] * 10.0 ) # obenbabel uses angstroms, not nm, convert to angstroms @@ -2763,7 +2755,8 @@ def _energy_minimize_openbabel( # Since the ignore_compounds can only be passed as a list # we can check the whole list at once before looping over it - self._check_openbabel_constraints(ignore_compounds, successors_list) + self._check_openbabel_constraints( + ignore_compounds, successors_list) for ignore in ignore_compounds: p1 = ignore @@ -3413,7 +3406,8 @@ def __getitem__(self, selection): return list(self.particles())[selection] if isinstance(selection, str): if selection not in self.labels: - raise MBuildError(f"{self.name}['{selection}'] does not exist.") + raise MBuildError( + f"{self.name}['{selection}'] does not exist.") return self.labels.get(selection) def __repr__(self): @@ -3531,3 +3525,16 @@ def _clone_bonds(self, clone_of=None): Particle = Compound + + +def _flatten_list(c_list): + """Flatten a list + + Helper function to flatten a list that may be nested, e.g. [comp1, [comp2, comp3]]. + """ + if isinstance(c_list, Iterable) and not isinstance(c_list, str): + for c in c_list: + if isinstance(c, Iterable) and not isinstance(c, str): + yield from _flatten_list(c) + else: + yield c From cbffe118ad9044f9cb5da446805d6032c7aff2fd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 17:40:00 +0000 Subject: [PATCH 22/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/compound.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 746796ed4..715de4f2e 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -511,8 +511,7 @@ def mass(self): if self._contains_only_ports(): return self._particle_mass(self) else: - particle_masses = [self._particle_mass( - p) for p in self.particles()] + particle_masses = [self._particle_mass(p) for p in self.particles()] if None in particle_masses: warn( f"Some particle of {self} does not have mass." @@ -1906,9 +1905,9 @@ def _visualize_nglview(self, show_ports=False, color_scheme={}): mdtraj = import_("mdtraj") from mdtraj.geometry.sasa import _ATOMIC_RADII - def remove_digits(x): return "".join( - i for i in x if not i.isdigit() or i == "_" - ) + def remove_digits(x): + return "".join(i for i in x if not i.isdigit() or i == "_") + for particle in self.particles(): particle.name = remove_digits(particle.name).upper() if not particle.name: @@ -2507,8 +2506,7 @@ def _check_openbabel_constraints( if not isinstance(part, Compound): raise MBuildError(f"{part} is not a Compound.") if id(part) != id(self) and id(part) not in successors_list: - raise MBuildError( - f"{part} is not a member of Compound {self}.") + raise MBuildError(f"{part} is not a member of Compound {self}.") if check_if_particle: if len(part.children) != 0: @@ -2755,8 +2753,7 @@ def _energy_minimize_openbabel( # Since the ignore_compounds can only be passed as a list # we can check the whole list at once before looping over it - self._check_openbabel_constraints( - ignore_compounds, successors_list) + self._check_openbabel_constraints(ignore_compounds, successors_list) for ignore in ignore_compounds: p1 = ignore @@ -3406,8 +3403,7 @@ def __getitem__(self, selection): return list(self.particles())[selection] if isinstance(selection, str): if selection not in self.labels: - raise MBuildError( - f"{self.name}['{selection}'] does not exist.") + raise MBuildError(f"{self.name}['{selection}'] does not exist.") return self.labels.get(selection) def __repr__(self): From 3a93096a07710e477984b295cb15ecc53935db78 Mon Sep 17 00:00:00 2001 From: Co Quach Date: Fri, 28 Apr 2023 12:48:56 -0500 Subject: [PATCH 23/25] fix style --- mbuild/compound.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 715de4f2e..7ad850542 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -511,7 +511,8 @@ def mass(self): if self._contains_only_ports(): return self._particle_mass(self) else: - particle_masses = [self._particle_mass(p) for p in self.particles()] + particle_masses = [self._particle_mass( + p) for p in self.particles()] if None in particle_masses: warn( f"Some particle of {self} does not have mass." @@ -2506,7 +2507,8 @@ def _check_openbabel_constraints( if not isinstance(part, Compound): raise MBuildError(f"{part} is not a Compound.") if id(part) != id(self) and id(part) not in successors_list: - raise MBuildError(f"{part} is not a member of Compound {self}.") + raise MBuildError( + f"{part} is not a member of Compound {self}.") if check_if_particle: if len(part.children) != 0: @@ -2753,7 +2755,8 @@ def _energy_minimize_openbabel( # Since the ignore_compounds can only be passed as a list # we can check the whole list at once before looping over it - self._check_openbabel_constraints(ignore_compounds, successors_list) + self._check_openbabel_constraints( + ignore_compounds, successors_list) for ignore in ignore_compounds: p1 = ignore @@ -3403,7 +3406,8 @@ def __getitem__(self, selection): return list(self.particles())[selection] if isinstance(selection, str): if selection not in self.labels: - raise MBuildError(f"{self.name}['{selection}'] does not exist.") + raise MBuildError( + f"{self.name}['{selection}'] does not exist.") return self.labels.get(selection) def __repr__(self): @@ -3524,7 +3528,7 @@ def _clone_bonds(self, clone_of=None): def _flatten_list(c_list): - """Flatten a list + """Flatten a list. Helper function to flatten a list that may be nested, e.g. [comp1, [comp2, comp3]]. """ From 667edc5d6577ece9bdb044132aa6e73962cdecd5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 17:49:23 +0000 Subject: [PATCH 24/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mbuild/compound.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mbuild/compound.py b/mbuild/compound.py index 7ad850542..b09569b3f 100644 --- a/mbuild/compound.py +++ b/mbuild/compound.py @@ -511,8 +511,7 @@ def mass(self): if self._contains_only_ports(): return self._particle_mass(self) else: - particle_masses = [self._particle_mass( - p) for p in self.particles()] + particle_masses = [self._particle_mass(p) for p in self.particles()] if None in particle_masses: warn( f"Some particle of {self} does not have mass." @@ -2507,8 +2506,7 @@ def _check_openbabel_constraints( if not isinstance(part, Compound): raise MBuildError(f"{part} is not a Compound.") if id(part) != id(self) and id(part) not in successors_list: - raise MBuildError( - f"{part} is not a member of Compound {self}.") + raise MBuildError(f"{part} is not a member of Compound {self}.") if check_if_particle: if len(part.children) != 0: @@ -2755,8 +2753,7 @@ def _energy_minimize_openbabel( # Since the ignore_compounds can only be passed as a list # we can check the whole list at once before looping over it - self._check_openbabel_constraints( - ignore_compounds, successors_list) + self._check_openbabel_constraints(ignore_compounds, successors_list) for ignore in ignore_compounds: p1 = ignore @@ -3406,8 +3403,7 @@ def __getitem__(self, selection): return list(self.particles())[selection] if isinstance(selection, str): if selection not in self.labels: - raise MBuildError( - f"{self.name}['{selection}'] does not exist.") + raise MBuildError(f"{self.name}['{selection}'] does not exist.") return self.labels.get(selection) def __repr__(self): From 54281f7cd8b7f712cda53a40eab4c0d001706a02 Mon Sep 17 00:00:00 2001 From: Co Quach Date: Fri, 28 Apr 2023 13:24:05 -0500 Subject: [PATCH 25/25] fix unit test --- mbuild/tests/test_compound.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mbuild/tests/test_compound.py b/mbuild/tests/test_compound.py index 1490721ac..99c19e1a5 100644 --- a/mbuild/tests/test_compound.py +++ b/mbuild/tests/test_compound.py @@ -622,7 +622,9 @@ def test_add_label_exists(self, ethane, h2o): ethane.add(mb.clone(h2o), label="water") def test_list_flatten(self, h2o): - out = [a for a in h2o._flatten_list(["one", "two", ["three", "four"]])] + from mbuild.compound import _flatten_list + + out = [a for a in _flatten_list(["one", "two", ["three", "four"]])] assert out == ["one", "two", "three", "four"] one = mb.clone(h2o) @@ -633,7 +635,7 @@ def test_list_flatten(self, h2o): three.name = "three" four = mb.clone(h2o) four.name = "four" - out = [a.name for a in h2o._flatten_list([one, two, [three, four]])] + out = [a.name for a in _flatten_list([one, two, [three, four]])] assert out == ["one", "two", "three", "four"]