Exemplo n.º 1
0
    def __init__(
        self,
        structure,
        name="static dipole moment",
        static_name="static",
        vasp_cmd="vasp",
        vasp_input_set=None,
        vasp_input_set_params=None,
        db_file=None,
        parents=None,
        gap_threshold=0.010,
        interpolate=False,
        start=None,
        end=None,
        this_image=0,
        nimages=5,
        **kwargs,
    ):
        """
        Static Firework that calculates the dipole moment of structure or a
        single interpolated image of structures output by two calculations
        specified by PassCalcLoc names start and end.

        This Firework uses three steps to calculate the dipole moment.

        1. A StaticFW or StaticInterpolatFW calculation is performed to compute
          the band gap of the structure.
        2. Because VASP cannot compute the dipole moment of metallic structures,
          CheckBandgap checks that the structure has a band gap greater than
          gap_threshold. If the structure has a band  gap less than
          gap_threshold, the Firework defuses. Otherwise,
        3. a polarization calculation (LCALCPOL=TRUE) is performed to calculate
          the dipole moment.

        If interpolate is equal to True, the keywords start and end are
        PassCalcLoc names used to locate the output structures (CONTCAR) of two
        previous calculations. These two structures must have the same number
        and type of atoms given in identical order in the structures. These
        structures are used to create nimages structures interpolations.

        this_image specifies which of the interpolated structures to use in this
        Firework. For example in the ferroelectric workflow, two structures that
        can be distorted into one another (a high-symmetry nonpolar structure
        and a low-symmetry polar structure) are relaxed using OptimizeFW. Then
        the dipole moment is calculated for nimages intermediate structures
        generated by interpolating between these two relaxed structures.

        Args:
            structure (Structure): Input structure. For an interpolation, this
                is a dummy structure. See interpolate arg description.
            name (str): Name for the polarization FireWork.
            static_name (str): Name for the SCF run to be used in PassCalcLoc
                if copy_vasp_outputs != True.
            vasp_cmd (str): Command to run vasp.
            vasp_input_set (str): string name for the VASP input set (e.g.,
                "MITMDVaspInputSet").
            vasp_input_set_params (dict): Dict of vasp_input_set_kwargs.
            db_file (str): Path to file specifying db credentials.
            parents (Firework): Parents of this particular Firework. FW or list
                of FWS.
            gap_threshold: Band gap cutoff for determining whether polarization
                calculation will proceed from SCF band gap.
            interpolate (bool): use structure created by interpolating CONTCAR
                structure from calculations indicated by start and end
                PassCalcLoc names. If interpolate is False, start and end do
                not need to be set.
            start (str): PassCalcLoc name of StaticFW or RelaxFW run of starting
                structure
            end (str): PassCalcLoc name of StaticFW or RelaxFW run of ending
                structure
            this_image (int): which interpolation to use for this run of the
                nimage interpolations.
            nimages (int): number of interpolations between CONTCAR structures
                from calculations indicated by start and end args.
        """
        t = []

        # Ensure that LWAVE is set to true so we can use WAVECAR for
        # polarization calculation.
        vasp_input_set_params = vasp_input_set_params or {}
        vasp_input_set_params = vasp_input_set_params.copy()

        if not vasp_input_set_params.get("user_incar_settings", None):
            vasp_input_set_params.update({"user_incar_settings": {}})
        vasp_input_set_params["user_incar_settings"].update({"LWAVE": True})

        vasp_input_set = vasp_input_set or "MPStaticSet"

        if interpolate:
            static = StaticInterpolateFW(
                structure,
                start,
                end,
                name=static_name,
                vasp_input_set=vasp_input_set,
                vasp_input_set_params=vasp_input_set_params,
                vasp_cmd=vasp_cmd,
                db_file=db_file,
                parents=parents,
                this_image=this_image,
                nimages=nimages,
                **kwargs,
            )
        else:
            vasp_input_set = MPStaticSet(structure, **vasp_input_set_params)
            static = StaticFW(
                structure,
                name=static_name,
                vasp_input_set=vasp_input_set,
                vasp_input_set_params=vasp_input_set_params,
                vasp_cmd=vasp_cmd,
                db_file=db_file,
                parents=parents,
                **kwargs,
            )
        t.extend(static.tasks)

        # Defuse workflow if bandgap is less than gap_threshold.
        t.append(CheckBandgap(min_gap=gap_threshold))

        # Create new directory and move to that directory to perform
        # polarization calculation
        t.append(CreateFolder(folder_name="polarization", change_dir=True))

        # Copy VASP Outputs from static calculation
        t.extend([
            CopyVaspOutputs(
                calc_loc=static_name,
                additional_files=["CHGCAR", "WAVECAR"],
                contcar_to_poscar=True,
            ),
            ModifyIncar(incar_update={"lcalcpol": True}),
            RunVaspCustodian(vasp_cmd=vasp_cmd),
            PassCalcLocs(name=name),
            VaspToDb(db_file=db_file, additional_fields={"task_label": name}),
        ])

        # Note, Outcar must have read_lcalcpol method for polarization
        # information to be processed. ...assuming VaspDrone will automatically
        # assimilate all properties of the Outcar.
        super().__init__(
            t,
            parents=parents,
            name=f"{structure.composition.reduced_formula}-{name}",
            **kwargs,
        )
