Пример #1
0
    def test_no_scaling(self):
        sm = StructureMatcher(ltol=0.1, stol=0.1, angle_tol=2,
                              scale=False, comparator=ElementComparator())
        self.assertTrue(sm.fit(self.struct_list[0], self.struct_list[1]))

        self.assertTrue(sm.get_rms_dist(self.struct_list[0],
                                        self.struct_list[1])[0] < 0.0008)
Пример #2
0
def _perform_grouping(args):
    (entries_json, hosts_json, ltol, stol, angle_tol,
     primitive_cell, scale, comparator, groups) = args

    entries = json.loads(entries_json, cls=MontyDecoder)
    hosts = json.loads(hosts_json, cls=MontyDecoder)
    unmatched = list(zip(entries, hosts))
    while len(unmatched) > 0:
        ref_host = unmatched[0][1]
        logger.info(
            "Reference tid = {}, formula = {}".format(unmatched[0][0].entry_id,
                                                      ref_host.formula)
        )
        ref_formula = ref_host.composition.reduced_formula
        logger.info("Reference host = {}".format(ref_formula))
        matches = [unmatched[0]]
        for i in range(1, len(unmatched)):
            test_host = unmatched[i][1]
            logger.info("Testing tid = {}, formula = {}"
                        .format(unmatched[i][0].entry_id, test_host.formula))
            test_formula = test_host.composition.reduced_formula
            logger.info("Test host = {}".format(test_formula))
            m = StructureMatcher(ltol=ltol, stol=stol, angle_tol=angle_tol,
                                 primitive_cell=primitive_cell, scale=scale,
                                 comparator=comparator)
            if m.fit(ref_host, test_host):
                logger.info("Fit found")
                matches.append(unmatched[i])
        groups.append(json.dumps([m[0] for m in matches], cls=MontyEncoder))
        unmatched = list(filter(lambda x: x not in matches, unmatched))
        logger.info("{} unmatched remaining".format(len(unmatched)))
Пример #3
0
    def _match_material(self, doc):
        """
        Returns the material_id that has the same structure as this doc as
         determined by the structure matcher. Returns None if no match.

        Args:
            doc: a JSON-like document

        Returns:
            (int) matching material_id or None
        """
        formula = doc["formula_reduced_abc"]
        sgnum = doc["spacegroup"]["number"]

        for m in self._materials.find({"formula_reduced_abc": formula, "sg_number": sgnum},
                                      {"structure": 1, "material_id": 1}):

            m_struct = Structure.from_dict(m["structure"])
            t_struct = Structure.from_dict(doc["structure"])

            sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                                  primitive_cell=True, scale=True,
                                  attempt_supercell=False, allow_subset=False,
                                  comparator=ElementComparator())

            if sm.fit(m_struct, t_struct):
                return m["material_id"]

        return None
Пример #4
0
    def test_get_mapping(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(1, 2, 3)
        s1 = Structure(l, ['Ag', 'Si', 'Si'],
                       [[.7,.4,.5],[0,0,0.1],[0,0,0.2]])
        s1.make_supercell([2,1,1])
        s2 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0,0.1,-0.95],[0,0.1,0],[-.7,.5,.375]])

        shuffle = [2,0,1,3,5,4]
        s1 = Structure.from_sites([s1[i] for i in shuffle])
        #test the mapping
        s2.make_supercell([2,1,1])
        #equal sizes
        for i, x in enumerate(sm.get_mapping(s1, s2)):
            self.assertEqual(s1[x].species_and_occu,
                             s2[i].species_and_occu)

        del s1[0]
        #s1 is subset of s2
        for i, x in enumerate(sm.get_mapping(s2, s1)):
            self.assertEqual(s1[i].species_and_occu,
                             s2[x].species_and_occu)
        #s2 is smaller than s1
        del s2[0]
        del s2[1]
        self.assertRaises(ValueError, sm.get_mapping, s2, s1)
Пример #5
0
    def add_if_belongs(self, cand_snl):

        # no need to compare if different formulas or spacegroups
        if cand_snl.snlgroup_key != self.canonical_snl.snlgroup_key:
            return False

        # no need to compare if one is ordered, the other disordered
        if not (cand_snl.structure.is_ordered == self.canonical_structure.is_ordered):
            return False

        # make sure the structure is not already in all_structures
        if cand_snl.snl_id in self.all_snl_ids:
            print 'WARNING: add_if_belongs() has detected that you are trying to add the same SNL id twice!'
            return False

        #try a structure fit to the canonical structure

        # use default Structure Matcher params from April 24, 2013, as suggested by Shyue
        # we are using the ElementComparator() because this is how we want to group results
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=True, scale=True, attempt_supercell=True, comparator=ElementComparator())

        if not sm.fit(cand_snl.structure, self.canonical_structure):
            return False

        # everything checks out, add to the group
        self.all_snl_ids.append(cand_snl.snl_id)
        self.updated_at = datetime.datetime.utcnow()

        return True
Пример #6
0
 def test_as_dict_and_from_dict(self):
     sm = StructureMatcher(ltol=0.1, stol=0.2, angle_tol=2,
                           primitive_cell=False, scale=False,
                           comparator=FrameworkComparator())
     d = sm.as_dict()
     sm2 = StructureMatcher.from_dict(d)
     self.assertEqual(sm2.as_dict(), d)
Пример #7
0
    def apply_transformation(self, structure):
        """
        Returns a copy of structure with lattice parameters
        and sites scaled to the same degree as the relaxed_structure.

        Arg:
            structure (Structure): A structurally similar structure in
                regards to crystal and site positions.
        """

        if self.species_map == None:
            match = StructureMatcher()
            s_map = \
                match.get_best_electronegativity_anonymous_mapping(self.unrelaxed_structure,
                                                                   structure)
        else:
            s_map = self.species_map

        params = list(structure.lattice.abc)
        params.extend(structure.lattice.angles)
        new_lattice = Lattice.from_parameters(*[p*self.params_percent_change[i] \
                                                for i, p in enumerate(params)])
        species, frac_coords = [], []
        for site in self.relaxed_structure:
            species.append(s_map[site.specie])
            frac_coords.append(site.frac_coords)

        return Structure(new_lattice, species, frac_coords)
Пример #8
0
    def test_previous_reconstructions(self):

        # Test to see if we generated all reconstruction
        # types correctly and nothing changes

        m = StructureMatcher()
        for n in self.rec_archive.keys():
            if "base_reconstruction" in self.rec_archive[n].keys():
                arch = self.rec_archive[
                    self.rec_archive[n]["base_reconstruction"]]
                sg = arch["spacegroup"]["symbol"]
            else:
                sg = self.rec_archive[n]["spacegroup"]["symbol"]
            if sg == "Fm-3m":
                rec = ReconstructionGenerator(self.Ni, 20, 20, n)
                el = self.Ni[0].species_string
            elif sg == "Im-3m":
                rec = ReconstructionGenerator(self.Fe, 20, 20, n)
                el = self.Fe[0].species_string
            elif sg == "Fd-3m":
                rec = ReconstructionGenerator(self.Si, 20, 20, n)
                el = self.Si[0].species_string

            slabs = rec.build_slabs()
            s = Structure.from_file(get_path(os.path.join("reconstructions",
                                                          el + "_" + n + ".cif")))
            self.assertTrue(any(
                [len(m.group_structures([s, slab])) == 1 for slab in slabs]))
