Ejemplo n.º 1
0
def get_relax_static_wf(structures,
                        vasp_cmd=">>vasp_cmd<<",
                        db_file=">>db_file<<",
                        name="regular_relax",
                        **kwargs):
    """
    :param structures:
    :param vasp_cmd:
    :param db_file:
    :param name:
    :param kwargs:
    :return:
    """
    wfs = []
    for s in structures:
        fw1 = OptimizeFW(s,
                         vasp_cmd=vasp_cmd,
                         db_file=db_file,
                         parents=[],
                         **kwargs)
        fw2 = StaticFW(s, vasp_cmd=vasp_cmd, db_file=db_file, parents=[fw1])
        wfs.append(
            Workflow([fw1, fw2],
                     name=name + str(s.composition.reduced_formula)))
    return wfs
Ejemplo n.º 2
0
def get_wf_molecules(molecules,
                     vasp_input_set=None,
                     db_file=None,
                     vasp_cmd="vasp",
                     name=""):
    """
    Args:
        molecules (Molecules): list of molecules to calculate
        vasp_input_set (DictSet): VaspInputSet for molecules
        db_file (string): database file path
        vasp_cmd (string): VASP command
        name (string): name for workflow

    Returns:
        workflow consisting of molecule calculations
    """
    fws = []

    for molecule in molecules:
        # molecule in box
        m_struct = molecule.get_boxed_structure(10,
                                                10,
                                                10,
                                                offset=np.array([5, 5, 5]))
        vis = vasp_input_set or MPSurfaceSet(m_struct)
        fws.append(
            OptimizeFW(structure=molecule,
                       job_type="normal",
                       vasp_input_set=vis,
                       db_file=db_file,
                       vasp_cmd=vasp_cmd))
    name = name or "molecules workflow"
    return Workflow(fws, name=name)
Ejemplo n.º 3
0
def get_wf_structure_sampler(xdatcar_file,
                             n=10,
                             steps_skip_first=1000,
                             vasp_cmd=">>vasp_cmd<<",
                             db_file=">>db_file<<",
                             name="structure_sampler",
                             **kwargs):
    """
    :param xdatcar_file:
    :param n:
    :param steps_skip_first:
    :param vasp_cmd:
    :param db_file:
    :param name:
    :param kwargs:
    :return:
    """
    structures = get_sample_structures(xdatcar_path=xdatcar_file,
                                       n=n,
                                       steps_skip_first=steps_skip_first)
    wfs = []
    for s in structures:
        fw1 = OptimizeFW(s,
                         vasp_cmd=vasp_cmd,
                         db_file=db_file,
                         parents=[],
                         **kwargs)
        fw2 = StaticFW(s, vasp_cmd=vasp_cmd, db_file=db_file, parents=[fw1])
        wfs.append(
            Workflow([fw1, fw2],
                     name=name + str(s.composition.reduced_formula)))
    return wfs
Ejemplo n.º 4
0
    def run_task(self, fw_spec):

        #create structure from CONTCAR
        struct = Poscar.from_file('CONTCAR').structure

        #repeat layers of bulk to create supercell
        struct.make_supercell([1, 1, self.get("num_layers", 2)])

        #add vacuum to create slab
        struct = add_vacuum(struct, self.get("vacuum", 15))

        #add selective dynamics
        selective_dynamics = []
        """
        min_bulk = self.get("surf_layers_to_relax",3)/(self.get("atomic_thickness")*self.get("num_layers",2)) * max([site.z for site in struct.sites])
        
        max_bulk = (self.get("atomic_thickness")*self.get("num_layers",2) - self.get("surf_layers_to_relax",3))/(self.get("atomic_thickness")*self.get("num_layers",2)) * max([site.z for site in struct.sites])
                     
        for site in struct.sites:
            if site.z > min_bulk and site.z <= max_bulk:
                selective_dynamics.append([False, False, False])
            else:
                selective_dynamics.append([True, True, True])
        struct.add_site_property("selective_dynamics", selective_dynamics)
        """
        #create optimize and static fireworks using the newly created slab
        slab_optimize = OptimizeFW(struct,
                                   name=name + '_slab_optimization' + time,
                                   vasp_cmd=">>vasp_cmd<<",
                                   db_file=">>db_file<<",
                                   parents=[bulk_optimize])

        slab_optimize = Workflow(slab_optimize)
        optimize_incar_settings = {"ISIF": 2}
        optimize_update = {"incar_update": optimize_incar_settings}
        slab_optimize = add_modify_incar(slab_optimize,
                                         modify_incar_params=optimize_update,
                                         fw_name_constraint='optimization')

        slab_static = StaticFW(struct,
                               name=name + '_slab_static_' + time,
                               parents=[slab_optimize],
                               prev_calc_loc=True,
                               vasp_cmd=">>vasp_cmd<<",
                               db_file=">>db_file<<")
        #slab_static.tasks.append(Slab_energy_and_SA())

        #surface_energy_calc_fw = Firework(Surface_energy_calc(), parents = [bulk_static, slab_static])

        #return FWAction(additions = [slab_optimize, slab_static, surface_energy_calc_fw])
        return FWAction(additions=[slab_optimize, slab_static])