Exemplo n.º 2
0
def get_wf_lobster_test_basis(
    structure: Structure,
    calculation_type: str = "standard",
    delete_all_wavecars: bool = True,
    c: dict = None,
    address_max_basis: Optional[str] = None,
    address_min_basis: Optional[str] = None,
    user_lobsterin_settings: dict = None,
    user_incar_settings: dict = None,
    user_kpoints_settings: dict = None,
    isym: int = 0,
    additional_outputs: List[str] = None,
) -> Workflow:
    """
    creates workflow where all possible basis functions for one compound are tested
    at the end, the user has to decide which projection worked best (e.g., based on chargespilling)
    this is the recommended workflow at the moment!
    Args:
        structure (Structure): structure object that will be used during the run
        calculation_type (str): only "standard" is implemented so far
        delete_all_wavecars (bool): all wavecars wil be deleted if True
        c (dict): specifications for wf, e.g. VASP_CMD, LOBSTER_CMD etc.
        address_max_basis (str): address to yaml file including maximum basis set (otherwise predefined file)
        address_min_basis (str): address to yaml file including minimum basis set (otherwise predefined file)
        user_lobsterin_settings (dict): change lobsterin settings here
        user_incar_settings (dict): change incar settings with this dict
        user_kpoints_settings (dict): change kpoint settings with this dict
        isym (int): isym setting during the VASP calculation, currently lobster can only deal with isym=-1 and isym=0
        additional_outputs (list): list of additional files to be stored in the
            results DB. They will be stored as files in gridfs. Examples are:
            "ICOHPLIST.lobster" or "DOSCAR.lobster". Note that the file name
            should be given with the full name and the correct capitalization.
    Returns:
    """

    c = c or {}

    vasp_cmd = c.get("VASP_CMD", VASP_CMD)
    lobster_cmd = c.get("LOBSTER_CMD", LOBSTER_CMD)
    db_file = c.get("DB_FILE", DB_FILE)

    fws = []
    # get the relevant potcar files!
    inputset = LobsterSet(
        structure,
        address_basis_file=address_max_basis,
        user_incar_settings=user_incar_settings,
        user_kpoints_settings=user_kpoints_settings,
        isym=isym,
    )
    # get the basis from dict_max_basis
    potcar_symbols = inputset.potcar_symbols

    # will get all possible basis functions that have to be tested
    if address_max_basis is None and address_min_basis is None:
        list_basis_dict = Lobsterin.get_all_possible_basis_functions(
            structure=structure, potcar_symbols=potcar_symbols)
    elif address_max_basis is not None and address_min_basis is None:
        list_basis_dict = Lobsterin.get_all_possible_basis_functions(
            structure=structure,
            potcar_symbols=potcar_symbols,
            address_basis_file_max=address_max_basis,
        )
    elif address_min_basis is not None and address_max_basis is None:
        list_basis_dict = Lobsterin.get_all_possible_basis_functions(
            structure=structure,
            potcar_symbols=potcar_symbols,
            address_basis_file_min=address_min_basis,
        )
    elif address_min_basis is not None and address_max_basis is not None:
        list_basis_dict = Lobsterin.get_all_possible_basis_functions(
            structure=structure,
            potcar_symbols=potcar_symbols,
            address_basis_file_max=address_max_basis,
            address_basis_file_min=address_min_basis,
        )

    staticfw = StaticFW(
        structure=structure,
        vasp_input_set=inputset,
        vasp_cmd=vasp_cmd,
        db_file=db_file,
        name="static",
    )
    fws.append(staticfw)

    # append all lobster calculations that need to be done
    fws_lobster = []
    for ibasis, basis_dict in enumerate(list_basis_dict):
        fws_lobster.append(
            LobsterFW(
                structure=structure,
                parents=staticfw,
                calculation_type=calculation_type,
                delete_wavecar=delete_all_wavecars,
                delete_wavecar_previous_fw=False,
                lobster_cmd=lobster_cmd,
                db_file=db_file,
                user_supplied_basis=basis_dict,
                lobsterin_key_dict=user_lobsterin_settings,
                handler_group="default",
                validator_group="strict",
                name="lobster_calculation_{}".format(ibasis),
                lobstertodb_kwargs={
                    "basis_id": ibasis,
                    "number_lobster_runs": len(list_basis_dict),
                },
                additional_outputs=additional_outputs,
            ))

    fws.extend(fws_lobster)
    # wavecar from static run is deleted, WAVECARs without symmetry can be huge!
    if delete_all_wavecars:
        t = DeleteFilesPrevFolder(files=["WAVECAR", "WAVECAR.gz"],
                                  calc_loc="static")
        final_fw = Firework([t], parents=fws_lobster, name="DelteWavecar")
        fws.append(final_fw)

    workflow = Workflow(fws, name="LobsterWorkflow")
    return workflow