Пример #9
0
    def structure_transform(self, original_structure, new_structure,
                            refine_rotation=True):
        """
        Transforms a tensor from one basis for an original structure
        into a new basis defined by a new structure.

        Args:
            original_structure (Structure): structure corresponding
                to the basis of the current tensor
            new_structure (Structure): structure corresponding to the
                desired basis
            refine_rotation (bool): whether to refine the rotations
                generated in get_ieee_rotation

        Returns:
            Tensor that has been transformed such that its basis
            corresponds to the new_structure's basis
        """
        sm = StructureMatcher()
        if not sm.fit(original_structure, new_structure):
            warnings.warn("original and new structures do not match!")
        trans_1 = self.get_ieee_rotation(original_structure, refine_rotation)
        trans_2 = self.get_ieee_rotation(new_structure, refine_rotation)
        # Get the ieee format tensor
        new = self.rotate(trans_1)
        # Reverse the ieee format rotation for the second structure
        new = new.rotate(np.transpose(trans_2))
        return new
Пример #10
0
    def test_disordered_primitive_to_ordered_supercell(self):
        sm_atoms = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                                    primitive_cell=False, scale=True,
                                    attempt_supercell=True,
                                    allow_subset=True,
                                    supercell_size = 'num_atoms',
                                    comparator=OrderDisorderElementComparator())
        sm_sites = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                                    primitive_cell=False, scale=True,
                                    attempt_supercell=True,
                                    allow_subset=True,
                                    supercell_size = 'num_sites',
                                    comparator=OrderDisorderElementComparator())
        lp = Lattice.orthorhombic(10, 20, 30)
        pcoords = [[0,   0,   0],
                   [0.5, 0.5, 0.5]]
        ls = Lattice.orthorhombic(20,20,30)
        scoords = [[0,    0,   0],
                   [0.75, 0.5, 0.5]]
        prim = Structure(lp, [{'Na':0.5}, {'Cl':0.5}], pcoords)
        supercell = Structure(ls, ['Na', 'Cl'], scoords)
        supercell.make_supercell([[-1,1,0],[0,1,1],[1,0,0]])

        self.assertFalse(sm_sites.fit(prim, supercell))
        self.assertTrue(sm_atoms.fit(prim, supercell))

        self.assertRaises(ValueError, sm_atoms.get_s2_like_s1, prim, supercell)
        self.assertEqual(len(sm_atoms.get_s2_like_s1(supercell, prim)), 4)
Пример #11
0
    def test_ordered_primitive_to_disordered_supercell(self):
        sm_atoms = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                                    primitive_cell=False, scale=True,
                                    attempt_supercell=True,
                                    allow_subset=True,
                                    supercell_size = 'num_atoms',
                                    comparator=OrderDisorderElementComparator())
        sm_sites = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                                    primitive_cell=False, scale=True,
                                    attempt_supercell=True,
                                    allow_subset=True,
                                    supercell_size = 'num_sites',
                                    comparator=OrderDisorderElementComparator())
        lp = Lattice.orthorhombic(10, 20, 30)
        pcoords = [[0,   0,   0],
                   [0.5, 0.5, 0.5]]
        ls = Lattice.orthorhombic(20,20,30)
        scoords = [[0,    0,   0],
                   [0.5,  0,   0],
                   [0.25, 0.5, 0.5],
                   [0.75, 0.5, 0.5]]
        s1 = Structure(lp, ['Na', 'Cl'], pcoords)
        s2 = Structure(ls, [{'Na':0.5}, {'Na':0.5}, {'Cl':0.5}, {'Cl':0.5}], scoords)

        self.assertTrue(sm_sites.fit(s1, s2))
        self.assertFalse(sm_atoms.fit(s1, s2))
 def test_primitive(self):
     """Test primitive cell reduction"""
     sm = StructureMatcher(primitive_cell=True)
     mod = SupercellMaker(self.struct_list[1],
                          scaling_matrix=[[2, 0, 0], [0, 3, 0], [0, 0, 1]])
     super_cell = mod.modified_structure
     self.assertTrue(sm.fit(self.struct_list[0], super_cell))
Пример #13
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], [0.7, 0.4, 0.5]])
        s2 = Structure(l, ["Si", "Ag"], [[0, 0.1, 0], [-0.7, 0.5, 0.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], [0.7, 0.4, 0.5]])
        s2 = Structure(l, ["Si", "Si"], [[0, 0.1, 0], [-0.7, 0.5, 0.4]])
        result = sm.get_s2_like_s1(s1, s2)
        mindists = np.min(s1.lattice.get_all_distances(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], [0.7, 0.4, 0.5]])
        s2 = Structure(l, ["Si", "Si"], [[0, 0.1, 0], [-0.7, 0.5, 0.4]])
        self.assertEqual(sm.get_s2_like_s1(s1, s2), None)
Пример #14
0
def compare_structures(options):
    """Inspired to a similar function in pmg_structure."""
    paths = options.paths
    if len(paths) < 2:
        print("You need more than one structure to compare!")
        return 1

    try:
        structures = [abilab.Structure.from_file(p) for p in paths]
    except Exception as ex:
        print("Error reading structures from files. Are they in the right format?")
        print(str(ex))
        return 1

    from pymatgen.analysis.structure_matcher import StructureMatcher, ElementComparator
    compareby = "species" if options.anonymous else "element"
    m = StructureMatcher() if compareby == "species" else StructureMatcher(comparator=ElementComparator())
    print("Grouping %s structures by `%s` with `anonymous: %s`" % (len(structures), compareby, options.anonymous))

    for i, grp in enumerate(m.group_structures(structures, anonymous=options.anonymous)):
        print("Group {}: ".format(i))
        for s in grp:
            spg_symbol, international_number = s.get_space_group_info()
            print("\t- {} ({}), vol: {:.2f} A^3, {} ({})".format(
                  paths[structures.index(s)], s.formula, s.volume, spg_symbol, international_number))
        print()

    if options.verbose:
        pprint(m.as_dict())
Пример #15
0
    def test_get_supercell_matrix(self):
        sm = StructureMatcher(ltol=0.1, stol=0.3, angle_tol=2,
                              primitive_cell=False, scale=True,
                              attempt_supercell=True)

        l = Lattice.orthorhombic(1, 2, 3)

        s1 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0,0,0.1],[0,0,0.2],[.7,.4,.5]])
        s1.make_supercell([2,1,1])
        s2 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0,0.1,0],[0,0.1,-0.95],[-.7,.5,.375]])
        result = sm.get_supercell_matrix(s1, s2)
        self.assertTrue((result == [[-2,0,0],[0,1,0],[0,0,1]]).all())

        s1 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0,0,0.1],[0,0,0.2],[.7,.4,.5]])
        s1.make_supercell([[1, -1, 0],[0, 0, -1],[0, 1, 0]])

        s2 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0,0.1,0],[0,0.1,-0.95],[-.7,.5,.375]])
        result = sm.get_supercell_matrix(s1, s2)
        self.assertTrue((result == [[-1,-1,0],[0,0,-1],[0,1,0]]).all())

        #test when the supercell is a subset
        sm = StructureMatcher(ltol=0.1, stol=0.3, angle_tol=2,
                              primitive_cell=False, scale=True,
                              attempt_supercell=True, allow_subset=True)
        del s1[0]
        result = sm.get_supercell_matrix(s1, s2)
        self.assertTrue((result == [[-1,-1,0],[0,0,-1],[0,1,0]]).all())
Пример #16
0
    def test_class(self):
        # Tests entire class as single working unit
        sm = StructureMatcher()
        # Test group_structures and find_indices
        out = sm.group_structures(self.struct_list)

        self.assertEqual(sm.find_indexes(self.struct_list, out), [0, 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 8, 9, 9, 10])
Пример #17
0
 def test_class(self):
     # Tests entire class as single working unit
     sm = StructureMatcher()
     # Test group_structures and find_indices
     out = sm.group_structures(self.struct_list)
     self.assertEqual(map(len, out), [4, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1])
     self.assertEqual(sum(map(len, out)), len(self.struct_list))
Пример #18
0
    def test_electronegativity(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5)

        s1 = read_structure(os.path.join(test_dir, "Na2Fe2PAsO4S4.cif"))
        s2 = read_structure(os.path.join(test_dir, "Na2Fe2PNO4Se4.cif"))
        self.assertAlmostEqual(sm.fit_with_electronegativity(s1, s2),
                               {Composition('S'): Composition('Se'), Composition('As'): Composition('N')})