Ejemplo n.º 5
0
def get_wf_ferroelectric(polar_structure,
                         nonpolar_structure,
                         vasp_cmd="vasp",
                         db_file=None,
                         vasp_input_set_polar="MPStaticSet",
                         vasp_input_set_nonpolar="MPStaticSet",
                         relax=False,
                         vasp_relax_input_set_polar=None,
                         vasp_relax_input_set_nonpolar=None,
                         nimages=9,
                         hse=False,
                         add_analysis_task=False,
                         wfid=None,
                         tags=None):
    """
    Returns a workflow to calculate the spontaneous polarization of polar_structure using
    a nonpolar reference phase structure and linear interpolations between the polar and
    nonpolar structure.

    The nonpolar and polar structures must be in the same space group setting and atoms ordered
    such that a linear interpolation can be performed to create intermediate structures along
    the distortion.

    For example, to calculate the polarization of orthorhombic BaTiO3 (space group 38) using
    the cubic structure (space group 221) as the nonpolar reference phase, we must transform
    the cubic to the orthorhombic setting. This can be accomplished using Bilbao Crystallographic
    Server's Structure Relations tool. (http://www.cryst.ehu.es/cryst/rel.html)

    Args:
        polar_structure (Structure): polar structure of candidate ferroelectric
        nonpolar_structure (Structure): nonpolar reference structure in polar setting
        vasp_input_set_polar (DictVaspInputSet): VASP polar input set. Defaults to MPStaticSet.
        vasp_input_set_nonpolar (DictVaspInputSet): VASP nonpolar input set. Defaults to MPStaticSet.
        vasp_relax_input_set_polar (DictVaspInputSet): VASP polar input set. Defaults to MPRelaxSet.
        vasp_relax_input_set_nonpolar (DictVaspInputSet): VASP nonpolar input set. Defaults to MPRelaxSet.
        vasp_cmd (str): command to run
        db_file (str): path to file containing the database credentials.
        nimages: Number of interpolations calculated from polar to nonpolar structures, including the nonpolar.
            For example, nimages = 9 will calculate 8 interpolated structures. 8 interpolations + nonpolar = 9.
        add_analysis_task: Analyze polarization and energy trends as part of workflow. Default False.
        wfid (string): Unique worfklow id starting with "wfid_". If None this is atomatically generated (recommended).
        tags (list of strings): Additional tags to add such as identifiers for structures.

    Returns:

    """
    wf = []

    if wfid is None:
        wfid = 'wfid_' + get_a_unique_id()
    if tags is None:
        tags = []

    if relax:
        polar_relax = OptimizeFW(structure=polar_structure,
                                 name="_polar_relaxation",
                                 vasp_cmd=vasp_cmd,
                                 db_file=db_file,
                                 vasp_input_set=vasp_relax_input_set_polar)
        nonpolar_relax = OptimizeFW(
            structure=nonpolar_structure,
            name="_nonpolar_relaxation",
            vasp_cmd=vasp_cmd,
            db_file=db_file,
            vasp_input_set=vasp_relax_input_set_nonpolar)
        wf.append(polar_relax)
        wf.append(nonpolar_relax)
        parents_polar = polar_relax
        parents_nonpolar = nonpolar_relax
    else:
        parents_polar = None
        parents_nonpolar = None

    # Run polarization calculation on polar structure.
    # Defuse workflow if polar structure is metallic.
    polar = LcalcpolFW(structure=polar_structure,
                       name="_polar_polarization",
                       static_name="_polar_static",
                       parents=parents_polar,
                       vasp_cmd=vasp_cmd,
                       db_file=db_file,
                       vasp_input_set=vasp_input_set_polar)

    # Run polarization calculation on nonpolar structure.
    # Defuse workflow if nonpolar structure is metallic.
    nonpolar = LcalcpolFW(structure=nonpolar_structure,
                          name="_nonpolar_polarization",
                          static_name="_nonpolar_static",
                          parents=parents_nonpolar,
                          vasp_cmd=vasp_cmd,
                          db_file=db_file,
                          vasp_input_set=vasp_input_set_nonpolar)

    # Interpolation polarization
    interpolation = []
    # Interpolations start from one increment after polar and end prior to nonpolar.
    # The Structure.interpolate method adds an additional image for the nonpolar endpoint.
    # Defuse children fireworks if metallic.
    for i in range(1, nimages):
        # nonpolar_structure is being used as a dummy structure.
        # The structure will be replaced by the interpolated structure generated by
        # StaticInterpolatedFW.
        # Defuse workflow if interpolated structure is metallic.
        interpolation.append(
            LcalcpolFW(structure=polar_structure,
                       name="_interpolation_{}_polarization".format(str(i)),
                       static_name="_interpolation_{}_static".format(str(i)),
                       vasp_cmd=vasp_cmd,
                       db_file=db_file,
                       vasp_input_set=vasp_input_set_polar,
                       interpolate=True,
                       start="_polar_static",
                       end="_nonpolar_static",
                       nimages=nimages,
                       this_image=i,
                       parents=[polar, nonpolar]))

    wf.append(polar)
    wf.append(nonpolar)
    wf += interpolation

    # Add FireTask that uses Polarization object to store spontaneous polarization information
    if add_analysis_task:
        fw_analysis = Firework(PolarizationToDb(db_file=db_file),
                               parents=interpolation,
                               name="_polarization_post_processing")
        wf.append(fw_analysis)

    # Run HSE band gap calculation
    if hse:
        # Run HSE calculation at band gap for polar calculation if polar structure is not metallic
        hse = HSEBSFW(structure=polar_structure,
                      parents=polar,
                      name="_polar_hse_gap",
                      vasp_cmd=vasp_cmd,
                      db_file=db_file,
                      calc_loc="_polar_polarization")
        wf.append(hse)

    # Create Workflow task and add tags to workflow
    workflow = Workflow(wf)
    workflow = add_tags(workflow, [wfid] + tags)

    return workflow
