Пример #1
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)
Пример #2
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)
Пример #3
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())
Пример #4
0
def group_entries_with_structure_matcher(
    g,
    struct_matcher: StructureMatcher,
    working_ion: str = None,
) -> Iterable[List[Union[ComputedStructureEntry]]]:
    """
    Group the entries together based on similarity of the  primitive cells
    Args:
        g: a list of entries
        struct_matcher: the StructureMatcher object used to aggregate structures
        working_ion: the name of the working ion, if none use the first ignored species
            from the structure_matcher
    Returns:
        subgroups: subgroups that are grouped together based on structure similarity
    """
    if working_ion is None:
        wion = struct_matcher.as_dict()["ignored_species"][0]

    # Sort the entries by symmetry and by working ion fraction
    def get_num_sym_ops(ent):
        sga = SpacegroupAnalyzer(ent.structure)
        return len(sga.get_space_group_operations())

    g.sort(key=get_num_sym_ops, reverse=True)
    g.sort(key=lambda x: x.composition.get_atomic_fraction(wion))

    labs = generic_groupby(
        g,
        comp=lambda x, y: struct_matcher.fit(
            x.structure, y.structure, symmetric=True),
    )
    for ilab in set(labs):
        sub_g = [g[itr] for itr, jlab in enumerate(labs) if jlab == ilab]
        yield [el for el in sub_g]
Пример #5
0
def get_ion_insertion_wf(
    structure: Structure,
    working_ion: str,
    structure_matcher: StructureMatcher = None,
    db_file: str = DB_FILE,
    vasptodb_kwargs: dict = None,
    volumetric_data_type: str = "CHGCAR",
    vasp_powerups: List[dict] = None,
    attempt_insertions: int = 4,
    max_inserted_atoms: int = None,
    allow_fizzled_parents: bool = True,
    optimizefw_kwargs: dict = None,
    staticfw_kwargs: dict = None,
):
    """
    Take the output static worflow and iteratively insert working ions based on charge density analysis.

    The workflow performs the following tasks.
    (StaticFW) <- Recieved dat inserted task_id from this workflow
    (AnalyzeChgcar) <- Obtain the set of possible unique insertions using the stored charge density
    (GetInsertionCalcs) <- This task contains the dynamic workflow creation that will keep inserting working ions

    Args:
        structure: The host structure to begin inserting on
        working_ion: The working ion to be inserted at each step
        structure_matcher: StructureMatcher object used to define topotactic insertion
        db_file: The db_file that defines the VASP output database
        vasptodb_kwargs: vasptodb_kwargs for the static workflow
        volumetric_data_type: the type of volumetric data used to determine the insertion sites
        vasp_powerups: additional powerups given to all the dynamically created workflows
        optimizefw_kwargs: additional kwargs for all the OptimizeFWs
        max_inserted_atoms: the limit on the total number of ions to insert
        attempt_insertions: number of insertions sites to run at each insertion step
        staticfw_kwargs: additional kwargs for all the StaticFWs
    """

    if not structure.is_ordered:
        raise ValueError(
            "Please obtain an ordered approximation of the input structure.")

    if optimizefw_kwargs is None:
        optimizefw_kwargs = {}
    if staticfw_kwargs is None:
        staticfw_kwargs = {}

    # Configured the optimization and static FWs for the base material
    vasptodb_kwargs = vasptodb_kwargs if vasptodb_kwargs is not None else {}
    vasptodb_kwargs_vol_data = {
        "CHGCAR": ["CHGCAR"],
        "AECCAR": ["AECCAR0", "AECCAR2"]
    }

    vasptodb_kwargs.update({
        "store_volumetric_data":
        vasptodb_kwargs_vol_data[volumetric_data_type],
        "task_fields_to_push": {
            "base_task_id": "task_id"
        },
    })

    opt_wf = OptimizeFW(structure=structure,
                        db_file=db_file,
                        **optimizefw_kwargs)

    pass_task = pass_vasp_result(
        filename="vasprun.xml.relax2.gz",
        pass_dict=">>output.ionic_steps.-1.structure",
        mod_spec_key="prev_calc_structure",
    )
    opt_wf.tasks.append(pass_task)

    static_wf = StaticFW(structure=structure,
                         vasptodb_kwargs=vasptodb_kwargs,
                         db_file=db_file,
                         parents=[opt_wf],
                         spec_structure_key="prev_calc_structure",
                         **staticfw_kwargs)

    wf_name = "{}-{}".format(
        structure.composition.reduced_formula if structure else "unknown",
        "insertion",
    )

    # Configure the analysis FW
    analysis_wf = Firework(
        [AnalyzeChgcar(), GetInsertionCalcs()],
        parents=[static_wf],
        name="Charge Density Analysis-0",
    )
    analysis_wf.spec["working_ion"] = working_ion

    # Crate the initial workflow
    wf = Workflow([opt_wf, static_wf, analysis_wf], name=wf_name)

    # Apply the vasp powerup if present
    if vasp_powerups is not None:
        wf = powerup_by_kwargs(wf, vasp_powerups)
        for fw in wf.fws:
            fw.spec["vasp_powerups"] = vasp_powerups

    if structure_matcher is not None:
        sm_dict = structure_matcher.as_dict()
        for fw in wf.fws:
            fw.spec["structure_matcher"] = sm_dict

    # write the persistent specs to all the fws
    # Note this is probably redundant but is easier
    for fw in wf.fws:
        fw.spec["db_file"] = db_file
        fw.spec["attempt_insertions"] = attempt_insertions
        fw.spec["vasptodb_kwargs"] = vasptodb_kwargs
        fw.spec["staticfw_kwargs"] = staticfw_kwargs
        fw.spec["optimizefw_kwargs"] = optimizefw_kwargs
        fw.spec["allow_fizzled_parents"] = allow_fizzled_parents
        fw.spec["volumetric_data_type"] = volumetric_data_type
        fw.spec["max_inserted_atoms"] = max_inserted_atoms

    return wf