Пример #19
0
    def _match_material(self, taskdoc):
        """
        Returns the material_id that has the same structure as this task as
         determined by the structure matcher. Returns None if no match.

        Args:
            taskdoc (dict): a JSON-like task document

        Returns:
            (int) matching material_id or None
        """
        formula = taskdoc["formula_reduced_abc"]

        if "parent_structure" in taskdoc:  # this is used to intentionally combine multiple data w/same formula but slightly different structure, e.g. from an ordering scheme
            t_struct = Structure.from_dict(taskdoc["parent_structure"]["structure"])
            q = {"formula_reduced_abc": formula, "parent_structure.spacegroup.number": taskdoc["parent_structure"]["spacegroup"]["number"]}
        else:
            sgnum = taskdoc["output"]["spacegroup"]["number"]
            t_struct = Structure.from_dict(taskdoc["output"]["structure"])
            q = {"formula_reduced_abc": formula, "sg_number": sgnum}

        for m in self._materials.find(q, {"parent_structure": 1, "structure": 1, "material_id": 1}):
            s_dict = m["parent_structure"]["structure"] if "parent_structure" in m else m["structure"]
            m_struct = Structure.from_dict(s_dict)
            sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                                  primitive_cell=True, scale=True,
                                  attempt_supercell=False, allow_subset=False,
                                  comparator=ElementComparator())

            if sm.fit(m_struct, t_struct):
                return m["material_id"]

        return None
Пример #20
0
    def test_get_supercell_size(self):
        l = Lattice.cubic(1)
        l2 = Lattice.cubic(0.9)
        s1 = Structure(l, ['Mg', 'Cu', 'Ag', 'Cu', 'Ag'], [[0] * 3] * 5)
        s2 = Structure(l2, ['Cu', 'Cu', 'Ag'], [[0] * 3] * 3)

        sm = StructureMatcher(supercell_size='volume')
        self.assertEqual(sm._get_supercell_size(s1, s2),
                         (1, True))
        self.assertEqual(sm._get_supercell_size(s2, s1),
                         (1, True))

        sm = StructureMatcher(supercell_size='num_sites')
        self.assertEqual(sm._get_supercell_size(s1, s2),
                         (2, False))
        self.assertEqual(sm._get_supercell_size(s2, s1),
                         (2, True))

        sm = StructureMatcher(supercell_size='Ag')
        self.assertEqual(sm._get_supercell_size(s1, s2),
                         (2, False))
        self.assertEqual(sm._get_supercell_size(s2, s1),
                         (2, True))

        sm = StructureMatcher(supercell_size='wfieoh')
        self.assertRaises(ValueError, sm._get_supercell_size, s1, s2)
Пример #21
0
    def add_if_belongs(self, cand_snl):

        # no need to compare if different formulas or spacegroups
        if cand_snl.snlgroup_key != self.canonical_snl.snlgroup_key:
            return False, None

        # no need to compare if one is ordered, the other disordered
        if not (cand_snl.structure.is_ordered == self.canonical_structure.is_ordered):
            return False, None

        # filter out large C-Ce structures
        comp = cand_snl.structure.composition
        elsyms = sorted(set([e.symbol for e in comp.elements]))
        chemsys = '-'.join(elsyms)
        if (
                cand_snl.structure.num_sites > 1500 or self.canonical_structure.num_sites > 1500) and chemsys == 'C-Ce':
            print 'SKIPPING LARGE C-Ce'
            return False, None

        # make sure the structure is not already in all_structures
        if cand_snl.snl_id in self.all_snl_ids:
            print 'WARNING: add_if_belongs() has detected that you are trying to add the same SNL id twice!'
            return False, None

        #try a structure fit to the canonical structure

        # use default Structure Matcher params from April 24, 2013, as suggested by Shyue
        # we are using the ElementComparator() because this is how we want to group results
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=True, scale=True,
                              attempt_supercell=False, comparator=ElementComparator())

        if not sm.fit(cand_snl.structure, self.canonical_structure):
            return False, None

        # everything checks out, add to the group
        self.all_snl_ids.append(cand_snl.snl_id)

        # now that we are in the group, if there are site properties we need to check species_groups
        # e.g., if there is another SNL in the group with the same site properties, e.g. MAGMOM
        spec_group = None

        if has_species_properties(cand_snl.structure):
            for snl in self.species_snl:
                sms = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=True, scale=True,
                              attempt_supercell=False, comparator=SpeciesComparator())
                if sms.fit(cand_snl.structure, snl.structure):
                    spec_group = snl.snl_id
                    self.species_groups[snl.snl_id].append(cand_snl.snl_id)
                    break

            # add a new species group
            if not spec_group:
                self.species_groups[cand_snl.snl_id] = [cand_snl.snl_id]
                self.species_snl.append(cand_snl)
                spec_group = cand_snl.snl_id

        self.updated_at = datetime.datetime.utcnow()

        return True, spec_group
Пример #22
0
    def apply_transformation(self, structure, return_ranked_list=False):
        #Make a mutable structure first
        mods = Structure.from_sites(structure)
        for sp, spin in self.mag_species_spin.items():
            sp = get_el_sp(sp)
            oxi_state = getattr(sp, "oxi_state", 0)
            if spin:
                up = Specie(sp.symbol, oxi_state, {"spin": abs(spin)})
                down = Specie(sp.symbol, oxi_state, {"spin": -abs(spin)})
                mods.replace_species(
                    {sp: Composition({up: self.order_parameter,
                                      down: 1 - self.order_parameter})})
            else:
                mods.replace_species(
                    {sp: Specie(sp.symbol, oxi_state, {"spin": spin})})

        if mods.is_ordered:
            return [mods] if return_ranked_list > 1 else mods

        enum_args = self.enum_kwargs

        enum_args["min_cell_size"] = max(int(
            MagOrderingTransformation.determine_min_cell(
                structure, self.mag_species_spin,
                self.order_parameter)),
            enum_args.get("min_cell_size"))

        max_cell = self.enum_kwargs.get('max_cell_size')
        if max_cell:
            if enum_args["min_cell_size"] > max_cell:
                raise ValueError('Specified max cell size is smaller'
                                 ' than the minimum enumerable cell size')
        else:
            enum_args["max_cell_size"] = enum_args["min_cell_size"]

        t = EnumerateStructureTransformation(**enum_args)

        alls = t.apply_transformation(mods,
                                      return_ranked_list=return_ranked_list)

        try:
            num_to_return = int(return_ranked_list)
        except ValueError:
            num_to_return = 1

        if num_to_return == 1 or not return_ranked_list:
            return alls[0]["structure"] if num_to_return else alls

        m = StructureMatcher(comparator=SpinComparator())

        grouped = m.group_structures([d["structure"] for d in alls])

        alls = [{"structure": g[0], "energy": self.emodel.get_energy(g[0])}
                for g in grouped]

        self._all_structures = sorted(alls, key=lambda d: d["energy"])

        return self._all_structures[0:num_to_return]
