def make_mols(molecule_subgraphs=molecule_subgraphs, center=False): # pylint:disable=dangerous-default-value molecules = [] indices = [] indices_here = [] mol_centers = [] coordinates = [] for subgraph in molecule_subgraphs: coords = [ supercell_sg.structure[node].coords for node in subgraph.nodes() ] species = [ supercell_sg.structure[node].specie for node in subgraph.nodes() ] # binding = [ # supercell_sg.structure[n].properties["binding"] # for n in subgraph.nodes() # ] idx = [subgraph.nodes[node]["idx"] for node in subgraph.nodes()] idx_here = subgraph.nodes() molecule = Molecule( species, coords) # site_properties={"binding": binding} mol_centers.append( np.mean(supercell_sg.structure.cart_coords[idx_here], axis=0)) # shift so origin is at center of mass if center: molecule = molecule.get_centered_molecule() indices.append(idx) molecules.append(molecule) indices_here.append(idx_here) coordinates.append(coords) return molecules, indices, indices_here, mol_centers, coordinates
def get_subgraphs_as_molecules_all( structure_graph: pymatgen.analysis.graphs.StructureGraph, ): """Copied from http://pymatgen.org/_modules/pymatgen/analysis/graphs.html#StructureGraph.get_subgraphs_as_molecules and removed the duplicate check Args: structure_graph ( pymatgen.analysis.graphs.StructureGraph): Structuregraph Returns: List: list of molecules """ # creating a supercell is an easy way to extract # molecules (and not, e.g., layers of a 2D crystal) # without adding extra logic supercell_sg = structure_graph * (3, 3, 3) # make undirected to find connected subgraphs supercell_sg.graph = nx.Graph(supercell_sg.graph) # find subgraphs all_subgraphs = [ supercell_sg.graph.subgraph(c) for c in nx.connected_components(supercell_sg.graph) ] # discount subgraphs that lie across *supercell* boundaries # these will subgraphs representing crystals molecule_subgraphs = [] for subgraph in all_subgraphs: intersects_boundary = any([ d["to_jimage"] != (0, 0, 0) for u, v, d in subgraph.edges(data=True) ]) if not intersects_boundary: molecule_subgraphs.append(nx.MultiDiGraph(subgraph)) # add specie names to graph to be able to test for isomorphism for subgraph in molecule_subgraphs: for node in subgraph: subgraph.add_node(node, specie=str(supercell_sg.structure[node].specie)) # get Molecule objects for each subgraph molecules = [] for subgraph in molecule_subgraphs: coords = [supercell_sg.structure[n].coords for n in subgraph.nodes()] species = [supercell_sg.structure[n].specie for n in subgraph.nodes()] molecule = Molecule(species, coords) # shift so origin is at center of mass molecule = molecule.get_centered_molecule() molecules.append(molecule) return molecules
def get_subgraphs_as_molecules(self, use_weights=False): """ Retrieve subgraphs as molecules, useful for extracting molecules from periodic crystals. Will only return unique molecules, not any duplicates present in the crystal (a duplicate defined as an isomorphic subgraph). :param use_weights (bool): If True, only treat subgraphs as isomorphic if edges have the same weights. Typically, this means molecules will need to have the same bond lengths to be defined as duplicates, otherwise bond lengths can differ. This is a fairly robust approach, but will treat e.g. enantiomers as being duplicates. :return: list of unique Molecules in Structure """ # creating a supercell is an easy way to extract # molecules (and not, e.g., layers of a 2D crystal) # without adding extra logic if getattr(self, '_supercell_sg', None) is None: self._supercell_sg = supercell_sg = self*(3,3,3) # make undirected to find connected subgraphs supercell_sg.graph = nx.Graph(supercell_sg.graph) # find subgraphs all_subgraphs = list(nx.connected_component_subgraphs(supercell_sg.graph)) # discount subgraphs that lie across *supercell* boundaries # these will subgraphs representing crystals molecule_subgraphs = [] for subgraph in all_subgraphs: intersects_boundary = any([d['to_jimage'] != (0, 0, 0) for u, v, d in subgraph.edges(data=True)]) if not intersects_boundary: molecule_subgraphs.append(subgraph) # add specie names to graph to be able to test for isomorphism for subgraph in molecule_subgraphs: for n in subgraph: subgraph.add_node(n, specie=str(supercell_sg.structure[n].specie)) # now define how we test for isomorphism def node_match(n1, n2): return n1['specie'] == n2['specie'] def edge_match(e1, e2): if use_weights: return e1['weight'] == e2['weight'] else: return True # prune duplicate subgraphs unique_subgraphs = [] for subgraph in molecule_subgraphs: already_present = [nx.is_isomorphic(subgraph, g, node_match=node_match, edge_match=edge_match) for g in unique_subgraphs] if not any(already_present): unique_subgraphs.append(subgraph) # get Molecule objects for each subgraph molecules = [] for subgraph in unique_subgraphs: coords = [supercell_sg.structure[n].coords for n in subgraph.nodes()] species = [supercell_sg.structure[n].specie for n in subgraph.nodes()] molecule = Molecule(species, coords) # shift so origin is at center of mass molecule = molecule.get_centered_molecule() molecules.append(molecule) return molecules