Example #1
0
    def setUp(self):
        """
        1) Basic check for pymatgen configurations.
        2) Setup all test workflow.
        """
        super(TestNudgedElasticBandWorkflow, self).setUp()
        # Structures used for test:
        parent = PymatgenTest.get_structure("Li2O")
        parent.remove_oxidation_states()
        parent.make_supercell(2)
        ep0, ep1 = get_endpoints_from_index(parent, [0, 1])
        neb_dir = [os.path.join(module_dir, "..", "..", "test_files", "neb_wf", "4", "inputs", "{:02}",
                                "POSCAR").format(i) for i in range(5)]
        self.structures = [Structure.from_file(n) for n in neb_dir]

        # Run fake vasp
        test_yaml = os.path.join(module_dir, "../../test_files/neb_wf/config/neb_unittest.yaml")
        with open(test_yaml, 'r') as stream:
            self.config = yaml.safe_load(stream)
            # Use scratch directory as destination directory for testing
            self.config["common_params"]["_fw_env"] = {"run_dest_root": self.scratch_dir}

        # Config 1: The parent structure & two endpoint indexes provided; need relaxation first.
        self.config_1 = copy.deepcopy(self.config)
        self.config_1["common_params"]["is_optimized"] = False
        self.config_1["common_params"]["wf_name"] = "NEB_test_1"

        # Config 2: The parent structure & two endpoint indexes provided; no need to relax.
        self.config_2 = copy.deepcopy(self.config)
        del self.config_2["fireworks"][0]
        self.config_2["common_params"]["is_optimized"] = True
        self.config_2["common_params"]["wf_name"] = "NEB_test_2"

        # Config 3: Two endpoints provided; need to relax two endpoints.
        self.config_3 = copy.deepcopy(self.config)
        del self.config_3["fireworks"][0]
        self.config_3["common_params"]["is_optimized"] = False
        self.config_3["common_params"]["wf_name"] = "NEB_test_3"

        # Config 4: Two relaxed endpoints provided; no need to relax two endpoints.
        self.config_4 = copy.deepcopy(self.config_3)
        del self.config_4["fireworks"][0]
        self.config_4["common_params"]["is_optimized"] = True
        self.config_4["common_params"]["wf_name"] = "NEB_test_4"

        # Config 5: All images including two endpoints are provided.
        self.config_5 = copy.deepcopy(self.config)
        del self.config_5["fireworks"][0: 2]
        self.config_5["common_params"]["wf_name"] = "NEB_test_5"

        self.wf_1 = wf_nudged_elastic_band([parent], parent, self.config_1)
        self.wf_2 = wf_nudged_elastic_band([parent], parent, self.config_2)
        self.wf_3 = wf_nudged_elastic_band([ep0, ep1], parent, self.config_3)
        self.wf_4 = wf_nudged_elastic_band([ep0, ep1], parent, self.config_4)
        self.wf_5 = wf_nudged_elastic_band(self.structures, parent, self.config_5)

        # Workflow without the config file
        self.wf_6 = wf_nudged_elastic_band(self.structures, parent)
Example #2
0
    def setUp(self):
        """
        1) Basic check for pymatgen configurations.
        2) Setup all test workflow.
        """
        super(TestNudgedElasticBandWorkflow, self).setUp()
        # Structures used for test:
        parent = PymatgenTest.get_structure("Li2O")
        parent.remove_oxidation_states()
        parent.make_supercell(2)
        ep0, ep1 = get_endpoints_from_index(parent, [0, 1])
        neb_dir = [os.path.join(module_dir, "..", "..", "test_files", "neb_wf", "4", "inputs", "{:02}",
                                "POSCAR").format(i) for i in range(5)]
        self.structures = [Structure.from_file(n) for n in neb_dir]

        # Run fake vasp
        test_yaml = os.path.join(module_dir, "../../test_files/neb_wf/config/neb_unittest.yaml")
        with open(test_yaml, 'r') as stream:
            self.config = yaml.safe_load(stream)
            # Use scratch directory as destination directory for testing
            self.config["common_params"]["_fw_env"] = {"run_dest_root": self.scratch_dir}

        # Config 1: The parent structure & two endpoint indexes provided; need relaxation first.
        self.config_1 = copy.deepcopy(self.config)
        self.config_1["common_params"]["is_optimized"] = False
        self.config_1["common_params"]["wf_name"] = "NEB_test_1"

        # Config 2: The parent structure & two endpoint indexes provided; no need to relax.
        self.config_2 = copy.deepcopy(self.config)
        del self.config_2["fireworks"][0]
        self.config_2["common_params"]["is_optimized"] = True
        self.config_2["common_params"]["wf_name"] = "NEB_test_2"

        # Config 3: Two endpoints provided; need to relax two endpoints.
        self.config_3 = copy.deepcopy(self.config)
        del self.config_3["fireworks"][0]
        self.config_3["common_params"]["is_optimized"] = False
        self.config_3["common_params"]["wf_name"] = "NEB_test_3"

        # Config 4: Two relaxed endpoints provided; no need to relax two endpoints.
        self.config_4 = copy.deepcopy(self.config_3)
        del self.config_4["fireworks"][0]
        self.config_4["common_params"]["is_optimized"] = True
        self.config_4["common_params"]["wf_name"] = "NEB_test_4"

        # Config 5: All images including two endpoints are provided.
        self.config_5 = copy.deepcopy(self.config)
        del self.config_5["fireworks"][0: 2]
        self.config_5["common_params"]["wf_name"] = "NEB_test_5"

        self.wf_1 = wf_nudged_elastic_band([parent], parent, self.config_1)
        self.wf_2 = wf_nudged_elastic_band([parent], parent, self.config_2)
        self.wf_3 = wf_nudged_elastic_band([ep0, ep1], parent, self.config_3)
        self.wf_4 = wf_nudged_elastic_band([ep0, ep1], parent, self.config_4)
        self.wf_5 = wf_nudged_elastic_band(self.structures, parent, self.config_5)

        # Workflow without the config file
        self.wf_6 = wf_nudged_elastic_band(self.structures, parent)