Пример #23
0
    def test_get_lattice_from_lattice_type(self):
        cif_structure = """#generated using pymatgen
data_FePO4
_symmetry_space_group_name_H-M   Pnma
_cell_length_a   10.41176687
_cell_length_b   6.06717188
_cell_length_c   4.75948954
_chemical_formula_structural   FePO4
_chemical_formula_sum   'Fe4 P4 O16'
_cell_volume   300.65685512
_cell_formula_units_Z   4
_symmetry_cell_setting Orthorhombic
loop_
  _symmetry_equiv_pos_site_id
  _symmetry_equiv_pos_as_xyz
   1  'x, y, z'
loop_
  _atom_site_type_symbol
  _atom_site_label
  _atom_site_symmetry_multiplicity
  _atom_site_fract_x
  _atom_site_fract_y
  _atom_site_fract_z
  _atom_site_occupancy
  Fe  Fe1  1  0.218728  0.750000  0.474867  1
  Fe  Fe2  1  0.281272  0.250000  0.974867  1
  Fe  Fe3  1  0.718728  0.750000  0.025133  1
  Fe  Fe4  1  0.781272  0.250000  0.525133  1
  P  P5  1  0.094613  0.250000  0.418243  1
  P  P6  1  0.405387  0.750000  0.918243  1
  P  P7  1  0.594613  0.250000  0.081757  1
  P  P8  1  0.905387  0.750000  0.581757  1
  O  O9  1  0.043372  0.750000  0.707138  1
  O  O10  1  0.096642  0.250000  0.741320  1
  O  O11  1  0.165710  0.046072  0.285384  1
  O  O12  1  0.165710  0.453928  0.285384  1
  O  O13  1  0.334290  0.546072  0.785384  1
  O  O14  1  0.334290  0.953928  0.785384  1
  O  O15  1  0.403358  0.750000  0.241320  1
  O  O16  1  0.456628  0.250000  0.207138  1
  O  O17  1  0.543372  0.750000  0.792862  1
  O  O18  1  0.596642  0.250000  0.758680  1
  O  O19  1  0.665710  0.046072  0.214616  1
  O  O20  1  0.665710  0.453928  0.214616  1
  O  O21  1  0.834290  0.546072  0.714616  1
  O  O22  1  0.834290  0.953928  0.714616  1
  O  O23  1  0.903358  0.750000  0.258680  1
  O  O24  1  0.956628  0.250000  0.292862  1

"""
        cp = CifParser.from_string(cif_structure)
        s_test = cp.get_structures(False)[0]
        filepath = os.path.join(test_dir, 'POSCAR')
        poscar = Poscar.from_file(filepath)
        s_ref = poscar.structure

        sm = StructureMatcher(stol=0.05, ltol=0.01, angle_tol=0.1)
        self.assertTrue(sm.fit(s_ref, s_test))
    def test_supercell_fit(self):
        sm = StructureMatcher(attempt_supercell=False)
        s1 = read_structure(os.path.join(test_dir, "Al3F9.cif"))
        s2 = read_structure(os.path.join(test_dir, "Al3F9_distorted.cif"))

        self.assertFalse(sm.fit(s1, s2))

        sm = StructureMatcher(attempt_supercell=True)

        self.assertTrue(sm.fit(s1, s2))
Пример #25
0
 def test_class(self):
     # Tests entire class as single working unit
     sm = StructureMatcher()
     # Test group_structures and find_indices
     out = sm.group_structures(self.struct_list)
     self.assertEqual(list(map(len, out)), [4, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1])
     self.assertEqual(sum(map(len, out)), len(self.struct_list))
     for s in self.struct_list[::2]:
         s.replace_species({'Ti': 'Zr', 'O':'Ti'})
     out = sm.group_structures(self.struct_list, anonymous=True)
     self.assertEqual(list(map(len, out)), [4, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1])
Пример #26
0
    def test_supercell_fit(self):
        sm = StructureMatcher(attempt_supercell=False)
        s1 = Structure.from_file(os.path.join(test_dir, "Al3F9.json"))
        s2 = Structure.from_file(os.path.join(test_dir, "Al3F9_distorted.json"))

        self.assertFalse(sm.fit(s1, s2))

        sm = StructureMatcher(attempt_supercell=True)

        self.assertTrue(sm.fit(s1, s2))
        self.assertTrue(sm.fit(s2, s1))
Пример #27
0
    def get_framework_rms_plot(self, plt=None, granularity=200,
                               matching_s=None):
        """
        Get the plot of rms framework displacement vs time. Useful for checking
        for melting, especially if framework atoms can move via paddle-wheel
        or similar mechanism (which would show up in max framework displacement
        but doesn't constitute melting).

        Args:
            plt (matplotlib.pyplot): If plt is supplied, changes will be made 
                to an existing plot. Otherwise, a new plot will be created.
            granularity (int): Number of structures to match
            matching_s (Structure): Optionally match to a disordered structure
                instead of the first structure in the analyzer. Required when
                a secondary mobile ion is present.
        Notes:
            The method doesn't apply to NPT-AIMD simulation analysis.
        """
        from pymatgen.util.plotting import pretty_plot
        if self.lattices is not None and len(self.lattices) > 1:
            warnings.warn("Note the method doesn't apply to NPT-AIMD "
                          "simulation analysis!")

        plt = pretty_plot(12, 8, plt=plt)
        step = (self.corrected_displacements.shape[1] - 1) // (granularity - 1)
        f = (matching_s or self.structure).copy()
        f.remove_species([self.specie])
        sm = StructureMatcher(primitive_cell=False, stol=0.6,
                              comparator=OrderDisorderElementComparator(),
                              allow_subset=True)
        rms = []
        for s in self.get_drift_corrected_structures(step=step):
            s.remove_species([self.specie])
            d = sm.get_rms_dist(f, s)
            if d:
                rms.append(d)
            else:
                rms.append((1, 1))
        max_dt = (len(rms) - 1) * step * self.step_skip * self.time_step
        if max_dt > 100000:
            plot_dt = np.linspace(0, max_dt / 1000, len(rms))
            unit = 'ps'
        else:
            plot_dt = np.linspace(0, max_dt, len(rms))
            unit = 'fs'
        rms = np.array(rms)
        plt.plot(plot_dt, rms[:, 0], label='RMS')
        plt.plot(plot_dt, rms[:, 1], label='max')
        plt.legend(loc='best')
        plt.xlabel("Timestep ({})".format(unit))
        plt.ylabel("normalized distance")
        plt.tight_layout()
        return plt
Пример #28
0
 def test_mix(self):
     structures = [self.get_structure("Li2O"), self.get_structure("Li2O2"), self.get_structure("LiFePO4")]
     for fname in ["POSCAR.Li2O", "POSCAR.LiFePO4"]:
         structures.append(Structure.from_file(os.path.join(test_dir, fname)))
     sm = StructureMatcher(comparator=ElementComparator())
     groups = sm.group_structures(structures)
     for g in groups:
         formula = g[0].composition.reduced_formula
         if formula in ["Li2O", "LiFePO4"]:
             self.assertEqual(len(g), 2)
         else:
             self.assertEqual(len(g), 1)
Пример #29
0
    def test_electronegativity(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5)

        s1 = Structure.from_file(os.path.join(test_dir, "Na2Fe2PAsO4S4.json"))
        s2 = Structure.from_file(os.path.join(test_dir, "Na2Fe2PNO4Se4.json"))
        self.assertEqual(sm.get_best_electronegativity_anonymous_mapping(s1, s2),
                    {Element('S'): Element('Se'),
                     Element('As'): Element('N'),
                     Element('Fe'): Element('Fe'),
                     Element('Na'): Element('Na'),
                     Element('P'): Element('P'),
                     Element('O'): Element('O'),})
        self.assertEqual(len(sm.get_all_anonymous_mappings(s1, s2)), 2)
Пример #30
0
    def test_cmp_fstruct(self):
        sm = StructureMatcher()

        s1 = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])
        s2 = np.array([[0.11, 0.22, 0.33]])
        frac_tol = np.array([0.02, 0.03, 0.04])
        mask = np.array([[False, False]])
        mask2 = np.array([[True, False]])

        self.assertRaises(ValueError, sm._cmp_fstruct, s2, s1, frac_tol, mask.T)
        self.assertRaises(ValueError, sm._cmp_fstruct, s1, s2, frac_tol, mask.T)

        self.assertTrue(sm._cmp_fstruct(s1, s2, frac_tol, mask))
        self.assertFalse(sm._cmp_fstruct(s1, s2, frac_tol/2, mask))
        self.assertFalse(sm._cmp_fstruct(s1, s2, frac_tol, mask2))