Ejemplo n.º 6
0
def get_slab_fw(slab,
                transmuter=False,
                db_file=None,
                vasp_input_set=None,
                parents=None,
                vasp_cmd="vasp",
                name="",
                add_slab_metadata=True,
                user_incar_settings=None):
    """
    Function to generate a a slab firework.  Returns a TransmuterFW if
    bulk_structure is specified, constructing the necessary transformations
    from the slab and slab generator parameters, or an OptimizeFW if only a
    slab is specified.

    Args:
        slab (Slab or Structure): structure or slab corresponding
            to the slab to be calculated
        transmuter (bool): whether or not to use a TransmuterFW based
            on slab params, if this option is selected, input slab must
            be a Slab object (as opposed to Structure)
        vasp_input_set (VaspInputSet): vasp_input_set corresponding to
            the slab calculation
        parents (Fireworks or list of ints): parent FWs
        db_file (string): path to database file
        vasp_cmd (string): vasp command
        name (string): name of firework
        add_slab_metadata (bool): whether to add slab metadata to task doc

    Returns:
        Firework corresponding to slab calculation
    """
    vasp_input_set = vasp_input_set or MPSurfaceSet(
        slab, user_incar_settings=user_incar_settings)

    # If a bulk_structure is specified, generate the set of transformations,
    # else just create an optimize FW with the slab
    if transmuter:
        if not isinstance(slab, Slab):
            raise ValueError(
                "transmuter mode requires slab to be a Slab object")

        # Get transformation from oriented bulk and slab
        oriented_bulk = slab.oriented_unit_cell
        slab_trans_params = get_slab_trans_params(slab)
        trans_struct = SlabTransformation(**slab_trans_params)
        slab_from_bulk = trans_struct.apply_transformation(oriented_bulk)

        # Ensures supercell construction
        supercell_trans = SupercellTransformation.from_scaling_factors(
            round(slab.lattice.a / slab_from_bulk.lattice.a),
            round(slab.lattice.b / slab_from_bulk.lattice.b))

        # Get site properties, set velocities to zero if not set to avoid
        # custodian issue
        site_props = slab.site_properties
        if 'velocities' not in site_props:
            site_props['velocities'] = [0. for s in slab]

        # Get adsorbates for InsertSitesTransformation
        if "adsorbate" in slab.site_properties.get("surface_properties", ""):
            ads_sites = [
                site for site in slab
                if site.properties["surface_properties"] == "adsorbate"
            ]
        else:
            ads_sites = []
        transformations = [
            "SlabTransformation", "SupercellTransformation",
            "InsertSitesTransformation", "AddSitePropertyTransformation"
        ]
        trans_params = [
            slab_trans_params, {
                "scaling_matrix": supercell_trans.scaling_matrix
            }, {
                "species": [site.species_string for site in ads_sites],
                "coords": [site.frac_coords for site in ads_sites]
            }, {
                "site_properties": site_props
            }
        ]
        fw = TransmuterFW(name=name,
                          structure=oriented_bulk,
                          transformations=transformations,
                          transformation_params=trans_params,
                          copy_vasp_outputs=True,
                          db_file=db_file,
                          vasp_cmd=vasp_cmd,
                          parents=parents,
                          vasp_input_set=vasp_input_set)
    else:
        fw = OptimizeFW(name=name,
                        structure=slab,
                        vasp_input_set=vasp_input_set,
                        vasp_cmd=vasp_cmd,
                        db_file=db_file,
                        parents=parents,
                        job_type="normal")
    # Add slab metadata
    if add_slab_metadata:
        parent_structure_metadata = get_meta_from_structure(
            slab.oriented_unit_cell)
        fw.tasks[-1]["additional_fields"].update({
            "slab":
            slab,
            "parent_structure":
            slab.oriented_unit_cell,
            "parent_structure_metadata":
            parent_structure_metadata
        })
    return fw
Ejemplo n.º 7
0
def get_wf_slab(slab,
                include_bulk_opt=False,
                adsorbates=None,
                ads_structures_params=None,
                ads_site_finder_params=None,
                vasp_cmd="vasp",
                db_file=None,
                add_molecules_in_box=False,
                user_incar_settings=None):
    """
    Gets a workflow corresponding to a slab calculation along with optional
    adsorbate calcs and precursor oriented unit cell optimization

    Args:
        slabs (list of Slabs or Structures): slabs to calculate
        include_bulk_opt (bool): whether to include bulk optimization,
            this flag sets the slab fireworks to be TransmuterFWs based
            on bulk optimization of oriented unit cells
        adsorbates ([Molecule]): list of molecules to place as adsorbates
        ads_structures_params (dict): parameters to be supplied as
            kwargs to AdsorbateSiteFinder.generate_adsorption_structures
        add_molecules_in_box (boolean): flag to add calculation of
            adsorbate molecule energies to the workflow
        db_file (string): path to database file
        vasp_cmd (string): vasp command

    Returns:
        Workflow
    """
    fws, parents = [], []

    if adsorbates is None:
        adsorbates = []

    if ads_structures_params is None:
        ads_structures_params = {}

    # Add bulk opt firework if specified
    if include_bulk_opt:
        oriented_bulk = slab.oriented_unit_cell
        vis = MPSurfaceSet(oriented_bulk, bulk=True)
        fws.append(
            OptimizeFW(structure=oriented_bulk,
                       vasp_input_set=vis,
                       vasp_cmd=vasp_cmd,
                       db_file=db_file))
        parents = fws[-1]

    name = slab.composition.reduced_formula
    if getattr(slab, "miller_index", None):
        name += "_{}".format(slab.miller_index)
    # Create slab fw and add it to list of fws
    slab_fw = get_slab_fw(slab,
                          include_bulk_opt,
                          db_file=db_file,
                          vasp_cmd=vasp_cmd,
                          parents=parents,
                          name="{} slab optimization".format(name))
    fws.append(slab_fw)

    for adsorbate in adsorbates:
        ads_slabs = AdsorbateSiteFinder(
            slab, **ads_site_finder_params).generate_adsorption_structures(
                adsorbate, **ads_structures_params)
        for n, ads_slab in enumerate(ads_slabs):
            # Create adsorbate fw
            ads_name = "{}-{} adsorbate optimization {}".format(
                adsorbate.composition.formula, name, n)
            adsorbate_fw = get_slab_fw(ads_slab,
                                       include_bulk_opt,
                                       db_file=db_file,
                                       vasp_cmd=vasp_cmd,
                                       parents=parents,
                                       name=ads_name,
                                       user_incar_settings=user_incar_settings)
            fws.append(adsorbate_fw)

    if isinstance(slab, Slab):
        name = "{}_{} slab workflow".format(
            slab.composition.reduced_composition, slab.miller_index)
    else:
        name = "{} slab workflow".format(slab.composition.reduced_composition)

    wf = Workflow(fws, name=name)

    # Add optional molecules workflow
    if add_molecules_in_box:
        molecule_wf = get_wf_molecules(adsorbates,
                                       db_file=db_file,
                                       vasp_cmd=vasp_cmd)
        wf.append_wf(molecule_wf)

    return wf
