Example #1
0
class JMolNNTest(PymatgenTest):
    def setUp(self):
        self.jmol = JMolNN()
        self.jmol_update = JMolNN(el_radius_updates={"Li": 1})

    def test_get_nn(self):
        s = self.get_structure('LiFePO4')

        # Test the default near-neighbor finder.
        nsites_checked = 0

        for site_idx, site in enumerate(s):
            if site.specie == Element("Li"):
                self.assertEqual(self.jmol.get_cn(s, site_idx), 0)
                nsites_checked += 1
            elif site.specie == Element("Fe"):
                self.assertEqual(self.jmol.get_cn(s, site_idx), 6)
                nsites_checked += 1
            elif site.specie == Element("P"):
                self.assertEqual(self.jmol.get_cn(s, site_idx), 4)
                nsites_checked += 1
        self.assertEqual(nsites_checked, 12)

        # Test a user override that would cause Li to show up as 6-coordinated
        self.assertEqual(self.jmol_update.get_cn(s, 0), 6)

        # Verify get_nn function works
        self.assertEqual(len(self.jmol_update.get_nn(s, 0)), 6)

    def tearDown(self):
        del self.jmol
        del self.jmol_update
Example #2
0
class JMolNNTest(PymatgenTest):

    def setUp(self):
        self.jmol = JMolNN()
        self.jmol_update = JMolNN(el_radius_updates={"Li": 1})

    def test_get_nn(self):
        s = self.get_structure('LiFePO4')

        # Test the default near-neighbor finder.
        nsites_checked = 0

        for site_idx, site in enumerate(s):
            if site.specie == Element("Li"):
                self.assertEqual(self.jmol.get_cn(s, site_idx), 0)
                nsites_checked += 1
            elif site.specie == Element("Fe"):
                self.assertEqual(self.jmol.get_cn(s, site_idx), 6)
                nsites_checked += 1
            elif site.specie == Element("P"):
                self.assertEqual(self.jmol.get_cn(s, site_idx), 4)
                nsites_checked += 1
        self.assertEqual(nsites_checked, 12)

        # Test a user override that would cause Li to show up as 6-coordinated
        self.assertEqual(self.jmol_update.get_cn(s, 0), 6)

        # Verify get_nn function works
        self.assertEqual(len(self.jmol_update.get_nn(s, 0)), 6)

    def tearDown(self):
        del self.jmol
        del self.jmol_update