Пример #31
0
    def _match_material(self, doc, ltol=0.2, stol=0.3, angle_tol=5):
        """
        Returns the material_id that has the same structure as this doc as
         determined by the structure matcher. Returns None if no match.

        Args:
            doc (dict): a JSON-like document
            ltol (float): StructureMatcher tuning parameter
            stol (float): StructureMatcher tuning parameter
            angle_tol (float): StructureMatcher tuning parameter

        Returns:
            (int) matching material_id or None
        """
        formula = doc["formula_reduced_abc"]
        sgnum = doc["spacegroup"]["number"]

        for m in self._materials.find(
            {
                "formula_reduced_abc": formula,
                "sg_number": sgnum
            },
            {
                "structure": 1,
                "material_id": 1
            },
        ):

            m_struct = Structure.from_dict(m["structure"])
            t_struct = Structure.from_dict(doc["structure"])

            sm = StructureMatcher(
                ltol=ltol,
                stol=stol,
                angle_tol=angle_tol,
                primitive_cell=True,
                scale=True,
                attempt_supercell=False,
                allow_subset=False,
                comparator=ElementComparator(),
            )

            if sm.fit(m_struct, t_struct):
                return m["material_id"]

        return None
Пример #32
0
    def test_get_lattices(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                              primitive_cell=True, scale=True,
                              attempt_supercell=False)
        l1 = Lattice.from_lengths_and_angles([1, 2.1, 1.9] , [90, 89, 91])
        l2 = Lattice.from_lengths_and_angles([1.1, 2, 2] , [89, 91, 90])
        s1 = Structure(l1, [], [])
        s2 = Structure(l2, [], [])

        lattices = list(sm._get_lattices(s=s1, target_lattice=s2.lattice))
        self.assertEqual(len(lattices), 16)

        l3 = Lattice.from_lengths_and_angles([1.1, 2, 20] , [89, 91, 90])
        s3 = Structure(l3, [], [])

        lattices = list(sm._get_lattices(s=s1, target_lattice=s3.lattice))
        self.assertEqual(len(lattices), 0)
Пример #33
0
    def test_cmp_fstruct(self):
        sm = StructureMatcher()

        s1 = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])
        s2 = np.array([[0.11, 0.22, 0.33]])
        frac_tol = np.array([0.02, 0.03, 0.04])
        mask = np.array([[False, False]])
        mask2 = np.array([[True, False]])

        self.assertRaises(ValueError, sm._cmp_fstruct, s2, s1, frac_tol,
                          mask.T)
        self.assertRaises(ValueError, sm._cmp_fstruct, s1, s2, frac_tol,
                          mask.T)

        self.assertTrue(sm._cmp_fstruct(s1, s2, frac_tol, mask))
        self.assertFalse(sm._cmp_fstruct(s1, s2, frac_tol / 2, mask))
        self.assertFalse(sm._cmp_fstruct(s1, s2, frac_tol, mask2))
Пример #34
0
 def test_mix(self):
     structures = [
         self.get_structure("Li2O"),
         self.get_structure("Li2O2"),
         self.get_structure("LiFePO4")
     ]
     for fname in ["POSCAR.Li2O", "POSCAR.LiFePO4"]:
         structures.append(
             Structure.from_file(os.path.join(test_dir, fname)))
     sm = StructureMatcher(comparator=ElementComparator())
     groups = sm.group_structures(structures)
     for g in groups:
         formula = g[0].composition.reduced_formula
         if formula in ["Li2O", "LiFePO4"]:
             self.assertEqual(len(g), 2)
         else:
             self.assertEqual(len(g), 1)
Пример #35
0
    def test_ignore_species(self):
        s1 = Structure.from_file(os.path.join(test_dir, "LiFePO4.cif"))
        s2 = Structure.from_file(os.path.join(test_dir, "POSCAR"))
        m = StructureMatcher(ignored_species=["Li"],
                             primitive_cell=False,
                             attempt_supercell=True)
        self.assertTrue(m.fit(s1, s2))
        self.assertTrue(m.fit_anonymous(s1, s2))
        groups = m.group_structures([s1, s2])
        self.assertEqual(len(groups), 1)
        s2.make_supercell((2, 1, 1))
        ss1 = m.get_s2_like_s1(s2, s1, include_ignored_species=True)
        self.assertAlmostEqual(ss1.lattice.a, 20.820740000000001)
        self.assertEqual(ss1.composition.reduced_formula, "LiFePO4")

        self.assertEqual(
            {
                k.symbol: v.symbol
                for k, v in m.get_best_electronegativity_anonymous_mapping(
                    s1, s2).items()
            }, {
                "Fe": "Fe",
                "P": "P",
                "O": "O"
            })
Пример #36
0
    def test_disordered_primitive_to_ordered_supercell(self):
        sm_atoms = StructureMatcher(
            ltol=0.2,
            stol=0.3,
            angle_tol=5,
            primitive_cell=False,
            scale=True,
            attempt_supercell=True,
            allow_subset=True,
            supercell_size='num_atoms',
            comparator=OrderDisorderElementComparator())
        sm_sites = StructureMatcher(
            ltol=0.2,
            stol=0.3,
            angle_tol=5,
            primitive_cell=False,
            scale=True,
            attempt_supercell=True,
            allow_subset=True,
            supercell_size='num_sites',
            comparator=OrderDisorderElementComparator())
        lp = Lattice.orthorhombic(10, 20, 30)
        pcoords = [[0, 0, 0], [0.5, 0.5, 0.5]]
        ls = Lattice.orthorhombic(20, 20, 30)
        scoords = [[0, 0, 0], [0.75, 0.5, 0.5]]
        prim = Structure(lp, [{'Na': 0.5}, {'Cl': 0.5}], pcoords)
        supercell = Structure(ls, ['Na', 'Cl'], scoords)
        supercell.make_supercell([[-1, 1, 0], [0, 1, 1], [1, 0, 0]])

        self.assertFalse(sm_sites.fit(prim, supercell))
        self.assertTrue(sm_atoms.fit(prim, supercell))

        self.assertRaises(ValueError, sm_atoms.get_s2_like_s1, prim, supercell)
        self.assertEqual(len(sm_atoms.get_s2_like_s1(supercell, prim)), 4)
Пример #37
0
def _perform_grouping(args):
    (
        entries_json,
        hosts_json,
        ltol,
        stol,
        angle_tol,
        primitive_cell,
        scale,
        comparator,
        groups,
    ) = args

    entries = json.loads(entries_json, cls=MontyDecoder)
    hosts = json.loads(hosts_json, cls=MontyDecoder)
    unmatched = list(zip(entries, hosts))
    while len(unmatched) > 0:
        ref_host = unmatched[0][1]
        logger.info(
            f"Reference tid = {unmatched[0][0].entry_id}, formula = {ref_host.formula}"
        )
        ref_formula = ref_host.composition.reduced_formula
        logger.info(f"Reference host = {ref_formula}")
        matches = [unmatched[0]]
        for i in range(1, len(unmatched)):
            test_host = unmatched[i][1]
            logger.info(
                f"Testing tid = {unmatched[i][0].entry_id}, formula = {test_host.formula}"
            )
            test_formula = test_host.composition.reduced_formula
            logger.info(f"Test host = {test_formula}")
            m = StructureMatcher(
                ltol=ltol,
                stol=stol,
                angle_tol=angle_tol,
                primitive_cell=primitive_cell,
                scale=scale,
                comparator=comparator,
            )
            if m.fit(ref_host, test_host):
                logger.info("Fit found")
                matches.append(unmatched[i])
        groups.append(json.dumps([m[0] for m in matches], cls=MontyEncoder))
        unmatched = list(filter(lambda x: x not in matches, unmatched))
        logger.info(f"{len(unmatched)} unmatched remaining")
