def test_get_bond_distance_summary(self): """Test getting the bond distance summary""" sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_bond_distance_summary(0) self.assertEqual(len(data[2]), 6) self.assertAlmostEqual(data[2][0], 2.0922101061490546)
def test_init(self): """Test to check SiteDescriber can be initialised""" sa = SiteAnalyzer(self.tin_dioxide) self.assertNotEqual(sa, None, msg="tin dioxide site analyzer could not be init") # check different structure sa = SiteAnalyzer(self.ba_n) self.assertNotEqual(sa, None, msg="BaN2 site analyzer could not be initialized")
def test_connectivity_angle_summary(self): """Test getting the connectivity angle summary""" sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_connectivity_angle_summary(0) self.assertEqual(len(data[0]['corner']), 8) self.assertEqual(len(data[0]['edge']), 4) self.assertAlmostEqual(data[0]['edge'][0], 101.62287790513848)
def test_nnn_distance_summary(self): """Test getting the nnn distance summary""" sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_nnn_distance_summary(0) self.assertEqual(len(data[0]['corner']), 8) self.assertEqual(len(data[0]['edge']), 2) self.assertAlmostEqual(data[0]['edge'][0], 3.24322132)
def test_geometries_match(self): """Test geometry matching function.""" sa = SiteAnalyzer(self.tin_dioxide, use_symmetry_equivalent_sites=False) geom_a = sa.get_site_geometry(0) geom_b = sa.get_site_geometry(1) geom_c = sa.get_site_geometry(4) self.assertTrue(geometries_match(geom_a, geom_b)) self.assertFalse(geometries_match(geom_a, geom_c))
def test_get_site_summary(self): """Test getting the site summary""" sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_site_summary(0) self.assertEqual(data["element"], "Sn4+") self.assertEqual(data["geometry"]["type"], "octahedral") self.assertAlmostEqual(data["geometry"]["likeness"], 0.9349776258427136) self.assertEqual(len(data["nn"]), 6) self.assertEqual(len(data["nnn"]["corner"]), 8) self.assertEqual(len(data["nnn"]["edge"]), 2) self.assertEqual(data["poly_formula"], "O6") self.assertEqual(data["sym_labels"], (1,))
def test_equivalent_sites(self): """Check equivalent sites instance variable set correctly.""" sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=False) self.assertEqual(sa.equivalent_sites, [0, 0, 0, 0, 4, 4]) # test using symmetry to determine equivalent sites sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=True) self.assertIsInstance(sa.equivalent_sites, list) self.assertEqual(sa.equivalent_sites, [0, 0, 0, 0, 4, 4]) # test symprec option works sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=True, symprec=0.0001) self.assertEqual(sa.equivalent_sites, [0, 1, 1, 0, 4, 4])
def test_get_site_summary(self): """Test getting the site summary""" sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_site_summary(0) self.assertEqual(data['element'], 'Sn4+') self.assertEqual(data['geometry']['type'], 'octahedral') self.assertAlmostEqual(data['geometry']['likeness'], 0.9349776258427136) self.assertEqual(len(data['nn']), 6) self.assertEqual(len(data['nnn']['corner']), 8) self.assertEqual(len(data['nnn']['edge']), 2) self.assertEqual(data['poly_formula'], 'O6') self.assertEqual(data['sym_labels'], (1, ))
def test_get_next_nearest_neighbors(self): """Check getting next nearest neighbors.""" sa = SiteAnalyzer(self.tin_dioxide) info = sa.get_next_nearest_neighbors(5) self.assertEqual(len(info), 14) self.assertEqual(info[0]["element"], "O2-") self.assertEqual(info[0]["connectivity"], "edge") self.assertEqual(info[0]["geometry"]["type"], "trigonal planar") self.assertEqual(info[0]["inequiv_index"], 2) info = sa.get_next_nearest_neighbors(0, inc_inequivalent_site_index=False) self.assertTrue('inequiv_index' not in info[0]) info = sa.get_next_nearest_neighbors(0) self.assertEqual(info[0]["element"], 'Sn4+') self.assertEqual(info[0]["connectivity"], "edge") self.assertEqual(info[0]["geometry"]["type"], "octahedral") self.assertEqual(len(info[0]['angles']), 2) self.assertAlmostEqual(info[0]['angles'][0], 101.62287790513848) # check different structure without oxi state sa = SiteAnalyzer(self.ba_n) info = sa.get_next_nearest_neighbors(0) self.assertEqual(len(info), 36) self.assertEqual(info[5]["element"], "N") self.assertEqual(info[5]["connectivity"], "edge") self.assertEqual(info[5]["geometry"]["type"], "6-coordinate") self.assertEqual(len(info[5]['angles']), 2) self.assertAlmostEqual(info[5]['angles'][0], 83.91397867959587)
def test_get_next_nearest_neighbors(self): """Check getting next nearest neighbors.""" sa = SiteAnalyzer(self.tin_dioxide) info = sa.get_next_nearest_neighbors(5) self.assertEqual(len(info), 14) idx = [i for i, s in enumerate(info) if s["connectivity"] == "edge"][0] self.assertEqual(info[idx]["element"], "O2-") self.assertEqual(info[idx]["connectivity"], "edge") self.assertEqual(info[idx]["geometry"]["type"], "trigonal planar") self.assertEqual(info[idx]["inequiv_index"], 2) info = sa.get_next_nearest_neighbors(0, inc_inequivalent_site_index=False) self.assertTrue("inequiv_index" not in info[0]) info = sa.get_next_nearest_neighbors(0) self.assertEqual(info[0]["element"], "Sn4+") self.assertEqual(info[0]["connectivity"], "edge") self.assertEqual(info[0]["geometry"]["type"], "octahedral") self.assertEqual(len(info[0]["angles"]), 2) self.assertAlmostEqual(info[0]["angles"][0], 101.62287790513848) self.assertAlmostEqual(info[0]["distance"], 3.24322132) # check different structure without oxi state sa = SiteAnalyzer(self.ba_n) info = sa.get_next_nearest_neighbors(0) self.assertEqual(len(info), 36) self.assertEqual(info[5]["element"], "N") self.assertEqual(info[5]["connectivity"], "edge") self.assertEqual(info[5]["geometry"]["type"], "6-coordinate") self.assertEqual(len(info[5]["angles"]), 2) self.assertAlmostEqual(info[5]["angles"][0], 83.91397867959587) self.assertAlmostEqual(info[5]["distance"], 3.549136232944574)
def test_nnn_summaries_match(self): """Test nearest neighbour summary matching function.""" sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=True) nnn_a = sa.get_next_nearest_neighbors(0) nnn_b = sa.get_next_nearest_neighbors(3) nnn_c = sa.get_next_nearest_neighbors(4) self.assertTrue(nnn_summaries_match(nnn_a, nnn_b)) self.assertFalse(nnn_summaries_match(nnn_a, nnn_c)) # test not matching bond angles self.assertTrue( nnn_summaries_match(nnn_a, nnn_b, bond_angle_tol=1e-10, match_bond_angles=False))
def test_get_inequivalent_site_indices(self): sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=False) inequiv_indices = sa.get_inequivalent_site_indices(list(range(6))) self.assertEqual(inequiv_indices, [0, 0, 0, 0, 4, 4]) # test using symmetry to determine inequivalent sites. sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=True) inequiv_indices = sa.get_inequivalent_site_indices(list(range(6))) self.assertEqual(inequiv_indices, [0, 0, 0, 0, 4, 4]) # test symprec option sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=True, symprec=0.000001) inequiv_indices = sa.get_inequivalent_site_indices(list(range(6))) self.assertEqual(inequiv_indices, [0, 1, 1, 0, 4, 4])
def test_get_site_geometry(self): """Test site geometry description.""" sa = SiteAnalyzer(self.tin_dioxide) geom_data = sa.get_site_geometry(0) self.assertEqual(geom_data['type'], "octahedral") self.assertAlmostEqual(geom_data['likeness'], 0.9349776258427136) geom_data = sa.get_site_geometry(4) self.assertEqual(geom_data['type'], "trigonal planar") self.assertAlmostEqual(geom_data['likeness'], 0.6050243049545359) # check different structure sa = SiteAnalyzer(self.ba_n) geom_data = sa.get_site_geometry(0) self.assertEqual(geom_data['type'], "6-coordinate") self.assertAlmostEqual(geom_data['likeness'], 1)
def test_get_nearest_neighbors(self): """Check getting nearest neighbors.""" sa = SiteAnalyzer(self.tin_dioxide) info = sa.get_nearest_neighbors(4) self.assertEqual(len(info), 3) self.assertEqual(info[0]["element"], "Sn4+") self.assertEqual(info[0]["inequiv_index"], 0) self.assertAlmostEqual(info[0]["dist"], 2.0922101061490546) info = sa.get_nearest_neighbors(0, inc_inequivalent_site_index=False) self.assertTrue('inequiv_index' not in info[0]) # check different structure without oxi state sa = SiteAnalyzer(self.ba_n) info = sa.get_nearest_neighbors(0) self.assertEqual(len(info), 6) self.assertEqual(info[0]["element"], "N") self.assertEqual(info[0]["inequiv_index"], 0) self.assertAlmostEqual(info[0]["dist"], 1.2619877178483)
def test_symmetry_labels(self): """Check equivalent sites instance variable set correctly.""" sa = SiteAnalyzer(self.ba_n, use_symmetry_equivalent_sites=False) self.assertEqual(sa.symmetry_labels, [1, 1, 1, 1, 1, 1])
def test_get_all_connectivity_angle_summaries(self): sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_all_connectivity_angle_summaries() self.assertEqual(len(data[0][0]['corner']), 8) self.assertEqual(len(data[0][0]['edge']), 4) self.assertAlmostEqual(data[0][0]['edge'][0], 101.62287790513848)
def test_get_all_bond_distance_summaries(self): sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_all_bond_distance_summaries() self.assertEqual(len(data[0][2]), 6) self.assertEqual(len(data[2][0]), 3) self.assertAlmostEqual(data[0][2][0], 2.0922101061490546)
def condense_structure(self, structure: Structure) -> Dict[str, Any]: """Condenses the structure into an intermediate dict representation. Args: structure: A pymatgen structure object. Returns: The condensed structure information. The data is formatted as a :obj:`dict` with a fixed set of keys. An up-to-date example of the, the condensed representation of MoS2 given in the documentation. See: ``robocrystallographer/docs_rst/source/format.rst`` or https://hackingmaterials.lbl.gov/robocrystallographer/format.html """ # sort so we can give proper symmetry labels structure = structure.get_sorted_structure() # wrap all site coords into unit cell structure.translate_sites(range(structure.num_sites), [1, 1, 1]) sga = SpacegroupAnalyzer(structure, symprec=self.symprec) if self.use_conventional_cell: structure = sga.get_conventional_standard_structure() else: structure = sga.get_symmetrized_structure() bonded_structure = self.near_neighbors.get_bonded_structure(structure) components = get_structure_components( bonded_structure, inc_orientation=True, inc_site_ids=True, inc_molecule_graph=True, ) dimensionality = max(c["dimensionality"] for c in components) mineral = self._condense_mineral(structure, components) formula = self._condense_formula(structure, components) structure_data = { "formula": formula, "spg_symbol": sga.get_space_group_symbol(), "crystal_system": sga.get_crystal_system(), "mineral": mineral, "dimensionality": dimensionality, } site_analyzer = SiteAnalyzer( bonded_structure, symprec=self.symprec, use_symmetry_equivalent_sites=self.use_symmetry_equivalent_sites, ) structure_data["sites"] = site_analyzer.get_all_site_summaries() structure_data[ "distances"] = site_analyzer.get_all_bond_distance_summaries() structure_data[ "angles"] = site_analyzer.get_all_connectivity_angle_summaries() structure_data[ "nnn_distances"] = site_analyzer.get_all_nnn_distance_summaries() component_summary, component_makeup = self._condense_components( components, sga, site_analyzer) structure_data["components"] = component_summary structure_data["component_makeup"] = component_makeup if components_are_vdw_heterostructure(components): hs_info = get_vdw_heterostructure_information( components, use_iupac_formula=self.use_iupac_formula, use_common_formulas=self.use_common_formulas, ) else: hs_info = None structure_data["vdw_heterostructure_info"] = hs_info return structure_data
def _condense_components( self, components: List[Component], spacegroup_analyzer: SpacegroupAnalyzer, site_analyzer: SiteAnalyzer, ) -> Tuple[Dict[int, Any], List[int]]: """Condenses the component data. Args: components: A list of structure components, generated using :obj:`pymatgen.analysis.dimensionality.get_structure_components` site_analyzer: A site analyzer object for the structure containing the components. spacegroup_analyzer: A space group analyzer object for the structure containing the components. Returns: The condensed component data and the component makeup of the structure. The condensed components have the form:: { 0: { 'formula': 'MoS2', 'sites': [0, 2] 'dimensionality': 2, 'molecule_name': None, 'orientation': (0, 0, 1) } } Where the ``0`` key is the component identifier. The ``sites`` key gives a :obj:`list` of the indexes of the inequivalent sites in the structure. If the component is zero-dimensional and is a known molecule, the ``molecule_name`` key will be a :obj:`str` with the molecule name. The ``orientation`` key is the miller index (for two-dimensional components) or direction of propagation (for one-dimensional components). """ if self.use_symmetry_equivalent_sites: inequiv_components = get_sym_inequiv_components( components, spacegroup_analyzer) else: inequiv_components = get_structure_inequiv_components(components) molecule_namer = MoleculeNamer() components = {} component_makeup = [] for i, component in enumerate(inequiv_components): formula = get_component_formula( component, use_iupac_formula=self.use_iupac_formula, use_common_formulas=self.use_common_formulas, ) sites = site_analyzer.get_inequivalent_site_indices( component["site_ids"]) if component["dimensionality"] == 0: molecule_name = molecule_namer.get_name_from_molecule_graph( component["molecule_graph"]) else: molecule_name = None components[i] = { "formula": formula, "dimensionality": component["dimensionality"], "orientation": component["orientation"], "molecule_name": molecule_name, "sites": sites, } component_makeup.extend([i] * component["count"]) return components, component_makeup
def test_get_all_nnn_distance_summaries(self): sa = SiteAnalyzer(self.tin_dioxide) data = sa.get_all_nnn_distance_summaries() self.assertEqual(len(data[0][0]['corner']), 8) self.assertEqual(len(data[0][0]['edge']), 2) self.assertAlmostEqual(data[0][0]['edge'][0], 3.24322132)