def predictions_structure_comparison(self, structure_dict, comparator=ElementComparator()): ''' Compares the entries in the same dictionary containing structures ''' ''' Returns a dictionary of structures that aren't repeated in the dictionary ''' sm = StructureMatcher(comparator=comparator, primitive_cell=False) filtered_structures = {} # new filtered dictionary seen_structures = {} # list of all seen structures, grouped by chemical system for chemsys in structure_dict: filtered_structures[chemsys] = [] seen_structures[chemsys] = [] for struct in structure_dict[chemsys]: found = False for seen_struct in seen_structures[chemsys]: if sm.fit(struct.final_structure, seen_struct.final_structure): found = True break if not found: filtered_structures[chemsys].append(struct) seen_structures[chemsys].append(struct) return filtered_structures
def filter_and_group_tasks(self, tasks): """ Groups tasks by structure matching """ filtered_tasks = [t for t in tasks if task_type( t['input']['incar']) in self.allowed_tasks] structures = [Structure.from_dict( t["output"]['structure']) for t in filtered_tasks] if self.separate_mag_orderings: for structure in structures: if has(structure.site_properties,"magmom"): structure.add_spin_by_site(structure.site_properties['magmom']) structure.remove_site_property('magmom') for idx, s in enumerate(structures): s.index = idx 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()) grouped_structures = sm.group_structures(structures) grouped_tasks = [[filtered_tasks[struc.index] for struc in group] for group in grouped_structures] return grouped_tasks
def MP_structure_comparison(self, structure_dict1, structure_dict2, comparator=ElementComparator()): ''' Compares the entries between two different dictionaries containing structures ''' ''' Returns a dictionary of structures that aren't present in both dictionaries ''' sm = StructureMatcher(comparator=comparator, primitive_cell=False) final_filtered_structs = {} for chemsys in structure_dict1.keys(): final_filtered_structs[chemsys] = [] if chemsys in structure_dict2.keys(): found = False for struct1 in structure_dict1[chemsys]: for struct2 in structure_dict2[chemsys]: if sm.fit(struct1.final_structure, struct2): found = True break if not found: final_filtered_structs[chemsys].append(struct1) else: final_filtered_structs[chemsys] = structure_dict1[chemsys] removed_empty_structs = {k: v for k, v in final_filtered_structs.items() if v != []} return removed_empty_structs
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
def __init__( self, existing_structures, structure_matcher=StructureMatcher(comparator=ElementComparator()), symprec=None, ): """ Remove existing structures based on the structure matcher and symmetry (if symprec is given). Args: existing_structures: List of existing structures to compare with 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 = [] self.existing_structures = existing_structures if isinstance(structure_matcher, dict): self.structure_matcher = StructureMatcher.from_dict(structure_matcher) else: self.structure_matcher = structure_matcher
def get_items(self): materials, jobs = self.sources matcher = StructureMatcher(ltol=LTOL, stol=STOL, angle_tol=ANGLE_TOL, primitive_cell=True, scale=True, attempt_supercell=False, comparator=ElementComparator()) jobs = list(jobs.query({"wflow.status": "release-ready"})) self.total = len(jobs) for job in jobs: structure = Structure.from_dict(job) criteria = { "pretty_formula": structure.composition.reduced_formula } material_id = next( (r['task_id'] for r in materials.query(criteria, ['structure', 'task_id']) if matcher.fit(structure, Structure.from_dict(r['structure'])) ), None) if material_id: yield ({ "snl_id": job["snl_id"] }, { "wflow.status": "released", "wflow.material_id": material_id })
def run_task(self, fw_spec): db = SPStructuresMongoAdapter.auto_load() tstructs = [] species = fw_spec['species'] t = fw_spec['threshold'] for p in SubstitutionPredictor(threshold=t).list_prediction(species): subs = p['substitutions'] if len(set(subs.values())) < len(species): continue st = SubstitutionTransformation(subs) target = map(str, subs.keys()) for snl in db.get_snls(target): ts = TransformedStructure.from_snl(snl) ts.append_transformation(st) if ts.final_structure.charge == 0: tstructs.append(ts) transmuter = StandardTransmuter(tstructs) f = RemoveDuplicatesFilter(structure_matcher=StructureMatcher( comparator=ElementComparator(), primitive_cell=False)) transmuter.apply_filter(f) results = [] for ts in transmuter.transformed_structures: results.append(ts.to_snl([]).to_dict) submissions = SPSubmissionsMongoAdapter.auto_load() submissions.insert_results(fw_spec['submission_id'], results)
def compare_structures(args): """ Compare structures in files for similarity using structure matcher. Args: args (dict): Args from argparse. """ 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()
def __init__(self, materials, electro, working_ion, query=None, compatibility=MaterialsProjectCompatibility("Advanced"), **kwargs): """ Calculates physical parameters of battery materials the battery entries using groups of ComputedStructureEntry and the entry for the most stable version of the working_ion in the system Args: materials (Store): Store of materials documents that contains the structures electro (Store): Store of insertion electrodes data such as voltage and capacity query (dict): dictionary to limit materials to be analyzed --- only applied to the materials when we need to group structures the phase diagram is still constructed with the entire set compatibility (PymatgenCompatability): Compatability module to ensure energies are compatible """ self.sm = StructureMatcher(comparator=ElementComparator(), primitive_cell=False) self.materials = materials self.electro = electro self.working_ion = working_ion self.query = query if query else {} self.compatibility = compatibility self.completed_tasks = set() self.working_ion_entry = None super().__init__(sources=[materials], targets=[electro], **kwargs)
def match(self, task, mats): """ Finds a material doc that matches with the given task Args: task (dict): the task doc mats ([dict]): the materials docs to match against Returns: dict: a materials doc if one is found otherwise returns None """ 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()) t_struct = Structure.from_dict(task["output"]["structure"]) for m in mats: m_struct = Structure.from_dict(m["structure"]) if task["output"]["spacegroup"]["number"] == m["spacegroup"]["number"] and \ sm.fit(m_struct, t_struct): return m return None
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)
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
def __init__(self, base_struct_entry, single_cat_entries, migrating_specie, base_aeccar=None, max_path_length=4, ltol=0.2, stol=0.3, angle_tol=5): """ Pass in a entries for analysis Args: base_struct_entry: the structure without a working ion for us to analyze the migration single_cat_entries: list of structures containing a single cation at different positions base_aeccar: Chgcar object that contains the AECCAR0 + AECCAR2 (Default value = None) migration_specie: a String symbol or Element for the cation. (Default value = 'Li') ltol: parameter for StructureMatcher (Default value = 0.2) stol: parameter for StructureMatcher (Default value = 0.3) angle_tol: parameter for StructureMatcher (Default value = 5) """ self.single_cat_entries = single_cat_entries self.base_struct_entry = base_struct_entry self.base_aeccar = base_aeccar self._tube_radius = 0 self.sm = StructureMatcher( comparator=ElementComparator(), primitive_cell=False, ignored_species=[migrating_specie], ltol=ltol, stol=stol, angle_tol=angle_tol) logger.debug('See if the structures all match') for ent in self.single_cat_entries: assert (self.sm.fit(self.base_struct_entry.structure, ent.structure)) self.translated_single_cat_entries = list( map(self.match_ent_to_base, self.single_cat_entries)) self.full_sites = self.get_full_sites() self.base_structure_full_sites = self.full_sites.copy() self.base_structure_full_sites.sites.extend( self.base_struct_entry.structure.sites) # Initialize super(ComputedEntryPath, self).__init__( structure=self.base_structure_full_sites, migrating_specie=migrating_specie, max_path_length=max_path_length, symprec=0.1, vac_mode=False) self.populate_edges_with_migration_paths() self.group_and_label_hops() self.get_unique_hops_dict() self._setup_grids()
def filter_entries(structure_type, all_entries, species, return_removed=False): """ Filter out the entry with exact same structure as queried entry among the entries in queried chemical space obtained from Materials Project. Used Pymatgen.analysis.structure_matcher.fit_anonymous to match the prototype of give structures. Args: structure_type(str): "garnet" or "perovskite" all_entries (list): entries in queried chemical space obtained from Materials Project composition (Composition): composition of queried entry return_removed (bool): If True, return the filtered entries Returns: filtered_entries (list) """ global MATCHER, PROTO if not MATCHER: MATCHER = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=True, comparator=ElementComparator()) if not PROTO: garnet_proto_path = os.path.join(DATA_DIR, "garnet/proto_mp-3050.cif") perov_proto_path = os.path.join(DATA_DIR, "perovskite/proto_mp-4019.cif") PROTO = { "garnet": Structure.from_file(garnet_proto_path).get_primitive_structure(), "perovskite": Structure.from_file(perov_proto_path).get_primitive_structure() } a_sites = [60, 61, 62, 63, 64, 65, 66, 67] for site_ind in a_sites: PROTO['garnet'].replace(site_ind, {"Ga": 1}) P = PROTO[structure_type].copy() if structure_type == 'garnet:': P.replace_species({ "Y": species['c'], "Ga": species['a'], "Al": species['d'] }) elif structure_type == 'perovskite': P.replace_species({"Ca": species['a'], "Ti": species['b']}) composition = Composition(spe2form(structure_type, species)) if not return_removed: return [e for e in all_entries \ if e.name != composition.reduced_formula \ and not MATCHER.fit(e.structure, P)] else: removed = [e for e in all_entries \ if e.name == composition.reduced_formula \ and MATCHER.fit(e.structure, P)] return removed, [e for e in all_entries if e not in removed]
def group_structures( structures, ltol=LTOL, stol=STOL, angle_tol=ANGLE_TOL, symprec=SYMPREC, separate_mag_orderings=False, ): """ Groups structures according to space group and structure matching Args: structures ([Structure]): list of structures to group ltol (float): StructureMatcher tuning parameter for matching tasks to materials stol (float): StructureMatcher tuning parameter for matching tasks to materials angle_tol (float): StructureMatcher tuning parameter for matching tasks to materials symprec (float): symmetry tolerance for space group finding separate_mag_orderings (bool): Separate magnetic orderings into different materials """ sm = StructureMatcher( ltol=ltol, stol=stol, angle_tol=angle_tol, primitive_cell=True, scale=True, attempt_supercell=False, allow_subset=False, comparator=ElementComparator(), ) def get_sg(struc): # helper function to get spacegroup with a loose tolerance try: sg = struc.get_space_group_info(symprec=SYMPREC)[1] except: sg = -1 return sg def get_mag_ordering(struc): # helperd function to get a label of the magnetic ordering type return np.around(np.abs(struc.total_magnetization) / struc.volume, decimals=1) # First group by spacegroup number then by structure matching for sg, pregroup in groupby(sorted(structures, key=get_sg), key=get_sg): for group in sm.group_structures(list(pregroup)): # Match magnetic orderings here if separate_mag_orderings: for _, mag_group in groupby(sorted(group, key=get_mag_ordering), key=get_mag_ordering): yield list(mag_group) else: yield group
def test_get_mask(self): sm = StructureMatcher(comparator=ElementComparator()) l = Lattice.cubic(1) s1 = Structure(l, ['Mg', 'Cu', 'Ag', 'Cu'], [[0] * 3] * 4) s2 = Structure(l, ['Cu', 'Cu', 'Ag'], [[0] * 3] * 3) result = [[True, False, True, False], [True, False, True, False], [True, True, False, True]] m, inds, i = sm._get_mask(s1, s2, 1, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 2) self.assertEqual(inds, [2]) # test supercell with match result = [[1, 1, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 1, 1, 0, 0], [1, 1, 1, 1, 0, 0, 1, 1]] m, inds, i = sm._get_mask(s1, s2, 2, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 2) self.assertTrue(np.allclose(inds, np.array([4]))) # test supercell without match result = [[1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 1, 1]] m, inds, i = sm._get_mask(s2, s1, 2, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 0) self.assertTrue(np.allclose(inds, np.array([]))) # test s2_supercell result = [[1, 1, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1], [1, 1, 0], [1, 1, 0], [0, 0, 1], [0, 0, 1]] m, inds, i = sm._get_mask(s2, s1, 2, False) self.assertTrue(np.all(m == result)) self.assertTrue(i == 0) self.assertTrue(np.allclose(inds, np.array([]))) # test for multiple translation indices s1 = Structure(l, ['Cu', 'Ag', 'Cu', 'Ag', 'Ag'], [[0] * 3] * 5) s2 = Structure(l, ['Ag', 'Cu', 'Ag'], [[0] * 3] * 3) result = [[1, 0, 1, 0, 0], [0, 1, 0, 1, 1], [1, 0, 1, 0, 0]] m, inds, i = sm._get_mask(s1, s2, 1, True) self.assertTrue(np.all(m == result)) self.assertTrue(i == 1) self.assertTrue(np.allclose(inds, [0, 2]))
def _match_material(self, taskdoc, ltol=0.2, stol=0.3, angle_tol=5): """ 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 ltol (float): StructureMatcher tuning parameter stol (float): StructureMatcher tuning parameter angle_tol (float): StructureMatcher tuning parameter Returns: (int) matching material_id or None """ formula = taskdoc["formula_reduced_abc"] # handle the "parent structure" option, which is used to intentionally force slightly # different structures to contribute to the same "material", e.g. from an ordering scheme if "parent_structure" in taskdoc: 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=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
def test_mix(self): structures = [] for fname in ["POSCAR.Li2O", "Li2O.cif", "Li2O2.cif", "LiFePO4.cif", "POSCAR.LiFePO4"]: structures.append(read_structure(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)
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=LTOL, stol=STOL, angle_tol=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: try: 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 except: self.logger.warning("Bad SNL found : {}".format( snl.get("task_id")))
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
def group_structures(structures, ltol=0.2, stol=0.3, angle_tol=5, symprec=0.1, separate_mag_orderings=False): """ Groups structures according to space group and structure matching Args: structures ([Structure]): list of structures to group ltol (float): StructureMatcher tuning parameter for matching tasks to materials stol (float): StructureMatcher tuning parameter for matching tasks to materials angle_tol (float): StructureMatcher tuning parameter for matching tasks to materials symprec (float): symmetry tolerance for space group finding separate_mag_orderings (bool): Separate magnetic orderings into different materials """ sm = StructureMatcher(ltol=ltol, stol=stol, angle_tol=angle_tol, primitive_cell=True, scale=True, attempt_supercell=False, allow_subset=False, comparator=ElementComparator()) def get_sg(struc): # helper function to get spacegroup with a loose tolerance return struc.get_space_group_info(symprec=symprec)[1] def get_mag_ordering(struc): # helperd function to get a label of the magnetic ordering type return CollinearMagneticStructureAnalyzer(struc).ordering.value # First group by spacegroup number then by structure matching for sg, pregroup in groupby(sorted(structures, key=get_sg), key=get_sg): for group in sm.group_structures(list(pregroup)): # Match magnetic orderings here if separate_mag_orderings: for _, mag_group in groupby(sorted(group, key=get_mag_ordering), key=get_mag_ordering): yield list(mag_group) else: yield group
def setUp(self): self.test_ents_MOF = loadfn( f'{dir_path}/full_path_files/Mn6O5F7_cat_migration.json') self.aeccar_MOF = Chgcar.from_file( f'{dir_path}/full_path_files/AECCAR_Mn6O5F7.vasp') 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)
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)
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 = map(read_structure, filenames) except Exception as ex: print "Error converting file. Are they in the right format?" print str(ex) sys.exit(-1) from pymatgen.analysis.structure_matcher import StructureMatcher, \ ElementComparator m = StructureMatcher() if args.oxi \ 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
def post_process(self, docs): s1 = Structure.from_dict(self.structure) m = StructureMatcher( ltol=self.ltol, stol=self.stol, angle_tol=self.angle_tol, primitive_cell=True, scale=True, attempt_supercell=False, comparator=ElementComparator(), ) matches = [] for doc in docs: s2 = Structure.from_dict(doc["structure"]) matched = m.fit(s1, s2) if matched: rms = m.get_rms_dist(s1, s2) matches.append({ "material_id": doc["material_id"], "normalized_rms_displacement": rms[0], "max_distance_paired_sites": rms[1], }) response = sorted( matches[:self.limit], key=lambda x: ( x["normalized_rms_displacement"], x["max_distance_paired_sites"], ), ) return response
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 try: snl_spacegroup = snl_struc.get_space_group_info()[0] except: snl_spacegroup = -1 for struc in m_strucs: try: struc_sg = struc.get_space_group_info()[0] except: struc_sg = -1 # The try-excepts are a temp fix to a spglib bug if struc_sg == snl_spacegroup and sm.fit(struc, snl_struc): yield snl break
def remove_multiple_cif(self): structMatch = StructureMatcher(ltol=0.05, stol=0.05, angle_tol=2, primitive_cell=False, scale=False, attempt_supercell=False, allow_subset=False, comparator=ElementComparator(), supercell_size='num_sites', ignored_species=None) for input_cif_file_path in glob.glob(self.ctx.input_cif_folder): input_cif_file = os.path.basename(input_cif_file_path) use_cif = True try: structure = Structure.from_file(input_cif_file_path) except: print('Structure import from cif not successful.') continue structure.remove_oxidation_states() for element in structure.composition.element_composition.elements: if str(element) not in self.ctx.element_list: use_cif = False for key in structures_used: if structMatch.fit(structure, structures_used[key]): use_cif = False self.ctx.structures_match_not_used[input_cif_file] = key if use_cif: self.ctx.structures_used[input_cif_file] = {} self.ctx.structures_used[input_cif_file][ 'structure_original'] = structure self.out('structures_match_not_used', ParameterData(dict=self.ctx.structures_match_not_used))
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 = [] if isinstance(structure_matcher, dict): self._sm = StructureMatcher.from_dict(structure_matcher) else: self._sm = structure_matcher
def group_structures(structures, ltol=0.2, stol=0.3, angle_tol=5, separate_mag_orderings=False): """ Groups structures according to space group and structure matching Args: structures ([Structure]): list of structures to group ltol (float): StructureMatcher tuning parameter for matching tasks to materials stol (float): StructureMatcher tuning parameter for matching tasks to materials angle_tol (float): StructureMatcher tuning parameter for matching tasks to materials separate_mag_orderings (bool): Separate magnetic orderings into different materials """ if separate_mag_orderings: for structure in structures: if has(structure.site_properties, "magmom"): structure.add_spin_by_site(structure.site_properties['magmom']) structure.remove_site_property('magmom') sm = StructureMatcher(ltol=ltol, stol=stol, angle_tol=angle_tol, primitive_cell=True, scale=True, attempt_supercell=False, allow_subset=False, comparator=ElementComparator()) def get_sg(struc): return struc.get_space_group_info(symprec=0.1)[1] # First group by spacegroup number then by structure matching for _, pregroup in groupby(sorted(structures, key=get_sg), key=get_sg): for group in sm.group_structures(sorted(pregroup, key=get_sg)): yield group
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 structures = [] 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())