Пример #38
0
    def test_get_supercell_matrix(self):
        sm = StructureMatcher(ltol=0.1, stol=0.3, angle_tol=2,
                              primitive_cell=False, scale=True,
                              attempt_supercell=True)

        l = Lattice.orthorhombic(1, 2, 3)

        s1 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0, 0, 0.1], [0, 0, 0.2], [.7, .4, .5]])
        s1.make_supercell([2, 1, 1])
        s2 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0, 0.1, 0], [0, 0.1, -0.95], [-.7, .5, .375]])
        result = sm.get_supercell_matrix(s1, s2)
        self.assertTrue((result == [[-2, 0, 0], [0, 1, 0], [0, 0, 1]]).all())

        s1 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0, 0, 0.1], [0, 0, 0.2], [.7, .4, .5]])
        s1.make_supercell([[1, -1, 0], [0, 0, -1], [0, 1, 0]])

        s2 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0, 0.1, 0], [0, 0.1, -0.95], [-.7, .5, .375]])
        result = sm.get_supercell_matrix(s1, s2)
        self.assertTrue((result == [[-1, -1, 0], [0, 0, -1], [0, 1, 0]]).all())

        # test when the supercell is a subset
        sm = StructureMatcher(ltol=0.1, stol=0.3, angle_tol=2,
                              primitive_cell=False, scale=True,
                              attempt_supercell=True, allow_subset=True)
        del s1[0]
        result = sm.get_supercell_matrix(s1, s2)
        self.assertTrue((result == [[-1, -1, 0], [0, 0, -1], [0, 1, 0]]).all())
Пример #39
0
def test_basic_structure(kind, index):
    base_structure = get_lattice(kind)
    num_type = 2
    species = ["Cu", "Au"]

    se = StructureEnumerator(
        base_structure,
        index,
        num_type,
        species,
        color_exchange=True,
        remove_superperiodic=True,
    )
    list_ds = se.generate()

    stm = StructureMatcher(ltol=1e-4, stol=1e-4)
    grouped = stm.group_structures(list_ds)
    assert len(grouped) == len(list_ds)
Пример #40
0
    def test_get_s2_like_s1(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                              primitive_cell=False, scale=True,
                              attempt_supercell=True)
        l = Lattice.orthorhombic(1, 2, 3)
        s1 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0,0,0.1],[0,0,0.2],[.7,.4,.5]])
        s1.make_supercell([2,1,1])
        s2 = Structure(l, ['Si', 'Si', 'Ag'],
                       [[0,0.1,0],[0,0.1,-0.95],[-.7,.5,.375]])
        result = sm.get_s2_like_s1(s1, s2)

        self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords,
                                                    [0.35,0.4,0.5])), 1)
        self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords,
                                                    [0,0,0.125])), 1)
        self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords,
                                                    [0,0,0.175])), 1)
Пример #41
0
    def test_electronegativity(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5)

        s1 = Structure.from_file(os.path.join(test_dir, "Na2Fe2PAsO4S4.json"))
        s2 = Structure.from_file(os.path.join(test_dir, "Na2Fe2PNO4Se4.json"))
        self.assertEqual(sm.get_best_electronegativity_anonymous_mapping(s1, s2),
                    {Element('S'): Element('Se'),
                     Element('As'): Element('N'),
                     Element('Fe'): Element('Fe'),
                     Element('Na'): Element('Na'),
                     Element('P'): Element('P'),
                     Element('O'): Element('O'),})
        self.assertEqual(len(sm.get_all_anonymous_mappings(s1, s2)), 2)

        # test include_dist
        dists = {Element('N'): 0, Element('P'): 0.0010725064}
        for mapping, d in sm.get_all_anonymous_mappings(s1, s2, include_dist=True):
            self.assertAlmostEqual(dists[mapping[Element('As')]], d)
Пример #42
0
    def relaxed_structure_match(self, i, j):
        """
        Check if the relaxed structures of two interstitials match

        Args:
            i: Symmetrically distinct interstitial index
            j: Symmetrically distinct interstitial index

        .. note::

            Index 0 corresponds to bulk.
        """
        if not self._relax_structs:
            self.relax()
        sm = StructureMatcher()
        struct1 = self._relax_structs[i]
        struct2 = self._relax_structs[j]
        return sm.fit(struct1, struct2)
Пример #43
0
    def test_find_match2(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                              primitive_cell=True, scale=True,
                              attempt_supercell=False)
        l = Lattice.orthorhombic(1, 2, 3)
        s1 = Structure(l, ['Si', 'Si'], [[0, 0, 0.1], [0, 0, 0.2]])
        s2 = Structure(l, ['Si', 'Si'], [[0, 0.1, 0], [0, 0.1, -0.95]])

        s1, s2, fu, s1_supercell = sm._preprocess(s1, s2, False)

        match = sm._strict_match(s1, s2, fu, s1_supercell=False,
                                 use_rms=True, break_on_match=False)
        scale_matrix = match[2]
        s2.make_supercell(scale_matrix)
        s2.translate_sites(range(len(s2)), match[3])

        self.assertAlmostEqual(np.sum(s2.frac_coords) % 1, 0.3)
        self.assertAlmostEqual(np.sum(s2.frac_coords[:, :2]) % 1, 0)
Пример #44
0
def mpid_and_link(symmetrizer: StructureSymmetrizer):

    reduced_formula = symmetrizer.structure.composition.reduced_formula
    criteria = {"reduced_cell_formula": reduced_formula,
                "spacegroup.number": symmetrizer.sg_number}
    properties = ["task_id", "structure"]
    with MPRester() as m:
        for doc in m.query(criteria, properties):
            sm = StructureMatcher()
            if sm.fit(doc["structure"], symmetrizer.structure):
                mpid = doc["task_id"]
                break
        else:
            return H4("None")

    return dcc.Link(f'mp-id {mpid}',
                    href=f'https://materialsproject.org/materials/{mpid}/',
                    style={'font-weight': 'bold', "font-size": "20px"})
Пример #45
0
    def test_occupancy_comparator(self):

        lp = Lattice.orthorhombic(10, 20, 30)
        pcoords = [[0, 0, 0],
                   [0.5, 0.5, 0.5]]
        s1 = Structure(lp, [{'Na': 0.6, 'K': 0.4}, 'Cl'], pcoords)
        s2 = Structure(lp, [{'Xa': 0.4, 'Xb': 0.6}, 'Cl'], pcoords)
        s3 = Structure(lp, [{'Xa': 0.5, 'Xb': 0.5}, 'Cl'], pcoords)

        sm_sites = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                                    primitive_cell=False, scale=True,
                                    attempt_supercell=True,
                                    allow_subset=True,
                                    supercell_size='num_sites',
                                    comparator=OccupancyComparator())

        self.assertTrue(sm_sites.fit(s1, s2))
        self.assertFalse(sm_sites.fit(s1, s3))
Пример #46
0
 def test_out_of_cell_s2_like_s1(self):
     l = Lattice.cubic(5)
     s1 = Structure(l, ['Si', 'Ag', 'Si'],
                    [[0, 0, -0.02], [0, 0, 0.001], [.7, .4, .5]])
     s2 = Structure(l, ['Si', 'Ag', 'Si'],
                    [[0, 0, 0.98], [0, 0, 0.99], [.7, .4, .5]])
     new_s2 = StructureMatcher(primitive_cell=False).get_s2_like_s1(s1, s2)
     dists = np.sum((s1.cart_coords - new_s2.cart_coords)**2, axis=-1)**0.5
     self.assertLess(np.max(dists), 0.1)