Example #3
0
 def test_cns(self):
     cnv = CoordinationNumber.from_preset('VoronoiNN')
     self.assertEqual(len(cnv.feature_labels()), 1)
     self.assertEqual(cnv.feature_labels()[0], 'CN_VoronoiNN')
     self.assertAlmostEqual(cnv.featurize(self.sc, 0)[0], 6)
     self.assertAlmostEqual(cnv.featurize(self.cscl, 0)[0], 14)
     self.assertAlmostEqual(cnv.featurize(self.cscl, 1)[0], 14)
     self.assertEqual(len(cnv.citations()), 2)
     cnv = CoordinationNumber(VoronoiNN(), use_weights='sum')
     self.assertEqual(cnv.feature_labels()[0], 'CN_VoronoiNN')
     self.assertAlmostEqual(cnv.featurize(self.cscl, 0)[0], 9.2584516)
     self.assertAlmostEqual(cnv.featurize(self.cscl, 1)[0], 9.2584516)
     self.assertEqual(len(cnv.citations()), 2)
     cnv = CoordinationNumber(VoronoiNN(), use_weights='effective')
     self.assertEqual(cnv.feature_labels()[0], 'CN_VoronoiNN')
     self.assertAlmostEqual(cnv.featurize(self.cscl, 0)[0], 11.648923254)
     self.assertAlmostEqual(cnv.featurize(self.cscl, 1)[0], 11.648923254)
     self.assertEqual(len(cnv.citations()), 2)
     cnj = CoordinationNumber.from_preset('JMolNN')
     self.assertEqual(cnj.feature_labels()[0], 'CN_JMolNN')
     self.assertAlmostEqual(cnj.featurize(self.sc, 0)[0], 0)
     self.assertAlmostEqual(cnj.featurize(self.cscl, 0)[0], 0)
     self.assertAlmostEqual(cnj.featurize(self.cscl, 1)[0], 0)
     self.assertEqual(len(cnj.citations()), 1)
     jmnn = JMolNN(el_radius_updates={"Al": 1.55, "Cl": 1.7, "Cs": 1.7})
     cnj = CoordinationNumber(jmnn)
     self.assertEqual(cnj.feature_labels()[0], 'CN_JMolNN')
     self.assertAlmostEqual(cnj.featurize(self.sc, 0)[0], 6)
     self.assertAlmostEqual(cnj.featurize(self.cscl, 0)[0], 8)
     self.assertAlmostEqual(cnj.featurize(self.cscl, 1)[0], 8)
     self.assertEqual(len(cnj.citations()), 1)
     cnmd = CoordinationNumber.from_preset('MinimumDistanceNN')
     self.assertEqual(cnmd.feature_labels()[0], 'CN_MinimumDistanceNN')
     self.assertAlmostEqual(cnmd.featurize(self.sc, 0)[0], 6)
     self.assertAlmostEqual(cnmd.featurize(self.cscl, 0)[0], 8)
     self.assertAlmostEqual(cnmd.featurize(self.cscl, 1)[0], 8)
     self.assertEqual(len(cnmd.citations()), 1)
     cnmok = CoordinationNumber.from_preset('MinimumOKeeffeNN')
     self.assertEqual(cnmok.feature_labels()[0], 'CN_MinimumOKeeffeNN')
     self.assertAlmostEqual(cnmok.featurize(self.sc, 0)[0], 6)
     self.assertAlmostEqual(cnmok.featurize(self.cscl, 0)[0], 8)
     self.assertAlmostEqual(cnmok.featurize(self.cscl, 1)[0], 6)
     self.assertEqual(len(cnmok.citations()), 2)
     cnmvire = CoordinationNumber.from_preset('MinimumVIRENN')
     self.assertEqual(cnmvire.feature_labels()[0], 'CN_MinimumVIRENN')
     self.assertAlmostEqual(cnmvire.featurize(self.sc, 0)[0], 6)
     self.assertAlmostEqual(cnmvire.featurize(self.cscl, 0)[0], 8)
     self.assertAlmostEqual(cnmvire.featurize(self.cscl, 1)[0], 14)
     self.assertEqual(len(cnmvire.citations()), 2)
     self.assertEqual(len(cnmvire.implementors()), 2)
     self.assertEqual(cnmvire.implementors()[0], 'Nils E. R. Zimmermann')
Example #4
0
def get_max_bond_lengths(structure, el_radius_updates=None):
    """
    Provides max bond length estimates for a structure based on the JMol
    table and algorithms.
    
    Args:
        structure: (structure)
        el_radius_updates: (dict) symbol->float to update atomic radii
    
    Returns: (dict) - (Element1, Element2) -> float. The two elements are 
        ordered by Z.
    """
    #jmc = JMolCoordFinder(el_radius_updates)
    jmnn = JMolNN(el_radius_updates)

    bonds_lens = {}
    els = sorted(structure.composition.elements, key=lambda x: x.Z)

    for i1 in range(len(els)):
        for i2 in range(len(els) - i1):
            bonds_lens[els[i1], els[i1 + i2]] = jmnn.get_max_bond_distance(
                els[i1].symbol, els[i1 + i2].symbol)

    return bonds_lens
Example #5
0
def get_max_bond_lengths(structure, el_radius_updates=None):
    """
    Provides max bond length estimates for a structure based on the JMol
    table and algorithms.
    
    Args:
        structure: (structure)
        el_radius_updates: (dict) symbol->float to update atomic radii
    
    Returns: (dict) - (Element1, Element2) -> float. The two elements are 
        ordered by Z.
    """
    #jmc = JMolCoordFinder(el_radius_updates)
    jmnn = JMolNN(el_radius_updates)

    bonds_lens = {}
    els = sorted(structure.composition.elements, key=lambda x: x.Z)

    for i1 in range(len(els)):
        for i2 in range(len(els) - i1):
            bonds_lens[els[i1], els[i1 + i2]] = jmnn.get_max_bond_distance(
                els[i1].symbol, els[i1 + i2].symbol)

    return bonds_lens