Example #3
0
    def test_get_endpoints_from_index(self):
        endpoints = get_endpoints_from_index(structure=self.structure,
                                             site_indices=[0, 1])
        ep_0 = endpoints[0].as_dict()
        ep_1 = endpoints[1].as_dict()
        ep_0_expect = Structure.from_file(get_path("POSCAR_ep0",
                                                   dirname="io_files")).as_dict()
        ep_1_expect = Structure.from_file(get_path("POSCAR_ep1",
                                                   dirname="io_files")).as_dict()

        self.assertEqual(ep_0, ep_0_expect)
        self.assertEqual(ep_1, ep_1_expect)
Example #4
0
    def run_task(self, fw_spec):

        label = self["label"]
        assert label in ["parent", "ep0", "ep1"] or "neb" in label, "Unknown label!"

        d_img = float(self.get("d_img", 0.7))  # Angstrom
        wf_name = fw_spec["wf_name"]
        src_dir = os.path.abspath(".")
        dest_dir = os.path.join(fw_spec["_fw_env"]["run_dest_root"], wf_name, label)
        shutil.copytree(src_dir, dest_dir)

        # Update fw_spec based on the type of calculations.
        if "neb" in label:
            # Update all relaxed images.
            subs = glob.glob("[0-2][0-9]")
            nimages = len(subs)
            concar_list = ["{:02}/CONTCAR".format(i) for i in range(nimages)[1:-1]]
            images = [Structure.from_file(contcar) for contcar in concar_list]

            # Update the two ending "images".
            images.insert(0, Structure.from_file("00/POSCAR"))
            images.append(Structure.from_file("{:02}/POSCAR".format(nimages - 1)))
            images = [s.as_dict() for s in images]
            neb = fw_spec.get("neb")
            neb.append(images)
            update_spec = {"neb": neb, "_queueadapter": {"nnodes": str(len(images) - 2),
                                                         "nodes": str(len(images) - 2)}}
            # Use neb walltime if it is in fw_spec
            if fw_spec["neb_walltime"] is not None:
                update_spec["_queueadapter"].update({"walltime": fw_spec.get("neb_walltime")})

        elif label in ["ep0", "ep1"]:
            # Update relaxed endpoint structures.
            file = glob.glob("CONTCAR*")[0]
            ep = Structure.from_file(file, False)  # One endpoint

            if fw_spec.get("incar_images"):  # "incar_images": pre-defined image number.
                update_spec = {label: ep.as_dict(),
                               "_queueadapter": {"nnodes": fw_spec["incar_images"],
                                                 "nodes": fw_spec["incar_images"]}}
            else:
                # Calculate number of images if "IMAGES" tag is not provided.
                index = int(label[-1])
                ep_1_dict = fw_spec.get("ep{}".format(1 - index))  # Another endpoint
                try:
                    ep_1 = Structure.from_dict(ep_1_dict)
                except:
                    ep_1 = ep_1_dict

                max_dist = max(get_endpoint_dist(ep, ep_1))
                nimages = round(max_dist / d_img) or 1
                update_spec = {label: ep, "_queueadapter": {"nnodes": int(nimages),
                                                            "nodes": int(nimages)}}
            # Use neb walltime if it is in fw_spec
            if fw_spec["neb_walltime"] is not None:
                update_spec["_queueadapter"].update({"walltime": fw_spec.get("neb_walltime")})

        else:  # label == "parent"
            f = glob.glob("CONTCAR*")[0]
            s = Structure.from_file(f, False)
            ep0, ep1 = get_endpoints_from_index(s, fw_spec["site_indices"])

            update_spec = {"parent": s.as_dict(), "ep0": ep0.as_dict(), "ep1": ep1.as_dict()}

        # Clear current directory.
        for d in os.listdir(src_dir):
            try:
                os.remove(os.path.join(src_dir, d))
            except:
                shutil.rmtree(os.path.join(src_dir, d))

        return FWAction(update_spec=update_spec)