Пример #47
0
    def get_framework_rms_plot(self, plt=None, granularity=200, matching_s=None):
        """
        Get the plot of rms framework displacement vs time. Useful for checking
        for melting, especially if framework atoms can move via paddle-wheel
        or similar mechanism (which would show up in max framework displacement
        but doesn't constitute melting).

        Args:
            granularity (int): Number of structures to match
            matching_s (Structure): Optionally match to a disordered structure
                instead of the first structure in the analyzer. Required when
                a secondary mobile ion is present.
        """
        from pymatgen.util.plotting_utils import get_publication_quality_plot
        plt = get_publication_quality_plot(12, 8, plt=plt)
        step = (self.corrected_displacements.shape[1] - 1) // (granularity - 1)
        f = (matching_s or self.structure).copy()
        f.remove_species([self.specie])
        sm = StructureMatcher(primitive_cell=False, stol=0.6,
                              comparator=OrderDisorderElementComparator(),
                              allow_subset=True)
        rms = []
        for s in self.get_drift_corrected_structures(step=step):
            s.remove_species([self.specie])
            d = sm.get_rms_dist(f, s)
            if d:
                rms.append(d)
            else:
                rms.append((1, 1))
        max_dt = (len(rms) - 1) * step * self.step_skip * self.time_step
        if max_dt > 100000:
            plot_dt = np.linspace(0, max_dt/1000, len(rms))
            unit = 'ps'
        else:
            plot_dt = np.linspace(0, max_dt, len(rms))
            unit = 'fs'
        rms = np.array(rms)
        plt.plot(plot_dt, rms[:, 0], label='RMS')
        plt.plot(plot_dt, rms[:, 1], label='max')
        plt.legend(loc='best')
        plt.xlabel("Timestep ({})".format(unit))
        plt.ylabel("normalized distance")
        plt.tight_layout()
        return plt
Пример #48
0
def test__EnumerateDistinctFacets():
    '''
    We take all the facets that the task are distinct/unique, then actually
    make slabs out of them and compare all the slabs to see if they are
    identical. Note that this tests only if we get repeats. It does not
    test if we missed anything.

    WARNING:  This test uses `run_task_locally`, which has a chance of
    actually submitting a FireWork to production. To avoid this, you must try
    to make sure that you have all of the gas calculations in the unit testing
    atoms collection.  If you copy/paste this test into somewhere else, make
    sure that you use `run_task_locally` appropriately.
    '''
    mpid = 'mp-2'
    max_miller = 2
    task = _EnumerateDistinctFacets(mpid=mpid, max_miller=max_miller)

    # Run the task to get the facets, and also get the bulk structure so we can
    # actually make slabs to check
    try:
        run_task_locally(task)
        distinct_millers = get_task_output(task)
        with open(task.input().path, 'rb') as file_handle:
            bulk_doc = pickle.load(file_handle)
        bulk_atoms = make_atoms_from_doc(bulk_doc)

        # Make all the slabs that the task said are distinct
        all_slabs = []
        for miller in distinct_millers:
            slabs = make_slabs_from_bulk_atoms(
                bulk_atoms,
                miller,
                SLAB_SETTINGS['slab_generator_settings'],
                SLAB_SETTINGS['get_slab_settings'],
            )
            all_slabs.extend(slabs)

        # Check that the slabs are actually different
        matcher = StructureMatcher()
        for slabs_to_compare in combinations(all_slabs, 2):
            assert not matcher.fit(*slabs_to_compare)

    finally:
        clean_up_tasks()
Пример #49
0
def match_structures(s1, s2, scale_lattice=False, rh_only=True):
    """
    Args
        s1: high sym structure
        s2: low sym structure
        scale_lattice (optional): high_sym_superlcell has same lattice vectors as s2 (no strain)
    Returns
        basis: should be the basis that when applied to s1 makes a supercell of the size and orentation of s2
        origin: any additional translation to best match (applied before applying the basis change to match what isotropy does)
        displacements
        high_sym_supercell
"""
    sm = StructureMatcher(ltol=0.3,
                          stol=0.3,
                          angle_tol=15,
                          scale=True,
                          attempt_supercell=True,
                          primitive_cell=False)
    basis, origin, mapping = sm.get_transformation(s1, s2, rh_only=rh_only)

    struct_hs_supercell = sm.get_s2_like_s1(s1, s2, rh_only=rh_only)

    # change origin from the supercell basis to the high sym basis
    origin = np.round_(frac_vec_convert(origin, struct_hs_supercell.lattice,
                                        s2.lattice),
                       decimals=5)
    if scale_lattice:
        hs_lat = struct_hs_supercell.lattice
        hs_std = pmg.Lattice.from_lengths_and_angles(hs_lat.abc, hs_lat.angles)
        ls_lat = s2.lattice
        ls_std = pmg.Lattice.from_lengths_and_angles(ls_lat.abc, ls_lat.angles)
        for aligned, rot, scale in hs_lat.find_all_mappings(hs_std):
            if (abs(aligned.matrix - hs_lat.matrix) < 1.e-3).all():
                strained_hs_lattice = pmg.Lattice(np.inner(ls_std.matrix, rot))
        struct_hs_supercell = pmg.Structure(
            strained_hs_lattice, struct_hs_supercell.species,
            [site.frac_coords for site in struct_hs_supercell])
    displacements = []
    for s_hs, s_ls in zip(struct_hs_supercell, s1):
        disp = np.round_(smallest_disp(s_hs.frac_coords, s_ls.frac_coords),
                         decimals=5)
        displacements.append(disp)
    return basis, origin, displacements, struct_hs_supercell
Пример #50
0
    def match(self, snls, mat):
        """
        Finds a material doc that matches with the given snl

        Args:
            snl ([dict]): the snls list
            mat (dict): a materials doc

        Returns:
            generator of materials doc keys
        """
        sm = StructureMatcher(
            ltol=self.ltol,
            stol=self.stol,
            angle_tol=self.angle_tol,
            primitive_cell=True,
            scale=True,
            attempt_supercell=False,
            allow_subset=False,
            comparator=ElementComparator())

        m_strucs = [Structure.from_dict(mat["structure"])
                    ] + [Structure.from_dict(init_struc) for init_struc in mat["initial_structures"]]
        for snl in snls:
            snl_struc = StructureNL.from_dict(snl).structure
            # Get SNL Spacegroup
            # This try-except fixes issues for some structures where space group data is not returned by spglib
            try:
                snl_spacegroup = snl_struc.get_space_group_info(symprec=0.1)[0]
            except:
                snl_spacegroup = -1
            for struc in m_strucs:

                # Get Materials Structure Spacegroup
                try:
                    struc_sg = struc.get_space_group_info(symprec=0.1)[0]
                except:
                    struc_sg = -1

                # Match spacegroups
                if struc_sg == snl_spacegroup and sm.fit(struc, snl_struc):
                    yield snl
                    break
Пример #51
0
    def setUp(self):
        self.test_ents_MOF = loadfn(get_path("Mn6O5F7_cat_migration.json",
                                             dirname="full_path_files"))
        self.aeccar_MOF = Chgcar.from_file(get_path("AECCAR_Mn6O5F7.vasp",
                                                    dirname="full_path_files"))
        self.cep = ComputedEntryPath(
            base_struct_entry=self.test_ents_MOF['ent_base'],
            migrating_specie='Li',
            single_cat_entries=self.test_ents_MOF['one_cation'],
            base_aeccar=self.aeccar_MOF
        )

        # structure matcher used for validation
        self.rough_sm = StructureMatcher(
            comparator=ElementComparator(),
            primitive_cell=False,
            ltol=0.5,
            stol=0.5,
            angle_tol=7)