Exemplo n.º 3
0
def get_wf_lobster(
    structure: Structure,
    calculation_type: str = "standard",
    delete_all_wavecars: bool = True,
    user_lobsterin_settings: dict = None,
    user_incar_settings: dict = None,
    user_kpoints_settings: dict = None,
    user_supplied_basis: dict = None,
    isym: int = 0,
    c: dict = None,
    additional_outputs: List[str] = None,
) -> Workflow:
    """
    Creates a workflow for a static Vasp calculation followed by a Lobster calculation.

    Args:
        structure: Structure object
        calculation_type: type of the Lobster calculation
        delete_all_wavecars: if True, all WAVECARs are deleted
        user_lobsterin_settings (dict): dict to set additional lobsterin settings
        user_incar_settings (dict): dict to set additional things in INCAR
        user_kpoints_settings (dict): dict to set additional things in KPOINTS
        user_supplied_basis (dict): dict to supply basis functions for each element type
        isym (int): isym setting during the vasp calculation, currently lobster can only deal with isym=-1
        c (dict): configurations dict which can include "VASP_CMD", "LOBSTER_CMD", "DB_FILE"
        additional_outputs (list): list of additional files to be stored in the
            results DB. They will be stored as files in gridfs. Examples are:
            "ICOHPLIST.lobster" or "DOSCAR.lobster". Note that the file name
            should be given with the full name and the correct capitalization.

    Returns: Workflow


    """

    c = c or {}

    vasp_cmd = c.get("VASP_CMD", VASP_CMD)
    lobster_cmd = c.get("LOBSTER_CMD", LOBSTER_CMD)
    db_file = c.get("DB_FILE", DB_FILE)

    fws = []
    staticfw = StaticFW(
        structure=structure,
        vasp_input_set=LobsterSet(
            structure,
            user_incar_settings=user_incar_settings,
            user_kpoints_settings=user_kpoints_settings,
            isym=isym,
        ),
        vasp_cmd=vasp_cmd,
        db_file=db_file,
    )
    fws.append(staticfw)
    fws.append(
        LobsterFW(
            structure=structure,
            parents=staticfw,
            calculation_type=calculation_type,
            delete_wavecar=delete_all_wavecars,
            delete_wavecar_previous_fw=delete_all_wavecars,
            lobster_cmd=lobster_cmd,
            db_file=db_file,
            lobsterin_key_dict=user_lobsterin_settings,
            user_supplied_basis=user_supplied_basis,
            handler_group="default",
            validator_group="strict",
            additional_outputs=additional_outputs,
        ))

    workflow = Workflow(fws, name="LobsterWorkflow")
    return workflow
Exemplo n.º 4
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