Example #6
0
def find_connected_atoms(struct, tolerance=0.45, ldict=JMolNN().el_radius):
    """
	Finds the list of bonded atoms.

	Args:
		struct (Structure): Input structure
		tolerance: length in angstroms used in finding bonded atoms. Two atoms are considered bonded if (radius of atom 1) + (radius of atom 2) + (tolerance) < (distance between atoms 1 and 2). Default value = 0.45, the value used by JMol and Cheon et al.
		ldict: dictionary of bond lengths used in finding bonded atoms. Values from JMol are used as default
		standardize: works with conventional standard structures if True. It is recommended to keep this as True.

	Returns:
		connected_list: A numpy array of shape (number of bonded pairs, 2); each row of is of the form [atomi, atomj].
		atomi and atomj are the indices of the atoms in the input structure.
		If any image of atomj is bonded to atomi with periodic boundary conditions, [atomi, atomj] is included in the list.
		If atomi is bonded to multiple images of atomj, it is only counted once.
	"""
    n_atoms = len(struct.species)
    fc = np.array(struct.frac_coords)
    species = list(map(str, struct.species))
    #in case of charged species
    for i, item in enumerate(species):
        if not item in ldict.keys():
            species[i] = str(Specie.from_string(item).element)
    latmat = struct.lattice.matrix
    connected_list = []

    for i in range(n_atoms):
        for j in range(i + 1, n_atoms):
            max_bond_length = ldict[species[i]] + ldict[species[j]] + tolerance
            add_ij = False
            for move_cell in itertools.product([0, 1, -1], [0, 1, -1],
                                               [0, 1, -1]):
                if not add_ij:
                    frac_diff = fc[j] + move_cell - fc[i]
                    distance_ij = np.dot(latmat.T, frac_diff)
                    if np.linalg.norm(distance_ij) < max_bond_length:
                        add_ij = True
            if add_ij:
                connected_list.append([i, j])
    return np.array(connected_list)
Example #7
0
 def setUp(self):
     self.jmol = JMolNN()
     self.jmol_update = JMolNN(el_radius_updates={"Li": 1})
Example #8
0
def find_dimension(structure_raw,
                   tolerance=0.45,
                   ldict=JMolNN().el_radius,
                   standardize=True):
    """
	Algorithm for finding the dimensions of connected subunits in a crystal structure.
	This method finds the dimensionality of the material even when the material is not layered along low-index planes, or does not have flat layers/molecular wires.
	See details at : Cheon, G.; Duerloo, K.-A. N.; Sendek, A. D.; Porter, C.; Chen, Y.; Reed, E. J. Data Mining for New Two- and One-Dimensional Weakly Bonded Solids and Lattice-Commensurate Heterostructures. Nano Lett. 2017.

	Args:
		structure (Structure): Input structure
		tolerance: length in angstroms used in finding bonded atoms. Two atoms are considered bonded if (radius of atom 1) + (radius of atom 2) + (tolerance) < (distance between atoms 1 and 2). Default value = 0.45, the value used by JMol and Cheon et al.
		ldict: dictionary of bond lengths used in finding bonded atoms. Values from JMol are used as default
		standardize: works with conventional standard structures if True. It is recommended to keep this as True.

	Returns:
		dim: dimension of the largest cluster as a string. If there are ions or molecules it returns 'intercalated ion/molecule'
	"""
    if standardize:
        structure = SpacegroupAnalyzer(
            structure_raw).get_conventional_standard_structure()
    structure_save = copy.copy(structure_raw)
    connected_list1 = find_connected_atoms(structure,
                                           tolerance=tolerance,
                                           ldict=ldict)
    max1, min1, clusters1 = find_clusters(structure, connected_list1)
    structure.make_supercell([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
    connected_list2 = find_connected_atoms(structure,
                                           tolerance=tolerance,
                                           ldict=ldict)
    max2, min2, clusters2 = find_clusters(structure, connected_list2)
    if min2 == 1:
        dim = 'intercalated ion'
    elif min2 == min1:
        if max2 == max1:
            dim = '0D'
        else:
            dim = 'intercalated molecule'
    else:
        dim = np.log2(float(max2) / max1)
        if dim == int(dim):
            dim = str(int(dim)) + 'D'
        else:
            structure = copy.copy(structure_save)
            structure.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 3]])
            connected_list3 = find_connected_atoms(structure,
                                                   tolerance=tolerance,
                                                   ldict=ldict)
            max3, min3, clusters3 = find_clusters(structure, connected_list3)
            if min3 == min2:
                if max3 == max2:
                    dim = '0D'
                else:
                    dim = 'intercalated molecule'
            else:
                dim = np.log2(float(max3) / max1) / np.log2(3)
                if dim == int(dim):
                    dim = str(int(dim)) + 'D'
                else:
                    return
    return dim
Example #9
0
 def setUp(self):
     self.jmol = JMolNN()
     self.jmol_update = JMolNN(el_radius_updates={"Li": 1})