Example #5
0
    def run_task(self, fw_spec):

        label = self["label"]
        assert label in ["parent", "ep0", "ep1"
                         ] or "neb" in label, "Unknown label!"

        d_img = float(self.get("d_img", 0.7))  # Angstrom
        wf_name = fw_spec["wf_name"]
        src_dir = os.path.abspath(".")
        dest_dir = os.path.join(fw_spec["_fw_env"]["run_dest_root"], wf_name,
                                label)
        shutil.copytree(src_dir, dest_dir)

        # Update fw_spec based on the type of calculations.
        if "neb" in label:
            # Update all relaxed images.
            subs = glob.glob("[0-2][0-9]")
            nimages = len(subs)
            concar_list = [
                "{:02}/CONTCAR".format(i) for i in range(nimages)[1:-1]
            ]
            images = [Structure.from_file(contcar) for contcar in concar_list]

            # Update the two ending "images".
            images.insert(0, Structure.from_file("00/POSCAR"))
            images.append(
                Structure.from_file("{:02}/POSCAR".format(nimages - 1)))
            images = [s.as_dict() for s in images]
            neb = fw_spec.get("neb")
            neb.append(images)
            update_spec = {
                "neb": neb,
                "_queueadapter": {
                    "nnodes": str(len(images) - 2),
                    "nodes": str(len(images) - 2)
                }
            }
            # Use neb walltime if it is in fw_spec
            if fw_spec["neb_walltime"] is not None:
                update_spec["_queueadapter"].update(
                    {"walltime": fw_spec.get("neb_walltime")})

        elif label in ["ep0", "ep1"]:
            # Update relaxed endpoint structures.
            file = glob.glob("CONTCAR*")[0]
            ep = Structure.from_file(file, False)  # One endpoint

            if fw_spec.get("incar_images"
                           ):  # "incar_images": pre-defined image number.
                update_spec = {
                    label: ep.as_dict(),
                    "_queueadapter": {
                        "nnodes": fw_spec["incar_images"],
                        "nodes": fw_spec["incar_images"]
                    }
                }
            else:
                # Calculate number of images if "IMAGES" tag is not provided.
                index = int(label[-1])
                ep_1_dict = fw_spec.get(
                    "ep{}".format(1 - index))  # Another endpoint
                try:
                    ep_1 = Structure.from_dict(ep_1_dict)
                except:
                    ep_1 = ep_1_dict

                max_dist = max(get_endpoint_dist(ep, ep_1))
                nimages = round(max_dist / d_img) or 1
                update_spec = {
                    label: ep,
                    "_queueadapter": {
                        "nnodes": int(nimages),
                        "nodes": int(nimages)
                    }
                }
            # Use neb walltime if it is in fw_spec
            if fw_spec["neb_walltime"] is not None:
                update_spec["_queueadapter"].update(
                    {"walltime": fw_spec.get("neb_walltime")})

        else:  # label == "parent"
            f = glob.glob("CONTCAR*")[0]
            s = Structure.from_file(f, False)
            ep0, ep1 = get_endpoints_from_index(s, fw_spec["site_indices"])

            update_spec = {
                "parent": s.as_dict(),
                "ep0": ep0.as_dict(),
                "ep1": ep1.as_dict()
            }

        # Clear current directory.
        for d in os.listdir(src_dir):
            try:
                os.remove(os.path.join(src_dir, d))
            except:
                shutil.rmtree(os.path.join(src_dir, d))

        return FWAction(update_spec=update_spec)
