def test_pbc_all_distances(self): fcoords = np.array([[0.3, 0.3, 0.5], [0.1, 0.1, 0.3], [0.9, 0.9, 0.8], [0.1, 0.0, 0.5], [0.9, 0.7, 0.0]]) lattice = Lattice.from_lengths_and_angles([8, 8, 4], [90, 76, 58]) expected = np.array([[0.000, 3.015, 4.072, 3.519, 3.245], [3.015, 0.000, 3.207, 1.131, 4.453], [4.072, 3.207, 0.000, 2.251, 1.788], [3.519, 1.131, 2.251, 0.000, 3.852], [3.245, 4.453, 1.788, 3.852, 0.000]]) output = pbc_all_distances(lattice, fcoords, fcoords) self.assertArrayAlmostEqual(output, expected, 3) #test just one input point output2 = pbc_all_distances(lattice, fcoords[0], fcoords) self.assertArrayAlmostEqual(output2, [expected[0]], 2) #test distance when initial points are not in unit cell f1 = [0, 0, 17] f2 = [0, 0, 10] self.assertEqual(pbc_all_distances(lattice, f1, f2)[0, 0], 0)
def test_subset(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=False, allow_subset=True) l = Lattice.orthorhombic(10, 20, 30) s1 = Structure(l, ['Si', 'Si', 'Ag'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s2 = Structure(l, ['Si', 'Ag'], [[0,0.1,0],[-.7,.5,.4]]) result = sm.get_s2_like_s1(s1, s2) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.1])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.7,0.4,0.5])), 1) #test with fewer species in s2 s1 = Structure(l, ['Si', 'Ag', 'Si'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s2 = Structure(l, ['Si', 'Si'], [[0,0.1,0],[-.7,.5,.4]]) result = sm.get_s2_like_s1(s1, s2) mindists = np.min(pbc_all_distances(s1.lattice, s1.frac_coords, result.frac_coords), axis=0) self.assertLess(np.max(mindists), 1e-6) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.1])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.7,0.4,0.5])), 1) #test with not enough sites in s1 #test with fewer species in s2 s1 = Structure(l, ['Si', 'Ag', 'Cl'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s2 = Structure(l, ['Si', 'Si'], [[0,0.1,0],[-.7,.5,.4]]) self.assertEqual(sm.get_s2_like_s1(s1, s2), None)
def parse_oxide(self): """ Determines if an oxide is a peroxide/superoxide/ozonide/normal oxide Returns: oxide_type: Type of oxide - ozonide/peroxide/superoxide/hydroxide/None nbonds: Number of peroxide/superoxide/hydroxide bonds in structure """ structure = self.structure relative_cutoff = self.relative_cutoff o_sites_frac_coords = [] h_sites_frac_coords = [] lattice = structure.lattice if isinstance(structure.composition.elements[0], Element): comp = structure.composition elif isinstance(structure.composition.elements[0], Specie): elmap = collections.defaultdict(float) for site in structure: for species, occu in site.species_and_occu.items(): elmap[species.element] += occu comp = Composition(elmap) if Element("O") not in comp or comp.is_element: return "None", 0 for site in structure: syms = [sp.symbol for sp in site.species_and_occu.keys()] if "O" in syms: o_sites_frac_coords.append(site.frac_coords) if "H" in syms: h_sites_frac_coords.append(site.frac_coords) if h_sites_frac_coords: dist_matrix = pbc_all_distances(lattice, o_sites_frac_coords, h_sites_frac_coords) if np.any(dist_matrix < relative_cutoff * 0.93): return "hydroxide", len( np.where(dist_matrix < relative_cutoff * 0.93)[0]) / 2.0 dist_matrix = pbc_all_distances(lattice, o_sites_frac_coords, o_sites_frac_coords) np.fill_diagonal(dist_matrix, 1000) is_superoxide = False is_peroxide = False is_ozonide = False if np.any(dist_matrix < relative_cutoff * 1.35): bond_atoms = np.where(dist_matrix < relative_cutoff * 1.35)[0] is_superoxide = True elif np.any(dist_matrix < relative_cutoff * 1.49): is_peroxide = True bond_atoms = np.where(dist_matrix < relative_cutoff * 1.49)[0] if is_superoxide: if len(bond_atoms) > len(set(bond_atoms)): is_superoxide = False is_ozonide = True try: nbonds = len(set(bond_atoms)) except UnboundLocalError: nbonds = 0.0 if is_ozonide: str_oxide = "ozonide" elif is_superoxide: str_oxide = "superoxide" elif is_peroxide: str_oxide = "peroxide" else: str_oxide = "oxide" return str_oxide, nbonds
def parse_oxide(self): """ Determines if an oxide is a peroxide/superoxide/ozonide/normal oxide Returns: oxide_type: Type of oxide - ozonide/peroxide/superoxide/hydroxide/None nbonds: Number of peroxide/superoxide/hydroxide bonds in structure """ structure = self.structure relative_cutoff = self.relative_cutoff o_sites_frac_coords = [] h_sites_frac_coords = [] lattice = structure.lattice if isinstance(structure.composition.elements[0], Element): comp = structure.composition elif isinstance(structure.composition.elements[0], Specie): elmap = collections.defaultdict(float) for site in structure: for species, occu in site.species_and_occu.items(): elmap[species.element] += occu comp = Composition(elmap) if Element("O") not in comp or comp.is_element: return "None", 0 for site in structure: syms = [sp. symbol for sp in site.species_and_occu.keys()] if "O" in syms: o_sites_frac_coords.append(site.frac_coords) if "H" in syms: h_sites_frac_coords.append(site.frac_coords) if h_sites_frac_coords: dist_matrix = pbc_all_distances(lattice, o_sites_frac_coords, h_sites_frac_coords) if np.any(dist_matrix < relative_cutoff * 0.93): return "hydroxide", len(np.where(dist_matrix < relative_cutoff * 0.93)[0]) / 2.0 dist_matrix = pbc_all_distances(lattice, o_sites_frac_coords, o_sites_frac_coords) np.fill_diagonal(dist_matrix, 1000) is_superoxide = False is_peroxide = False is_ozonide = False if np.any(dist_matrix < relative_cutoff * 1.35): bond_atoms = np.where(dist_matrix < relative_cutoff * 1.35)[0] is_superoxide = True elif np.any(dist_matrix < relative_cutoff * 1.49): is_peroxide = True bond_atoms = np.where(dist_matrix < relative_cutoff * 1.49)[0] if is_superoxide: if len(bond_atoms) > len(set(bond_atoms)): is_superoxide = False is_ozonide = True try: nbonds = len(set(bond_atoms)) except UnboundLocalError: nbonds = 0.0 if is_ozonide: str_oxide = "ozonide" elif is_superoxide: str_oxide = "superoxide" elif is_peroxide: str_oxide = "peroxide" else: str_oxide = "oxide" return str_oxide, nbonds
def oxide_type(structure, relative_cutoff=1.2): """ Determines if an oxide is a peroxide/superoxide/ozonide/normal oxide Args: structure: Input structure. relative_cutoff: Relative_cutoff * act. cutoff stipulates the max. distance two O atoms must be from each other. """ o_sites_frac_coords = [] h_sites_frac_coords = [] lattice = structure.lattice # Check if H2O/O2/H2O2/non-oxide is being checked el_other_than_OH = [el.symbol for el in structure.composition.elements if el.symbol not in ["H", "O"]] if (not el_other_than_OH) | (len(el_other_than_OH) == len(structure.composition.elements)): return "None" for site in structure: syms = [sp. symbol for sp in site.species_and_occu.keys()] if "O" in syms: o_sites_frac_coords.append(site.frac_coords) if "H" in syms: h_sites_frac_coords.append(site.frac_coords) # We are not correcting hydrides if not o_sites_frac_coords: return "None" if h_sites_frac_coords: dist_matrix = pbc_all_distances(lattice, o_sites_frac_coords, h_sites_frac_coords) if np.any(dist_matrix < relative_cutoff * 0.93): return "hydroxide" dist_matrix = pbc_all_distances(lattice, o_sites_frac_coords, o_sites_frac_coords) np.fill_diagonal(dist_matrix, 1000) is_superoxide = False is_peroxide = False is_ozonide = False if np.any(dist_matrix < relative_cutoff * 1.35): is_superoxide = True elif np.any(dist_matrix < relative_cutoff * 1.49): is_peroxide = True if is_superoxide: if (int(structure.composition["O"] / structure.composition.get_reduced_composition_and_factor()[1]) % 3 == 0): sum = 0 for elt in [el for el in structure.composition.elements if el is not Element("O")]: sum += structure.composition[elt.symbol] if sum / structure.composition.get_reduced_composition_and_factor()[1] <= 1: is_superoxide = False is_ozonide = True if is_ozonide: return "ozonide" elif is_superoxide: return "superoxide" elif is_peroxide: return "peroxide" else: return "oxide"