def test_substitute(self): structure = Structure.from_file(os.path.join(PymatgenTest.TEST_FILES_DIR, "Li2O.cif")) molecule = FunctionalGroups["methyl"] structure_copy = copy.deepcopy(structure) structure_copy_graph = copy.deepcopy(structure) sg = StructureGraph.with_local_env_strategy(structure, MinimumDistanceNN()) sg_copy = copy.deepcopy(sg) # Ensure that strings and molecules lead to equivalent substitutions sg.substitute_group(1, molecule, MinimumDistanceNN) sg_copy.substitute_group(1, "methyl", MinimumDistanceNN) self.assertEqual(sg, sg_copy) # Ensure that the underlying structure has been modified as expected structure_copy.substitute(1, "methyl") self.assertEqual(structure_copy, sg.structure) # Test inclusion of graph dictionary graph_dict = { (0, 1): {"weight": 0.5}, (0, 2): {"weight": 0.5}, (0, 3): {"weight": 0.5}, } sg_with_graph = StructureGraph.with_local_env_strategy(structure_copy_graph, MinimumDistanceNN()) sg_with_graph.substitute_group(1, "methyl", MinimumDistanceNN, graph_dict=graph_dict) edge = sg_with_graph.graph.get_edge_data(11, 13)[0] self.assertEqual(edge["weight"], 0.5)
def test_mul(self): square_sg_mul = self.square_sg * (2, 1, 1) square_sg_mul_ref_str = """Structure Graph Structure: Full Formula (H2) Reduced Formula: H2 abc : 10.000000 5.000000 50.000000 angles: 90.000000 90.000000 90.000000 Sites (2) # SP a b c --- ---- --- --- --- 0 H 0 0 0 1 H 0.5 0 -0 Graph: bonds from to to_image ---- ---- ------------ 0 0 (0, 1, 0) 0 0 (0, -1, 0) 0 1 (0, 0, 0) 0 1 (-1, 0, 0) 1 1 (0, 1, 0) 1 1 (0, -1, 0) """ square_sg_mul_actual_str = str(square_sg_mul) # only testing bonds portion, # the c frac_coord of the second H can vary from # 0 to -0 depending on machine precision square_sg_mul_ref_str = "\n".join(square_sg_mul_ref_str.splitlines()[11:]) square_sg_mul_actual_str = "\n".join(square_sg_mul_actual_str.splitlines()[11:]) self.assertStrContentEqual(square_sg_mul_actual_str, square_sg_mul_ref_str) # test sequential multiplication sq_sg_1 = self.square_sg * (2, 2, 1) sq_sg_1 = sq_sg_1 * (2, 2, 1) sq_sg_2 = self.square_sg * (4, 4, 1) self.assertEqual(sq_sg_1.graph.number_of_edges(), sq_sg_2.graph.number_of_edges()) # TODO: the below test still gives 8 != 4 # self.assertEqual(self.square_sg.get_coordination_of_site(0), 4) mos2_sg_mul = self.mos2_sg * (3, 3, 1) for idx in mos2_sg_mul.structure.indices_from_symbol("Mo"): self.assertEqual(mos2_sg_mul.get_coordination_of_site(idx), 6) mos2_sg_premul = StructureGraph.with_local_env_strategy(self.structure * (3, 3, 1), MinimumDistanceNN()) self.assertTrue(mos2_sg_mul == mos2_sg_premul) # test 3D Structure nio_sg = StructureGraph.with_local_env_strategy(self.NiO, MinimumDistanceNN()) nio_sg = nio_sg * 3 for n in range(len(nio_sg)): self.assertEqual(nio_sg.get_coordination_of_site(n), 6)
def get_bonds(self): graph = StructureGraph.with_local_env_strategy( self.structure, CutOffDictNN({("Si", "O"): 2.0, ("O", "Si"): 2.0}) ) # GULP starts counting on 1 return [(u + 1, v + 1, "single") for u, v in graph.graph.edges()]
def _has_stray_molecules(self) -> bool: self._set_cnn() sgraph = StructureGraph.with_local_env_strategy(self.structure, self._cnn) molecules = get_subgraphs_as_molecules_all(sgraph) if len(molecules) > 0: return True return False
def subgraph_translate3(read_path, write_dir): ''' This function takes the metal-deficient structure and saves the all connected components (i.e. linkers) ''' ase_struct = read(read_path) struct = pm.get_structure(ase_struct) n_atoms = len(struct.sites) sg = StructureGraph.with_local_env_strategy(struct, env.JmolNN(tol=.3)) count = 1 for i in range(n_atoms): for j in range(n_atoms): if i != j: try: sg.alter_edge(i, j, new_weight=count) except: pass count += 1 A = sg.get_subgraphs_as_molecules(use_weights=True) ls = [] count = 0 for mol in A: if len(mol.sites) > 4: smiles = getSmiles(mol) ls.append(smiles) path = write_dir + 'mol_' + str(count) + '.xyz' saveMol(mol, path) count += 1 return count, ls
def test_no_duplicate_hops(self): test_structure_dict = { "@module": "pymatgen.core.structure", "@class": "Structure", "charge": None, "lattice": { "matrix": [[2.990355, -5.149042, 0.0], [2.990355, 5.149042, 0.0], [0.0, 0.0, 24.51998]] }, "sites": [ { "species": [{ "element": "Ba", "occu": 1 }], "abc": [0.005572, 0.994428, 0.151095], "properties": {} }, ], } test_structure = Structure.from_dict(test_structure_dict) nn = MinimumDistanceNN(cutoff=6, get_all_sites=True) sg = StructureGraph.with_local_env_strategy(test_structure, nn) self.assertEqual(sg.graph.number_of_edges(), 3)
def __init__(self, structure, migrating_specie, max_path_length=10, symprec=0.1, vac_mode=False): """ Args: structure: Input structure that contains all sites. migrating_specie (Specie-like): The specie that migrates. E.g., "Li". max_path_length (float): Maximum length of NEB path in the unit of Angstrom. Defaults to None, which means you are setting the value to the min cutoff until finding 1D or >1D percolating paths. symprec (float): Symmetry precision to determine equivalence. """ self.structure = structure self.migrating_specie = get_el_sp(migrating_specie) self.symprec = symprec self.a = SpacegroupAnalyzer(self.structure, symprec=self.symprec) self.symm_structure = self.a.get_symmetrized_structure() self.only_sites = self.get_only_sites() self.unique_hops = None # Generate the graph edges between these all the sites self.s_graph = StructureGraph.with_local_env_strategy( self.only_sites, MinimumDistanceNN( cutoff=max_path_length, get_all_sites=True)) # weights in this graph are the distances self.s_graph.set_node_attributes()
def _get_graphs(cutoff, ordered_structures): """ Generate graph representations of magnetic structures with nearest neighbor bonds. Right now this only works for MinimumDistanceNN. Args: cutoff (float): Cutoff in Angstrom for nearest neighbor search. ordered_structures (list): Structure objects. Returns: sgraphs (list): StructureGraph objects. """ # Strategy for finding neighbors if cutoff: strategy = MinimumDistanceNN(cutoff=cutoff, get_all_sites=True) else: strategy = MinimumDistanceNN() # only NN # Generate structure graphs sgraphs = [ StructureGraph.with_local_env_strategy(s, strategy=strategy) for s in ordered_structures ] return sgraphs
def _preprocess_input_to_graph( input: Union[Structure, StructureGraph, Molecule, MoleculeGraph], bonding_strategy: str = "CrystalNN", bonding_strategy_kwargs: Optional[Dict] = None, ) -> Union[StructureGraph, MoleculeGraph]: if isinstance(input, Structure): # ensure fractional co-ordinates are normalized to be in [0,1) # (this is actually not guaranteed by Structure) input = input.as_dict(verbosity=0) for site in input["sites"]: site["abc"] = np.mod(site["abc"], 1) input = Structure.from_dict(input) if not input.is_ordered: # calculating bonds in disordered structures is currently very flaky bonding_strategy = "CutOffDictNN" # we assume most uses of this class will give a structure as an input argument, # meaning we have to calculate the graph for bonding information, however if # the graph is already known and supplied, we will use that if isinstance(input, StructureGraph) or isinstance( input, MoleculeGraph): graph = input else: if (bonding_strategy not in StructureMoleculeComponent. available_bonding_strategies.keys()): raise ValueError( "Bonding strategy not supported. Please supply a name " "of a NearNeighbor subclass, choose from: {}".format( ", ".join(StructureMoleculeComponent. available_bonding_strategies.keys()))) else: bonding_strategy_kwargs = bonding_strategy_kwargs or {} if bonding_strategy == "CutOffDictNN": if "cut_off_dict" in bonding_strategy_kwargs: # TODO: remove this hack by making args properly JSON serializable bonding_strategy_kwargs["cut_off_dict"] = { (x[0], x[1]): x[2] for x in bonding_strategy_kwargs["cut_off_dict"] } bonding_strategy = StructureMoleculeComponent.available_bonding_strategies[ bonding_strategy](**bonding_strategy_kwargs) try: if isinstance(input, Structure): graph = StructureGraph.with_local_env_strategy( input, bonding_strategy) else: graph = MoleculeGraph.with_local_env_strategy( input, bonding_strategy) except: # for some reason computing bonds failed, so let's not have any bonds(!) if isinstance(input, Structure): graph = StructureGraph.with_empty_graph(input) else: graph = MoleculeGraph.with_empty_graph(input) return graph
def test_from_local_env_and_equality_and_diff(self): nn = MinimumDistanceNN() sg = StructureGraph.with_local_env_strategy(self.structure, nn) self.assertEqual(sg.graph.number_of_edges(), 6) nn2 = MinimumOKeeffeNN() sg2 = StructureGraph.with_local_env_strategy(self.structure, nn2) self.assertTrue(sg == sg2) self.assertTrue(sg == self.mos2_sg) # TODO: find better test case where graphs are different diff = sg.diff(sg2) self.assertEqual(diff["dist"], 0) self.assertEqual(self.square_sg.get_coordination_of_site(0), 2)
def _has_lone_atom(self): self._set_cnn() graph = StructureGraph.with_local_env_strategy(self.structure, self._cnn) for site in range(len(self.structure)): nbr = graph.get_connected_sites(site) if not nbr: return True return False
def compare_graph_pair_cached(self, items): nn_strategy = JmolNN() crystal_a = self.reduced_structure_dict[ self.scalar_feature_matrix.iloc[items[0]]["name"]] crystal_b = self.reduced_structure_dict[ self.scalar_feature_matrix.iloc[items[1]]["name"]] if self.try_supercell: crystal_a, crystal_b = attempt_supercell_pymatgen( crystal_a, crystal_b) sgraph_a = StructureGraph.with_local_env_strategy( crystal_a, nn_strategy) sgraph_b = StructureGraph.with_local_env_strategy( crystal_b, nn_strategy) try: if sgraph_a == sgraph_b: logger.debug("Found duplicate") return items except ValueError: logger.debug("Structures were probably not different") return False
def get_cooccurrence_pairs(struct): pairs = [] struct_graph = StructureGraph.with_local_env_strategy(struct, CrystalNN()) labels = {i: spec.name for i, spec in enumerate(struct.species)} G = struct_graph.graph.to_undirected() for n in labels: target = labels[n] # TODO what if the atom doesn't have any neighbors? neighbors = [labels[i] for i in G.neighbors(n)] for neighbor in neighbors: pairs.append((target, neighbor)) return pairs
def test_no_duplicate_hops(self): test_structure = Structure( lattice=[[2.990355, -5.149042, 0.0], [2.990355, 5.149042, 0.0], [0.0, 0.0, 24.51998]], species=["Ba"], coords=[[0.005572, 0.994428, 0.151095]], ) nn = MinimumDistanceNN(cutoff=6, get_all_sites=True) sg = StructureGraph.with_local_env_strategy(test_structure, nn) self.assertEqual(sg.graph.number_of_edges(), 3)
def count_cooccurrences_single(struct): counts = {} struct_graph = StructureGraph.with_local_env_strategy(struct, CrystalNN()) labels = {i: spec.name for i, spec in enumerate(struct.species)} G = struct_graph.graph.to_undirected() for n in labels: target = labels[n] neighbors = [labels[i] for i in G.neighbors(n)] for neighbor in neighbors: key = frozenset([target, neighbor]) if key not in counts: counts[key] = 0 counts[key] += 1 return counts
def _has_undercoordinated_nitrogen(self, tolerance=10): """ Captures missing hydrogens on amino groups. Basically two common cases: 1. Have the N on a carbon and no hydrogen at all 2. (not that common) due to incorrect symmetry resolution we have only one h in a bent orientation """ undercoordinated_nitrogen = False for site_index in self.n_indices: cn = self.get_cn(site_index) # pylint:disable=invalid-name if cn == 1: # this is suspicous, but it also might a CN wish is perfectly fine # to check this, we first see if the neighbor is carbon # and then what its coordination number is graph = StructureGraph.with_local_env_strategy( self.structure, self._cnn ) neighbors = graph.get_connected_sites(site_index) if (self.get_cn(neighbors[0].index) > 2) and ( str(neighbors[0].periodic_site.specie) == "C" ): undercoordinated_nitrogen = True break if cn == 2: # ToDo: Check if it is bound to metal, then it might be a nitride graph = StructureGraph.with_local_env_strategy( self.structure, self._cnn ) neighbors = graph.get_connected_sites(site_index) angle = self.structure.get_angle( site_index, neighbors[0].index, neighbors[1].index ) if np.abs(90 - angle) > tolerance: undercoordinated_nitrogen = True break self._undercoordinated_nitrogen = undercoordinated_nitrogen
def _preprocess_input_to_graph( input: Union[Structure, StructureGraph], bonding_strategy: str = DEFAULTS["bonding_strategy"], bonding_strategy_kwargs: Optional[Dict] = None, ) -> Union[StructureGraph, MoleculeGraph]: # ensure fractional co-ordinates are normalized to be in [0,1) # (this is actually not guaranteed by Structure) try: input = input.as_dict(verbosity=0) except TypeError: # TODO: remove this, necessary for Slab(?), some structure subclasses don't have verbosity input = input.as_dict() for site in input["sites"]: site["abc"] = np.mod(site["abc"], 1) input = Structure.from_dict(input) if not input.is_ordered: # calculating bonds in disordered structures is currently very flaky bonding_strategy = "CutOffDictNN" if (bonding_strategy not in StructureComponent.available_bonding_strategies.keys()): raise ValueError( "Bonding strategy not supported. Please supply a name " "of a NearNeighbor subclass, choose from: {}".format(", ".join( StructureComponent.available_bonding_strategies.keys()))) else: bonding_strategy_kwargs = bonding_strategy_kwargs or {} if bonding_strategy == "CutOffDictNN": if "cut_off_dict" in bonding_strategy_kwargs: # TODO: remove this hack by making args properly JSON serializable bonding_strategy_kwargs["cut_off_dict"] = { (x[0], x[1]): x[2] for x in bonding_strategy_kwargs["cut_off_dict"] } bonding_strategy = StructureComponent.available_bonding_strategies[ bonding_strategy](**bonding_strategy_kwargs) try: with warnings.catch_warnings(): warnings.simplefilter("ignore") graph = StructureGraph.with_local_env_strategy( input, bonding_strategy) except: # for some reason computing bonds failed, so let's not have any bonds(!) graph = StructureGraph.with_empty_graph(input) return graph
def with_local_env_strategy(cls, structure: Structure, migrating_specie: str, nn: NearNeighbors, **kwargs) -> "MigrationGraph": """ Using a specific nn strategy to get the connectivity graph between all the migrating ion sites. Args: structure: Input structure that contains all sites. migrating_specie: The specie that migrates. E.g. "Li". nn: The specific local environment object used to connect the migrating ion sites. Returns: A constructed MigrationGraph object """ only_sites = get_only_sites_from_structure(structure, migrating_specie) migration_graph = StructureGraph.with_local_env_strategy( only_sites, nn) return cls(structure=structure, m_graph=migration_graph, **kwargs)
def get_mol_pymatgen(dataframe, nbrStruc): for i in range(nbrStruc): filename = dataframe.iloc[i,0] if (filename != "QAPHUK"): print(filename) parser = CifParser("../data/cif/{}.cif".format(filename)) structure = parser.get_structures()[0] sg = StructureGraph.with_local_env_strategy(structure, locenv.JmolNN()) my_molecules = sg.get_subgraphs_as_molecules() #molecule = MoleculeGraph.with_local_env_strategy(my_molecules,locenv.JmolNN()) #print(molecule) #crystool.view(my_molecules) my_molecules = pyxyz.XYZ(my_molecules) #print(my_molecules) pyxyz.XYZ.write_file(my_molecules,"../data/xyz_pymatgen/{}.xyz".format(filename))
def with_distance(cls, structure: Structure, migrating_specie: str, max_distance: float, **kwargs) -> "MigrationGraph": """ Using a specific nn strategy to get the connectivity graph between all the migrating ion sites. Args: max_distance: Maximum length of NEB path in the unit of Angstrom. Defaults to None, which means you are setting the value to the min cutoff until finding 1D or >1D percolating paths. Returns: A constructed MigrationGraph object """ only_sites = get_only_sites_from_structure(structure, migrating_specie) migration_graph = StructureGraph.with_local_env_strategy( only_sites, MinimumDistanceNN(cutoff=max_distance, get_all_sites=True), ) return cls(structure=structure, m_graph=migration_graph, **kwargs)
def get_local_environment( structure: Structure, n: int, loc_env_strategy: NearNeighbors ) -> List[Molecule]: """Create the molecule object of the local environment based on a given local environment strategy Args: structure (Structure): Input structure n (int): The site index loc_env_strategy (NearNeighbors): Returns: Molecule: [description] """ s_graph = StructureGraph.with_local_env_strategy(loc_env_strategy) return s_graph.get_subgraphs_as_molecules()
def test_draw(self): # draw MoS2 graph self.mos2_sg.draw_graph_to_file("MoS2_single.pdf", image_labels=True, hide_image_edges=False) mos2_sg = self.mos2_sg * (9, 9, 1) mos2_sg.draw_graph_to_file("MoS2.pdf", algo="neato") # draw MoS2 graph that's been successively multiplied mos2_sg_2 = self.mos2_sg * (3, 3, 1) mos2_sg_2 = mos2_sg_2 * (3, 3, 1) mos2_sg_2.draw_graph_to_file("MoS2_twice_mul.pdf", algo="neato", hide_image_edges=True) # draw MoS2 graph that's generated from a pre-multiplied Structure mos2_sg_premul = StructureGraph.with_local_env_strategy(self.structure * (3, 3, 1), MinimumDistanceNN()) mos2_sg_premul.draw_graph_to_file("MoS2_premul.pdf", algo="neato", hide_image_edges=True) # draw graph for a square lattice self.square_sg.draw_graph_to_file("square_single.pdf", hide_image_edges=False) square_sg = self.square_sg * (5, 5, 1) square_sg.draw_graph_to_file("square.pdf", algo="neato", image_labels=True, node_labels=False) # draw graph for a body-centered square lattice self.bc_square_sg.draw_graph_to_file("bc_square_single.pdf", hide_image_edges=False) bc_square_sg = self.bc_square_sg * (9, 9, 1) bc_square_sg.draw_graph_to_file("bc_square.pdf", algo="neato", image_labels=False) # draw graph for a body-centered square lattice defined in an alternative way self.bc_square_sg_r.draw_graph_to_file("bc_square_r_single.pdf", hide_image_edges=False) bc_square_sg_r = self.bc_square_sg_r * (9, 9, 1) bc_square_sg_r.draw_graph_to_file("bc_square_r.pdf", algo="neato", image_labels=False) # delete generated test files test_files = ( "bc_square_r_single.pdf", "bc_square_r.pdf", "bc_square_single.pdf", "bc_square.pdf", "MoS2_premul.pdf", "MoS2_single.pdf", "MoS2_twice_mul.pdf", "MoS2.pdf", "square_single.pdf", "square.pdf", ) for test_file in test_files: os.remove(test_file)
def __init__( self, structure, migrating_specie, max_path_length=10, symprec=0.1, vac_mode=False, name: str = None, ): """ Construct the FullPathMapper object using a structure will all mobile sites occupied. A structure graph is generated by connecting all sites withing max_path_length distance of each other The sites are decorated with Migration graph objects and then grouped together based on their equivalence. Args: structure: Input structure that contains all sites. migrating_specie (Specie-like): The specie that migrates. E.g., "Li". max_path_length (float): Maximum length of NEB path in the unit of Angstrom. Defaults to None, which means you are setting the value to the min cutoff until finding 1D or >1D percolating paths. symprec (float): Symmetry precision to determine equivalence. """ self.structure = structure self.migrating_specie = get_el_sp(migrating_specie) self.max_path_length = max_path_length self.symprec = symprec self.name = name self.a = SpacegroupAnalyzer(self.structure, symprec=self.symprec) self.symm_structure = self.a.get_symmetrized_structure() self.only_sites = self.get_only_sites() if vac_mode: raise NotImplementedError self.vac_mode = vac_mode self.unique_hops = None # Generate the graph edges between these all the sites self.s_graph = StructureGraph.with_local_env_strategy( self.only_sites, MinimumDistanceNN(cutoff=max_path_length, get_all_sites=True), ) # weights in this graph are the distances self.s_graph.set_node_attributes() self.populate_edges_with_migration_paths() self.group_and_label_hops() self._populate_unique_hops_dict()
def compute_graph(self, index, cached=False, method="jmolnn"): if cached: s = self.reduced_structure_dict[ self.scalar_feature_matrix.iloc[index]["name"]] else: s = Structure.from_file( self.scalar_feature_matrix.iloc[index]["name"]) if method == "jmolnn": nn_strategy = JmolNN() elif method == "crystalgraph": nn_strategy = CrystalNN() else: nn_strategy = JmolNN() graph = StructureGraph.with_local_env_strategy(s, nn_strategy) return graph
def walk(struct, p, q, num_walks, walk_length): struct_graph = StructureGraph.with_local_env_strategy( struct, CrystalNN()) labels = {i: spec.name for i, spec in enumerate(struct.species)} G = nx.Graph(struct_graph.graph) G = nx.relabel_nodes(G, labels) for source, target in G.edges(): G[source][target]['weight'] = 1 n2v_G = Node2VecGraph(G, is_directed=False, p=p, q=q) n2v_G.preprocess_transition_probs() walks = n2v_G.simulate_walks(num_walks=num_walks, walk_length=walk_length, verbose=False) return walks
def test_extract_molecules(self): structure_file = os.path.join( PymatgenTest.TEST_FILES_DIR, "H6PbCI3N_mp-977013_symmetrized.cif", ) s = Structure.from_file(structure_file) nn = MinimumDistanceNN() sg = StructureGraph.with_local_env_strategy(s, nn) molecules = sg.get_subgraphs_as_molecules() self.assertEqual(molecules[0].composition.formula, "H3 C1") self.assertEqual(len(molecules), 1) molecules = self.mos2_sg.get_subgraphs_as_molecules() self.assertEqual(len(molecules), 0)
def test_properties(self): self.assertEqual(self.mos2_sg.name, "bonds") self.assertEqual(self.mos2_sg.edge_weight_name, "bond_length") self.assertEqual(self.mos2_sg.edge_weight_unit, "Å") self.assertEqual(self.mos2_sg.get_coordination_of_site(0), 6) self.assertEqual(len(self.mos2_sg.get_connected_sites(0)), 6) self.assertTrue( isinstance( self.mos2_sg.get_connected_sites(0)[0].site, PeriodicSite)) self.assertEqual( str(self.mos2_sg.get_connected_sites(0)[0].site.specie), "S") self.assertAlmostEqual( self.mos2_sg.get_connected_sites( 0, jimage=(0, 0, 100))[0].site.frac_coords[2], 100.303027, ) # these two graphs should be equivalent for n in range(len(self.bc_square_sg)): self.assertEqual( self.bc_square_sg.get_coordination_of_site(n), self.bc_square_sg_r.get_coordination_of_site(n), ) # test we're not getting duplicate connected sites # thanks to Jack D. Sundberg for reporting this bug # known example where this bug occurred due to edge weights not being # bit-for-bit identical in otherwise identical edges nacl_lattice = Lattice([ [3.48543625, 0.0, 2.01231756], [1.16181208, 3.28610081, 2.01231756], [0.0, 0.0, 4.02463512], ]) nacl = Structure(nacl_lattice, ["Na", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) nacl_graph = StructureGraph.with_local_env_strategy( nacl, CutOffDictNN({("Cl", "Cl"): 5.0})) self.assertEqual(len(nacl_graph.get_connected_sites(1)), 12) self.assertEqual(len(nacl_graph.graph.get_edge_data(1, 1)), 6)
def process_item(self, item): """ Calculates StructureGraphs (bonding information) for a material """ topology_docs = [] task_id = item['task_id'] structure = Structure.from_dict(item['structure']) self.logger.debug("Calculating bonding for {}".format(task_id)) # try all local_env strategies for strategy in self.strategies: method = strategy.__class__.__name__ # failure statistics are interesting try: topology_docs.append({ 'task_id': task_id, 'method': method, 'graph': StructureGraph.with_local_env_strategy( structure, strategy).as_dict(), 'successful': True }) except Exception as e: topology_docs.append({ 'task_id': task_id, 'method': method, 'successful': False, 'error_message': str(e) }) self.logger.warning(e) self.logger.warning("Failed to calculate bonding for {} using " "{} strategy.".format(task_id, method)) return topology_docs
def get_hash(structure: Structure, get_niggli=True): """ This gets hash, using the structure graph as a part of the has Args: structure: pymatgen structure object get_niggli (bool): Returns: """ if get_niggli: crystal = structure.get_reduced_structure() else: crystal = structure nn_strategy = JmolNN() sgraph_a = StructureGraph.with_local_env_strategy(crystal, nn_strategy) graph_hash = str(hash(sgraph_a.graph)) comp_hash = str(hash(str(crystal.symbol_set))) density_hash = str(hash(crystal.density)) return graph_hash + comp_hash + density_hash
def check_unbound(s: Structure, whitelist: list = ['H'], threshold: float = 2.5, mode='naive') -> bool: """ This uses the fact that unbound solvent is often in pores and more distant from all other atoms. So far this test focusses on water. Args: s (pymatgen structure object): structure to be checked whitelist (list): elements that are not considered in the check (they are basically removed from the structure) mode (str): checking mode. If 'naive' then a simple distance based check is used and a atom is detected as unbound it there is no other atom within the threshold distance. Returns: """ crystal = s.copy() if whitelist: crystal.remove_species(whitelist) if mode == 'naive': for atom in crystal: neighbors = crystal.get_neighbors(atom, threshold) if len(neighbors) == 0: return True return False if mode == 'graph': nn_strategy = JmolNN() sgraph = StructureGraph.with_local_env_strategy( crystal, nn_strategy) molecules = get_subgraphs_as_molecules_all(sgraph) if len(molecules) > 0: return True else: return False