Ejemplo n.º 8
0
def generate_lattconst_wf(list_elt_sets,
                          functional='PBE',
                          vasp_cmd='>>vasp_cmd<<',
                          db_file='>>db_file<<',
                          submit=False,
                          scan_smart_lattice=None):
    """Generates a workflow which calculates lattice constants
    through optimization fireworks for a given functional type

    NOTE: that the SCAN functionality might be reliant on some Custodian features from Danny's Custodian
    """

    if functional in ['PBE', 'LDA']:
        job_type = 'double_relaxation_run'
        potcar_type = functional
        incar_settings = {"ADDGRID": True, 'EDIFF': 1e-8}
    elif functional in ['SCAN']:
        job_type = 'metagga_opt_run'
        potcar_type = 'PBE'  #this is the POTCAR that needs to be used for SCAN...
        incar_settings = {'EDIFF': 1e-8, 'ISIF': 7}
        if scan_smart_lattice is None:
            raise ValueError("Need to provide a smarter starting point "
                             "for SCAN lattice constants...")

    fws = []

    for elt_set in list_elt_sets:
        if functional == 'SCAN':
            compkey = Composition({
                elt_set[0]: 1,
                elt_set[1]: 1,
                elt_set[2]: 3
            })
            lattconst = scan_smart_lattice[compkey]
        else:
            lattconst = None
        pp = PerfectPerovskite(Asite=elt_set[0],
                               Bsite=elt_set[1],
                               Osite=elt_set[2],
                               lattconst=lattconst)
        s = pp.get_111_struct()

        vis = MPRelaxSet(s,
                         user_incar_settings=incar_settings,
                         potcar_functional=potcar_type)

        fw = OptimizeFW(s,
                        name="{} {} structure optimization".format(
                            s.composition.reduced_formula, functional),
                        vasp_input_set=vis,
                        vasp_cmd=vasp_cmd,
                        db_file=db_file,
                        job_type=job_type,
                        auto_npar=">>auto_npar<<")
        fws.append(fw)

    wf = Workflow(fws, name='{} latt const workflow'.format(functional))
    if submit:
        print('Submitting workflow with {} fws for {}'.format(
            len(list_elt_sets), functional))
        lpad = LaunchPad().from_file(lpad_file_path)
        lpad.add_wf(wf)
    else:
        print('Workflow created with {} fws for {}'.format(
            len(list_elt_sets), functional))
        return wf