Example #6
0
def get_wf_neb_from_structure(structure, user_incar_settings=None, additional_spec=None,
                              user_kpoints_settings=None, additional_cust_args=None):
    """
    Obtain the CI-NEB workflow staring with a parent structure. This works only under the single
    vacancy diffusion mechanism.

    Workflow: (parent relaxation) --> Endpoints relaxation --> NEB_1 --> NEB_2 --> ... --> NEB_r
              (i) If parent is not relaxed: then parent relaxation--ep--neb(r)
                    (r rounds of NEB)
              (ii) If parent is relaxed: ep--neb(r) (r rounds of NEB)
    Args:
        structure (Structure): The parent structure.
        user_incar_settings([dict]): Additional user_incar_settings. Note that the order of the
                    list is set as: "parent", "ep_relax", "neb1", "neb2" etc., which contains
                    at least three elements. The first dict is for parent structure relaxation,
                    the second dict is for endpoints relaxation, and the rest are for NEB
                    calculations. For example, [{}, {}, {"IOPT": 7}, {"IOPT": 1}]. Besides,
                    user_incar_settings is used to determine how many NEB rounds will be. Default
                    is [{}, {}, {}].
        additional_spec (dict): User spec settings to overwrite default_spec.
        user_kpoints_settings ([dict]): Additional user_kpoints_settings, which contains at at
                    least three elements, which is similar to user_incar_settings. For example,
                    [{}, {}, {"grid_density": 100}] for the workflow from the parent structure
                    relaxation, then the endpoint relaxation followed by one-round NEB simulation.
                    Default values depend on the selected VaspInputSet.
        additional_cust_args ([dict]): Optional parameters for RunVaspCustodian, same structure
                    with user_incar_settings and user_kpoints_settings.

    Returns:
        Workflow

    """
    spec = _update_spec(additional_spec)
    site_indices = spec["site_indices"]
    is_optimized = spec["is_optimized"]
    wf_name = spec["wf_name"]
    endpoints = get_endpoints_from_index(structure, site_indices)
    # Default settings for "parent", "ep0" and "ep1". If is_optimized is False, spec["ep0"] and
    # spec["ep1"] will be updated after parent relaxation.
    spec["parent"] = structure.as_dict()
    spec["ep0"], spec["ep1"] = endpoints[0].as_dict(), endpoints[1].as_dict()

    # Assume one round NEB if user_incar_settings not provided.
    user_incar_settings = user_incar_settings or [{}, {}, {}]
    neb_round = len(user_incar_settings[2:])
    user_kpoints_settings = user_kpoints_settings or [{"grid_density": 1000}] * (neb_round + 2)
    additional_cust_args = additional_cust_args or [{}] * (neb_round + 2)
    for incar in user_incar_settings[2:]:
        if incar.get("IMAGES"):
            # If "incar_images" shows up, the number of images is pre-defined
            spec["incar_images"] = incar["IMAGES"]
            break

    if is_optimized:  # Start from endpoints
        neb_fws, rlx_fws = [], []

        # Get neb fireworks.
        for n in range(neb_round):
            fw = NEBFW(spec=spec, neb_label=str(n + 1), from_images=False,
                       user_incar_settings=user_incar_settings[n + 2],
                       user_kpoints_settings=user_kpoints_settings[n + 2],
                       additional_cust_args=additional_cust_args[n + 2])
            neb_fws.append(fw)
        # Get relax fireworks
        for label in ["ep0", "ep1"]:
            fw = NEBRelaxationFW(spec=spec, label=label,
                                 user_incar_settings=user_incar_settings[1],
                                 user_kpoints_settings=user_kpoints_settings[1],
                                 additional_cust_args=additional_cust_args[1])
            rlx_fws.append(fw)
        # Build fireworks link
        links = {rlx_fws[0]: [neb_fws[0]], rlx_fws[1]: [neb_fws[0]]}

    else:  # Start from parent structure
        neb_fws, rlx_fws = [], []

        # Get neb fireworks.
        for n in range(neb_round):
            fw = NEBFW(spec=spec, neb_label=str(n + 1), from_images=False,
                       user_incar_settings=user_incar_settings[n + 2],
                       user_kpoints_settings=user_kpoints_settings[n + 2],
                       additional_cust_args=additional_cust_args[n + 2])
            neb_fws.append(fw)
        # Get relaxation fireworks.
        rlx_fws.append(NEBRelaxationFW(spec=spec, label="parent",
                                       user_incar_settings=user_incar_settings[0],
                                       user_kpoints_settings=user_kpoints_settings[0],
                                       additional_cust_args=additional_cust_args[0]))

        for i, label in enumerate(["ep0", "ep1"]):
            fw = NEBRelaxationFW(spec=spec, label=label,
                                 user_incar_settings=user_incar_settings[1],
                                 user_kpoints_settings=user_kpoints_settings[1],
                                 additional_cust_args=additional_cust_args[1])
            rlx_fws.append(fw)

        # Build fireworks link
        links = {rlx_fws[0]: [rlx_fws[1], rlx_fws[2]],
                 rlx_fws[1]: [neb_fws[0]],
                 rlx_fws[2]: [neb_fws[0]]}

    # Put all fireworks together with link
    fws = rlx_fws + neb_fws
    if neb_round >= 2:
        for r in range(1, neb_round):
            links[neb_fws[r - 1]] = [neb_fws[r]]
    workflow = Workflow(fws, links_dict=links, name=wf_name)
    return workflow