Пример #52
0
    def _calculate_energies(self):
        energies = np.zeros((len(self.structure), len(self.structure)))

        dm = self.structure.distance_matrix

        non_dup_sites = []
        blocked = []
        for i, site in enumerate(self.structure):
            if i in blocked:
                continue
            non_dup_sites.append(site)
            blocked.extend(np.where(dm[i] < 0.001)[0])

        cs = self.ce.supercell_from_structure(
            Structure.from_sites(non_dup_sites))
        sm = StructureMatcher(primitive_cell=False,
                              attempt_supercell=False,
                              allow_subset=True,
                              scale=True,
                              comparator=OrderDisorderElementComparator())

        aligned = sm.get_s2_like_s1(cs.supercell, self.structure)
        dists = aligned.lattice.get_all_distances(aligned.frac_coords,
                                                  cs.supercell.frac_coords)
        lw_mapping = np.argmin(dists, axis=-1)

        bits = cs.bits
        exp_inds = np.where(
            np.sum(aligned.distance_matrix < 0.001, axis=-1) > 1)[0]

        for i in exp_inds:
            for j in exp_inds:
                if lw_mapping[i] == lw_mapping[j]:
                    continue
                occu = np.copy(cs.nbits)
                occu[lw_mapping[i]] = bits[lw_mapping[i]].index(
                    str(aligned[i].specie))
                occu[lw_mapping[j]] = bits[lw_mapping[j]].index(
                    str(aligned[j].specie))
                energies[i][j] = np.dot(cs.corr_from_occupancy(occu),
                                        self.ecis)

        return energies
Пример #53
0
    def __init__(self, structure_matcher=StructureMatcher(
                 comparator=ElementComparator()), symprec=None):
        """
        Remove duplicate structures based on the structure matcher
        and symmetry (if symprec is given).

        Args:
            structure_matcher: Provides a structure matcher to be used for
                structure comparison.
            symprec: The precision in the symmetry finder algorithm if None (
                default value), no symmetry check is performed and only the
                structure matcher is used. A recommended value is 1e-5.
        """
        self.symprec = symprec
        self.structure_list = defaultdict(list)
        if isinstance(structure_matcher, dict):
            self.structure_matcher = StructureMatcher.from_dict(structure_matcher)
        else:
            self.structure_matcher = structure_matcher
Пример #54
0
    def relaxed_structure_match(self, i, j):
        """
        Check if the relaxed structures of two interstitials match

        Args:
            i: Symmetrically distinct interstitial index
            j: Symmetrically distinct interstitial index

        .. note::

            To use relaxed bulk structure pass -1.
            -ve index will not work as expected
        """
        if not self._relax_struct:
            self._relax_analysis()
        sm = StructureMatcher()
        struct1 = self._relax_struct[i + 1]
        struct2 = self._relax_struct[j + 1]
        return sm.fit(struct1, struct2)
Пример #55
0
    def test_get_s2_large_s2(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                              primitive_cell=False, scale=False,
                              attempt_supercell=True, allow_subset=False,
                              supercell_size='volume')

        l = Lattice.orthorhombic(1, 2, 3)
        s1 = Structure(l, ['Ag', 'Si', 'Si'],
                       [[.7, .4, .5], [0, 0, 0.1], [0, 0, 0.2]])

        l2 = Lattice.orthorhombic(1.01, 2.01, 3.01)
        s2 = Structure(l2, ['Si', 'Si', 'Ag'],
                       [[0, 0.1, -0.95], [0, 0.1, 0], [-.7, .5, .375]])
        s2.make_supercell([[0, -1, 0], [1, 0, 0], [0, 0, 1]])

        result = sm.get_s2_like_s1(s1, s2)

        for x, y in zip(s1, result):
            self.assertLess(x.distance(y), 0.08)
Пример #56
0
    def test_get_supercells(self):
        sm = StructureMatcher(comparator=ElementComparator())
        l = Lattice.cubic(1)
        l2 = Lattice.cubic(0.5)
        s1 = Structure(l, ['Mg', 'Cu', 'Ag', 'Cu'], [[0] * 3] * 4)
        s2 = Structure(l2, ['Cu', 'Cu', 'Ag'], [[0] * 3] * 3)
        scs = list(sm._get_supercells(s1, s2, 8, False))
        for x in scs:
            self.assertAlmostEqual(abs(np.linalg.det(x[3])), 8)
            self.assertEqual(len(x[0]), 4)
            self.assertEqual(len(x[1]), 24)
        self.assertEqual(len(scs), 48)

        scs = list(sm._get_supercells(s2, s1, 8, True))
        for x in scs:
            self.assertAlmostEqual(abs(np.linalg.det(x[3])), 8)
            self.assertEqual(len(x[0]), 24)
            self.assertEqual(len(x[1]), 4)
        self.assertEqual(len(scs), 48)
Пример #57
0
def pymatgen_distances(structures,
                       comparator='OccupancyComparator',
                       distance_tol=0.01,
                       **kwargs):
    '''
    Distance based on pymatgen StructureMatcher rms distance
    Args:
        structures ([dict]): dictionary-encoded pymatgen Structure objects
        comparator (str): name of comparator object to use from ['StructureMatcher',
                                                 'AbstractComparator', 'ElementComparator',
                                                 'FrameworkComparator', 'OccupancyComparator',
                                                 'OrderDisorderElementComparator',
                                                 'SpeciesComparator', 'SpinComparator']
        distance_tol (float): distance below which distance will be rounded to 0
        **kwargs: **kwargs to be passed to pymatgen's StructureMatcher object
    Returns:
        [float]: RMS distances between structures; goes like
            1-2, 1-3, ..., 1-n, 2-3, 2-4, ..., 2-n, ...]
    '''
    comparators = {
        'AbstractComparator': AbstractComparator,
        'ElementComparator': ElementComparator,
        'FrameworkComparator': FrameworkComparator,
        'OccupancyComparator': OccupancyComparator,
        'OrderDisorderElemementComparator': OrderDisorderElementComparator,
        'SpeciesComparator': SpeciesComparator,
        'SpinComparator': SpinComparator,
        None: None
    }
    comparator = comparators[comparator]()
    structure_matcher = StructureMatcher(comparator=comparator, **kwargs)
    structures = [Structure.from_dict(structure) for structure in structures]
    stars = []
    distances = []
    for i, struct_1 in enumerate(structures):
        for j, struct_2 in enumerate(structures[i:]):
            if i != j + i:
                stars.append((struct_1, struct_2))
                # distance = structure_matcher.get_rms_dist(struct_1, struct_2)
                # if distance is not None:
                #     distance = list(distance)
                #     if distance[0] <= distance_tol:
                #         distance[0] = 0.
                # distances.append(distance)
    pool = mp.Pool()
    distances = pool.starmap(structure_matcher.get_rms_dist, stars)
    pool.close()
    pool.join()
    for d, distance in enumerate(distances):
        if distance is not None:
            distance = list(distance)
            if distance[0] <= distance_tol:
                distance[0] = 0.
        distances[d] = distance
    return distances
Пример #58
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(s1.lattice.get_all_distances(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)
Пример #59
0
def compare_structures(args):
    filenames = args.filenames
    if len(filenames) < 2:
        print("You need more than one structure to compare!")
        sys.exit(-1)
    try:
        structures = [Structure.from_file(fn) for fn in filenames]
    except Exception as ex:
        print("Error converting file. Are they in the right format?")
        print(str(ex))
        sys.exit(-1)

    m = StructureMatcher() if args.group == "species" \
        else StructureMatcher(comparator=ElementComparator())
    for i, grp in enumerate(m.group_structures(structures)):
        print("Group {}: ".format(i))
        for s in grp:
            print("- {} ({})".format(filenames[structures.index(s)],
                                     s.formula))
        print()
Пример #60
0
def test_enumerated_structures(kind, num_types, composition_constraints,
                               site_constraints):
    structure = get_lattice(kind)

    for index in range(1, 5):
        # TODO: when remove_superperiodic = remove_incomplete = False, this test is failed.
        zse = ZddStructureEnumerator(
            structure,
            index,
            num_types,
            composition_constraints=composition_constraints,
            base_site_constraints=site_constraints,
            remove_superperiodic=True,
            remove_incomplete=True,
        )
        list_dstructs = zse.generate()

        stm = StructureMatcher(ltol=1e-4, stol=1e-4)
        grouped = stm.group_structures(list_dstructs)
        assert len(grouped) == len(list_dstructs)