Ejemplo n.º 9
0
    def get_wf(self,
               scan=False,
               perform_bader=True,
               num_orderings_hard_limit=16,
               c=None):
        """
        Retrieve the FireWorks workflow.

        Args:
            scan (bool): if True, use the SCAN functional instead of GGA+U,
                since the SCAN functional has shown to have improved
                performance for magnetic systems in some cases
            perform_bader (bool): if True, make sure the "bader" binary is in
                your path, will use Bader analysis to calculate
                atom-projected magnetic moments
            num_orderings_hard_limit (int): will make sure total number of
                magnetic orderings does not exceed this number even if there
                are extra orderings of equivalent symmetry
            c (dict): additional config dict (as used elsewhere in atomate)

        Returns: FireWorks Workflow

        """

        c_defaults = {"VASP_CMD": VASP_CMD, "DB_FILE": DB_FILE}
        additional_fields = {"relax": not self.static}
        c = c or {}
        for k, v in c_defaults.items():
            if k not in c:
                c[k] = v

        fws = []
        analysis_parents = []

        # trim total number of orderings (useful in high-throughput context)
        # this is somewhat course, better to reduce num_orderings kwarg and/or
        # change enumeration strategies
        ordered_structures = self.ordered_structures
        ordered_structure_origins = self.ordered_structure_origins

        def _add_metadata(structure):
            """
            For book-keeping, store useful metadata with the Structure
            object for later database ingestion including workflow
            version and a UUID for easier querying of all tasks generated
            from the workflow.

            Args:
                structure: Structure

            Returns: TransformedStructure

            """

            # this could be further improved by storing full transformation
            # history, but would require an improved transformation pipeline
            return TransformedStructure(
                structure, other_parameters={"wf_meta": self.wf_meta})

        ordered_structures = [
            _add_metadata(struct) for struct in ordered_structures
        ]

        if (num_orderings_hard_limit
                and len(self.ordered_structures) > num_orderings_hard_limit):
            ordered_structures = self.ordered_structures[
                0:num_orderings_hard_limit]
            ordered_structure_origins = self.ordered_structure_origins[
                0:num_orderings_hard_limit]
            logger.warning("Number of ordered structures exceeds hard limit, "
                           "removing last {} structures.".format(
                               len(self.ordered_structures) -
                               len(ordered_structures)))
            # always make sure input structure is included
            if self.input_index and self.input_index > num_orderings_hard_limit:
                ordered_structures.append(
                    self.ordered_structures[self.input_index])
                ordered_structure_origins.append(
                    self.ordered_structure_origins[self.input_index])

        # default incar settings
        user_incar_settings = {"ISYM": 0, "LASPH": True, "EDIFFG": -0.05}
        if scan:
            # currently, using SCAN relaxation as a static calculation also
            # since it is typically high quality enough, but want to make
            # sure we are also writing the AECCAR* files
            user_incar_settings.update({"LAECHG": True})
        user_incar_settings.update(c.get("user_incar_settings", {}))
        c["user_incar_settings"] = user_incar_settings

        for idx, ordered_structure in enumerate(ordered_structures):

            analyzer = CollinearMagneticStructureAnalyzer(ordered_structure)

            name = f" ordering {idx} {analyzer.ordering.value} -"

            if not scan:

                vis = MPRelaxSet(ordered_structure,
                                 user_incar_settings=user_incar_settings)

                if not self.static:

                    # relax
                    fws.append(
                        OptimizeFW(
                            ordered_structure,
                            vasp_input_set=vis,
                            vasp_cmd=c["VASP_CMD"],
                            db_file=c["DB_FILE"],
                            max_force_threshold=0.05,
                            half_kpts_first_relax=False,
                            name=name + " optimize",
                        ))

                # static
                fws.append(
                    StaticFW(
                        ordered_structure,
                        vasp_cmd=c["VASP_CMD"],
                        db_file=c["DB_FILE"],
                        name=name + " static",
                        prev_calc_loc=True,
                        parents=fws[-1],
                        vasptodb_kwargs={
                            "parse_chgcar": True,
                            "parse_aeccar": True
                        },
                    ))

                if not self.static:
                    # so a failed optimize doesn't crash workflow
                    fws[-1].spec["_allow_fizzled_parents"] = True

            elif scan:

                # wf_scan_opt is just a single FireWork so can append it directly
                scan_fws = wf_scan_opt(ordered_structure, c=c).fws
                # change name for consistency with non-SCAN
                new_name = scan_fws[0].name.replace("structure optimization",
                                                    name + " optimize")
                scan_fws[0].name = new_name
                scan_fws[0].tasks[-1]["additional_fields"][
                    "task_label"] = new_name
                fws += scan_fws

            analysis_parents.append(fws[-1])

        fw_analysis = Firework(
            MagneticOrderingsToDb(
                db_file=c["DB_FILE"],
                wf_uuid=self.uuid,
                parent_structure=self.sanitized_structure,
                origins=ordered_structure_origins,
                input_index=self.input_index,
                perform_bader=perform_bader,
                scan=scan,
                additional_fields=additional_fields,
            ),
            name="Magnetic Orderings Analysis",
            parents=analysis_parents,
            spec={"_allow_fizzled_parents": True},
        )
        fws.append(fw_analysis)

        formula = self.sanitized_structure.composition.reduced_formula
        wf_name = f"{formula} - magnetic orderings"
        if scan:
            wf_name += " - SCAN"
        wf = Workflow(fws, name=wf_name)

        wf = add_additional_fields_to_taskdocs(wf, {"wf_meta": self.wf_meta})

        tag = f"magnetic_orderings group: >>{self.uuid}<<"
        wf = add_tags(wf, [tag, ordered_structure_origins])

        return wf
Ejemplo n.º 10
0
def get_quench_wf(structures, temperatures={}, priority=None, quench_type="slow_quench", cool_args={}, hold_args={},
                  quench_args={},
                  descriptor="", **kwargs):
    fw_list = []
    temp = {"start_temp": 3000, "end_temp": 500, "temp_step": 500} if temp is None else temp
    cool_args = {"md_params": {"nsteps": 200}} if cool_args is None else cool_args
    hold_args = {"md_params": {"nsteps": 500}} if hold_args is None else hold_args
    quench_args = {} if quench_args is None else quench_args

    for (i, structure) in enumerate(structures):
        _fw_list = []
        if quench_type == "slow_quench":
            for temp in np.arange(temperatures["start_temp"], temperatures["end_temp"], -temperatures["temp_step"]):
                # get fw for cool step
                use_prev_structure = False
                if len(_fw_list) > 0:
                    use_prev_structure = True
                _fw = get_MDFW(structure, t, t - temp["temp_step"],
                               name="snap_" + str(i) + "_cool_" + str(t - temp["temp_step"]),
                               args=cool_args, parents=[_fw_list[-1]] if len(_fw_list) > 0 else [],
                               priority=priority, previous_structure=use_prev_structure,
                               insert_db=True, **kwargs)
                _fw_list.append(_fw)
                # get fw for hold step
                _fw = get_MDFW(structure, t - temp["temp_step"], t - temp["temp_step"],
                               name="snap_" + str(i) + "_hold_" + str(t - temp["temp_step"]),
                               args=hold_args, parents=[_fw_list[-1]], priority=priority,
                               previous_structure=True, insert_db=True, **kwargs)
                _fw_list.append(_fw)

        if quench_type in ["slow_quench", "mp_quench"]:
            # Relax OptimizeFW and StaticFW
            run_args = {"run_specs": {"vasp_input_set": None, "vasp_cmd": ">>vasp_cmd<<",
                                      "db_file": ">>db_file<<",
                                      "spec": {"_priority": priority}
                                      },
                        "optional_fw_params": {"override_default_vasp_params": {}}
                        }
            run_args = recursive_update(run_args, quench_args)
            _name = "snap_" + str(i)

            fw1 = OptimizeFW(structure=structure, name=_name + descriptor + "_optimize",
                             parents=[_fw_list[-1]] if len(_fw_list) > 0 else [],
                             **run_args["run_specs"], **run_args["optional_fw_params"],
                             max_force_threshold=None)
            if len(_fw_list) > 0:
                fw1 = powerups.add_cont_structure(fw1)
            fw1 = powerups.add_pass_structure(fw1)

            fw2 = StaticFW(structure=structure, name=_name + descriptor + "_static",
                           parents=[fw1], **run_args["run_specs"],
                           **run_args["optional_fw_params"])
            fw2 = powerups.add_cont_structure(fw2)
            fw2 = powerups.add_pass_structure(fw2)

            _fw_list.extend([fw1, fw2])

        fw_list.extend(_fw_list)

    name = structure.composition.reduced_formula + descriptor + "_quench"
    wf = Workflow(fw_list, name=name)
    return wf
Ejemplo n.º 11
0
def get_slab_fw(slab,
                bulk_structure=None,
                slab_gen_params={},
                db_file=None,
                vasp_input_set=None,
                parents=None,
                vasp_cmd="vasp",
                name=""):
    """
    Function to generate a a slab firework.  Returns a TransmuterFW if bulk_structure is specified,
    constructing the necessary transformations from the slab and slab generator parameters,
    or an OptimizeFW if only a slab is specified.

    Args:
        slab (Slab or Structure): structure or slab corresponding
            to the slab to be calculated
        bulk_structure (Structure): bulk structure corresponding to slab, if
            provided, slab firework is constructed as a TransmuterFW using
            the necessary transformations to get the slab from the bulk
        slab_gen_params (dict): dictionary of slab generation parameters
            used to generate the slab, necessary to get the slab
            that corresponds to the bulk structure
        vasp_input_set (VaspInputSet): vasp_input_set corresponding to
            the slab calculation
        parents (Fireworks or list of ints): parent FWs
        db_file (string): path to database file
        vasp_cmd (string): vasp command

    Returns:
        Firework
    """
    vasp_input_set = vasp_input_set or MVLSlabSet(slab)

    # If a bulk_structure is specified, generate the set of transformations, else
    # just create an optimize FW with the slab
    if bulk_structure:
        if not isinstance(slab, Slab):
            raise ValueError(
                "structure input to get_slab_fw requires slab to be a slab object!"
            )
        slab_trans_params = {
            "miller_index": slab.miller_index,
            "shift": slab.shift
        }
        slab_trans_params.update(slab_gen_params)

        # Get supercell parameters
        trans_struct = SlabTransformation(**slab_trans_params)
        slab_from_bulk = trans_struct.apply_transformation(bulk_structure)
        supercell_trans = SupercellTransformation.from_scaling_factors(
            round(slab.lattice.a / slab_from_bulk.lattice.a),
            round(slab.lattice.b / slab_from_bulk.lattice.b))

        # Get adsorbates for InsertSitesTransformation
        if "adsorbate" in slab.site_properties.get("surface_properties",
                                                   [None]):
            ads_sites = [
                site for site in slab
                if site.properties["surface_properties"] == "adsorbate"
            ]
        else:
            ads_sites = []
        transformations = [
            "SlabTransformation", "SupercellTransformation",
            "InsertSitesTransformation", "AddSitePropertyTransformation"
        ]
        trans_params = [
            slab_trans_params, {
                "scaling_matrix": supercell_trans.scaling_matrix
            }, {
                "species": [site.species_string for site in ads_sites],
                "coords": [site.frac_coords for site in ads_sites]
            }, {
                "site_properties": slab.site_properties
            }
        ]
        return TransmuterFW(name=name,
                            structure=bulk_structure,
                            transformations=transformations,
                            transformation_params=trans_params,
                            copy_vasp_outputs=True,
                            db_file=db_file,
                            vasp_cmd=vasp_cmd,
                            parents=parents,
                            vasp_input_set=vasp_input_set)
    else:
        return OptimizeFW(name=name,
                          structure=slab,
                          vasp_input_set=vasp_input_set,
                          vasp_cmd=vasp_cmd,
                          db_file=db_file,
                          parents=parents,
                          job_type="normal")
Ejemplo n.º 12
0
def get_wf_surface(slabs,
                   molecules=[],
                   bulk_structure=None,
                   slab_gen_params=None,
                   vasp_cmd="vasp",
                   db_file=None,
                   ads_structures_params={},
                   add_molecules_in_box=False):
    """

    Args:
        slabs (list of Slabs or Structures): slabs to calculate
        molecules (list of Molecules): molecules to place as adsorbates
        bulk_structure (Structure): bulk structure from which generate slabs
            after reoptimization.  If supplied, workflow will begin with
            bulk structure optimization.
        slab_gen_params (dict): dictionary of slab generation parameters
            used to generate the slab, necessary to get the slab
            that corresponds to the bulk structure if in that mode
        ads_structures_params (dict): parameters to be supplied as
            kwargs to AdsorbateSiteFinder.generate_adsorption_structures
        add_molecules_in_box (boolean): flag to add calculation of molecule
            energies to the workflow
        db_file (string): path to database file
        vasp_cmd (string): vasp command

    Returns:
        Workflow
    """
    fws, parents = [], []

    if bulk_structure:
        vis = MVLSlabSet(bulk_structure, bulk=True)
        fws.append(
            OptimizeFW(bulk_structure,
                       vasp_input_set=vis,
                       vasp_cmd="vasp",
                       db_file=db_file))
        parents = fws[0]

    for slab in slabs:
        name = slab.composition.reduced_formula
        if getattr(slab, "miller_index", None):
            name += "_{}".format(slab.miller_index)
        fws.append(
            get_slab_fw(slab,
                        bulk_structure,
                        slab_gen_params,
                        db_file=db_file,
                        vasp_cmd=vasp_cmd,
                        parents=parents,
                        name=name + " slab optimization"))
        for molecule in molecules:
            ads_slabs = AdsorbateSiteFinder(
                slab).generate_adsorption_structures(molecule,
                                                     **ads_structures_params)
            for n, ads_slab in enumerate(ads_slabs):
                ads_name = "{}-{} adsorbate optimization {}".format(
                    molecule.composition.formula, name, n)
                fws.append(
                    get_slab_fw(ads_slab,
                                bulk_structure,
                                slab_gen_params,
                                db_file=db_file,
                                vasp_cmd=vasp_cmd,
                                parents=parents,
                                name=ads_name))
    if add_molecules_in_box:
        for molecule in molecules:
            # molecule in box
            m_struct = Structure(Lattice.cubic(10),
                                 molecule.species_and_occu,
                                 molecule.cart_coords,
                                 coords_are_cartesian=True)
            m_struct.translate_sites(
                list(range(len(m_struct))),
                np.array([0.5] * 3) - np.average(m_struct.frac_coords, axis=0))
            vis = MVLSlabSet(m_struct)
            fws.append(
                OptimizeFW(molecule,
                           job_type="normal",
                           vasp_input_set=vis,
                           db_file=db_file,
                           vasp_cmd=vasp_cmd))
    # TODO: add analysis framework
    return Workflow(fws, name="")
Ejemplo n.º 13
0
    def get_wf(self, c=None):
        """
        Get the workflow.

        Returns:
            Workflow

        """

        c = c or {"VASP_CMD": VASP_CMD, "DB_FILE": DB_FILE}
        vasp_cmd = c.get("VASP_CMD", VASP_CMD)
        db_file = c.get("DB_FILE", DB_FILE)

        nsites = len(self.structure.sites)

        vis = MPRelaxSet(self.structure, potcar_functional="PBE_54", force_gamma=True)

        opt_fw = OptimizeFW(
            self.structure,
            vasp_input_set=vis,
            vasp_cmd=c["VASP_CMD"],
            db_file=c["DB_FILE"],
        )

        vis = MPStaticSet(self.structure, potcar_functional="PBE_54", force_gamma=True)

        static_fw = StaticFW(
            self.structure,
            vasp_input_set=vis,
            vasp_cmd=c["VASP_CMD"],
            db_file=c["DB_FILE"],
            parents=[opt_fw],
        )

        # Separate FW for each BZ surface calc
        # Run Z2Pack on unique TRIM planes in the BZ

        surfaces = ["kx_0", "kx_1"]
        equiv_planes = self.get_equiv_planes()

        # Only run calcs on inequivalent BZ surfaces
        if self.symmetry_reduction:
            for add_surface in equiv_planes.keys():
                mark = True
                for surface in surfaces:
                    if surface in equiv_planes[add_surface]:
                        mark = False
                if mark and add_surface not in surfaces:
                    surfaces.append(add_surface)
        else:  # 4 TRI surfaces define Z2 in 3D
            surfaces = ["kx_1", "ky_1", "kz_0", "kz_1"]

        z2pack_fws = []

        for surface in surfaces:
            z2pack_fw = Z2PackFW(
                parents=[static_fw],
                structure=self.structure,
                surface=surface,
                uuid=self.uuid,
                name="z2pack",
                vasp_cmd=c["VASP_CMD"],
                db_file=c["DB_FILE"],
            )
            z2pack_fws.append(z2pack_fw)

        analysis_fw = InvariantFW(
            parents=z2pack_fws,
            structure=self.structure,
            symmetry_reduction=self.symmetry_reduction,
            equiv_planes=equiv_planes,
            uuid=self.uuid,
            name="invariant",
            db_file=c["DB_FILE"],
        )

        fws = [opt_fw, static_fw] + z2pack_fws + [analysis_fw]

        wf = Workflow(fws)
        wf = add_additional_fields_to_taskdocs(wf, {"wf_meta": self.wf_meta})

        # Add vdW corrections if structure is layered
        dim_data = StructureDimensionality(self.structure)

        if np.any(
            [
                dim == 2
                for dim in [dim_data.larsen_dim, dim_data.cheon_dim, dim_data.gorai_dim]
            ]
        ):
            wf = add_modify_incar(
                wf,
                modify_incar_params={
                    "incar_update": {
                        "IVDW": 11,
                        "EDIFFG": 0.005,
                        "IBRION": 2,
                        "NSW": 100,
                    }
                },
                fw_name_constraint="structure optimization",
            )

            wf = add_modify_incar(
                wf,
                modify_incar_params={"incar_update": {"IVDW": 11}},
                fw_name_constraint="static",
            )

            wf = add_modify_incar(
                wf,
                modify_incar_params={"incar_update": {"IVDW": 11}},
                fw_name_constraint="z2pack",
            )

        else:
            wf = add_modify_incar(
                wf,
                modify_incar_params={
                    "incar_update": {"EDIFFG": 0.005, "IBRION": 2, "NSW": 100}
                },
                fw_name_constraint="structure optimization",
            )

        # Helpful vasp settings and no parallelization
        wf = add_modify_incar(
            wf,
            modify_incar_params={
                "incar_update": {
                    "ADDGRID": ".TRUE.",
                    "LASPH": ".TRUE.",
                    "GGA": "PS",
                    "NCORE": 1,
                }
            },
        )

        # Generate inputs for Z2Pack with a static calc
        wf = add_modify_incar(
            wf,
            modify_incar_params={"incar_update": {"PREC": "Accurate"}},
            fw_name_constraint="static",
        )

        wf = add_common_powerups(wf, c)

        wf.name = "{} {}".format(self.structure.composition.reduced_formula, "Z2Pack")

        if c.get("STABILITY_CHECK", STABILITY_CHECK):
            wf = add_stability_check(wf, fw_name_constraint="structure optimization")

        if c.get("ADD_WF_METADATA", ADD_WF_METADATA):
            wf = add_wf_metadata(wf, self.structure)

        tag = "z2pack: {}".format(self.uuid)
        wf = add_tags(wf, [tag])

        return wf
Ejemplo n.º 14
0
for composition in comp_list:
    tilt_count = 15
    temp_structs = copy.deepcopy(tilts_and_orders)
    comp_tag = composition[0] + composition[1] + 'N' + 'O' + str(
        composition[2])
    struct_tag = 'tetra'
    for structure in temp_structs:
        if composition[2] == 1:
            structure.replace_species({'O': 'N', 'N': 'O'})
        structure.replace_species({
            default_B: composition[1]
        })  #this will break if B-site is default_a but that shouldn't happen
        structure.replace_species({default_A: composition[0]})
        poscar_key = tetra_dict[tilt_count]

        opt = OptimizeFW(structure, vasp_cmd='ibrun tacc_affinity vasp_std')
        stat = StaticFW(parents=opt, vasp_cmd='ibrun tacc_affinity vasp_std')
        wf = Workflow([opt, stat])
        wf = add_modify_incar(wf,
                              modify_incar_params={
                                  'incar_update': {
                                      'KPAR': 2,
                                      'NCORE': 4,
                                      'NSIM': 8,
                                      'EDIFF': 0.000002,
                                      'LMAXMIX': 6,
                                      'LSCALAPACK': '.FALSE.',
                                      'ALGO': 'All'
                                  }
                              })
        wf = add_modify_incar(wf,
Ejemplo n.º 15
0
def get_wf_raman_spectra(
    structure, modes=None, step_size=0.005, vasp_cmd="vasp", db_file=None
):
    """
    Raman susceptibility tensor workflow:
        Calculation of phonon normal modes followed by the computation of dielectric tensor for
        structures displaced along the normal modes. Finally the dielectric tensors corresponding
        to each mode are used to compute the Raman susceptibility tensor using finite difference
        (central difference scheme).

    Args:
        structure (Structure): Input structure.
        modes (tuple/list): list of modes for which the Raman spectra need to be calculated.
            The default is to use all the 3N modes.
        step_size (float): site displacement along the normal mode in Angstroms. Used to compute
            the finite difference(central difference scheme) first derivative of the dielectric
            constant along the normal modes.
        vasp_cmd (str): vasp command to run.
        db_file (str): path to file containing the database credentials.

    Returns:
        Workflow
    """
    modes = modes or range(3 * len(structure))
    vis = MPRelaxSet(structure, force_gamma=True)
    # displacements in + and - direction along the normal mode so that the central difference scheme
    # can be used for the evaluation of Raman tensor (derivative of epsilon wrt displacement)
    displacements = [-step_size, step_size]

    fws = []

    # Structure optimization
    fw_opt = OptimizeFW(
        structure=structure,
        vasp_input_set=vis,
        ediffg=None,
        vasp_cmd=vasp_cmd,
        db_file=db_file,
    )
    fws.append(fw_opt)

    # Static run: compute the normal modes and pass
    fw_leps = DFPTFW(
        structure=structure,
        vasp_cmd=vasp_cmd,
        db_file=db_file,
        parents=fw_opt,
        pass_nm_results=True,
    )

    fws.append(fw_leps)

    # Static runs to compute epsilon for each mode and displacement along that mode.
    fws_nm_disp = []
    for mode in modes:
        for disp in displacements:
            fws_nm_disp.append(
                RamanFW(
                    mode,
                    disp,
                    structure=structure,
                    parents=fw_leps,
                    vasp_cmd=vasp_cmd,
                    db_file=db_file,
                )
            )
    fws.extend(fws_nm_disp)

    # Compute the Raman susceptibility tensor
    fw_analysis = Firework(
        RamanTensorToDb(db_file=db_file),
        parents=fws[:],
        name="{}-{}".format(structure.composition.reduced_formula, "raman analysis"),
    )
    fws.append(fw_analysis)

    wfname = "{}:{}".format(structure.composition.reduced_formula, "raman spectra")
    return Workflow(fws, name=wfname)
Ejemplo n.º 16
0
    def run_task(self, fw_spec):

        insert_sites = fw_spec.get("insert_sites", [])
        base_task_id = fw_spec.get("base_task_id")
        base_structure = Structure.from_dict(fw_spec.get("base_structure"))
        working_ion = fw_spec.get("working_ion")
        allow_fizzled_parents = fw_spec.get("allow_fizzled_parents", False)
        optimizefw_kwargs = fw_spec.get("optimizefw_kwargs", {})
        n_ion = int(
            base_structure.composition.element_composition[working_ion]) + 1

        new_fws = []
        for itr, isite in enumerate(insert_sites):
            inserted_structure = base_structure.copy()
            fpos = isite
            inserted_structure.insert(0,
                                      working_ion,
                                      fpos,
                                      properties={"magmom": 1.0})
            additional_fields = {
                "insertion_fpos": fpos,
                "base_task_id": base_task_id
            }

            # Create new fw
            fw = OptimizeFW(
                inserted_structure,
                name=
                f"structure optimization-{itr}",  # structure are rough guesses
                **optimizefw_kwargs,
            )
            fw.tasks[-1]["additional_fields"].update(
                additional_fields)  # easy way to update a field

            pass_dict = {
                "structure": ">>output.ionic_steps.-1.structure",
                "energy": "a>>final_energy",
            }

            pass_task = pass_vasp_result(
                filename="vasprun.xml.relax2.gz",
                pass_dict=pass_dict,
                mod_spec_cmd="_push",
                mod_spec_key="inserted_results",
            )

            fw.tasks.append(pass_task)
            new_fws.append(fw)

        if len(new_fws) == 0:
            return

        check_fw = Firework(
            [CollectInsertedCalcs(),
             SubmitMostStable()],
            parents=new_fws,
            name=f"Collect Inserted Calcs-{n_ion}",
        )
        # Allow fizzled parent
        check_fw.spec["_allow_fizzled_parents"] = allow_fizzled_parents

        wf = Workflow(new_fws + [check_fw])
        wf = get_powerup_wf(wf, fw_spec)

        update_wf_keys(wf, fw_spec)
        return FWAction(additions=[wf])