Esempio n. 1
0
 def test_chgcar_db_read_write(self):
     # generate a doc from the test folder
     drone = VaspDrone(parse_chgcar=True, parse_aeccar=True)
     print(ref_dirs_si['static'])
     doc = drone.assimilate(ref_dirs_si['static']+'/outputs')
     # insert the doc make sure that the
     cc = doc['calcs_reversed'][0]['chgcar']
     self.assertAlmostEqual(cc.data['total'].sum()/cc.ngridpts, 8.0, 4)
     cc = doc['calcs_reversed'][0]['aeccar0']
     self.assertAlmostEqual(cc.data['total'].sum()/cc.ngridpts, 23.253588293583313, 4)
     cc = doc['calcs_reversed'][0]['aeccar2']
     self.assertAlmostEqual(cc.data['total'].sum()/cc.ngridpts, 8.01314480789829, 4)
     mmdb = VaspCalcDb.from_db_file(os.path.join(db_dir, "db.json"))
     t_id = mmdb.insert_task(doc, use_gridfs=True)
     # space is freed up after uploading the document
     self.assertRaises(KeyError, lambda: doc['calcs_reversed'][0]['chgcar'])
     self.assertRaises(KeyError, lambda: doc['calcs_reversed'][0]['aeccar0'])
     self.assertRaises(KeyError, lambda: doc['calcs_reversed'][0]['aeccar2'])
     cc = mmdb.get_chgcar(task_id=t_id)
     self.assertAlmostEqual(cc.data['total'].sum()/cc.ngridpts, 8.0, 4)
     dcc = mmdb.get_aeccar(task_id=t_id)
     self.assertAlmostEqual(dcc['aeccar0'].data['total'].sum()/cc.ngridpts, 23.253588293583313, 4)
     self.assertAlmostEqual(dcc['aeccar2'].data['total'].sum()/cc.ngridpts, 8.01314480789829, 4)
     # check the retrieve_task function for the same fake calculation
     ret_task = mmdb.retrieve_task(t_id)
     ret_chgcar = ret_task['calcs_reversed'][0]['chgcar']
     ret_aeccar0 = ret_task['calcs_reversed'][0]['aeccar0']
     ret_aeccar2 = ret_task['calcs_reversed'][0]['aeccar2']
     ret_aeccar = ret_aeccar0 + ret_aeccar2
     self.assertAlmostEqual(ret_chgcar.data['total'].sum()/ret_chgcar.ngridpts, 8.0, 4)
     self.assertAlmostEqual(ret_aeccar.data['total'].sum()/ret_aeccar.ngridpts, 31.2667331015, 4)
Esempio n. 2
0
    def run_task(self, fw_spec):
        additional_fields = self.get("additional_fields", {})

        # pass the additional_fields first to avoid overriding BoltztrapAnalyzer items
        d = additional_fields.copy()

        btrap_dir = os.path.join(os.getcwd(), "boltztrap")
        d["boltztrap_dir"] = btrap_dir

        bta = BoltztrapAnalyzer.from_files(btrap_dir)
        d.update(bta.as_dict())
        d["scissor"] = bta.intrans["scissor"]

        # trim the output
        for x in ['cond', 'seebeck', 'kappa', 'hall', 'mu_steps', 'mu_doping', 'carrier_conc']:
            del d[x]

        if not self.get("hall_doping"):
            del d["hall_doping"]

        bandstructure_dir = os.getcwd()
        d["bandstructure_dir"] = bandstructure_dir

        # add the structure
        v, o = get_vasprun_outcar(bandstructure_dir, parse_eigen=False, parse_dos=False)
        structure = v.final_structure
        d["structure"] = structure.as_dict()
        d["formula_pretty"] = structure.composition.reduced_formula
        d.update(get_meta_from_structure(structure))

        # add the spacegroup
        sg = SpacegroupAnalyzer(Structure.from_dict(d["structure"]), 0.1)
        d["spacegroup"] = {"symbol": sg.get_space_group_symbol(),
                           "number": sg.get_space_group_number(),
                           "point_group": sg.get_point_group_symbol(),
                           "source": "spglib",
                           "crystal_system": sg.get_crystal_system(),
                           "hall": sg.get_hall()}

        d["created_at"] = datetime.utcnow()

        db_file = env_chk(self.get('db_file'), fw_spec)

        if not db_file:
            del d["dos"]
            with open(os.path.join(btrap_dir, "boltztrap.json"), "w") as f:
                f.write(json.dumps(d, default=DATETIME_HANDLER))
        else:
            mmdb = VaspCalcDb.from_db_file(db_file, admin=True)

            # dos gets inserted into GridFS
            dos = json.dumps(d["dos"], cls=MontyEncoder)
            fsid, compression = mmdb.insert_gridfs(dos, collection="dos_boltztrap_fs",
                                                   compress=True)
            d["dos_boltztrap_fs_id"] = fsid
            del d["dos"]

            mmdb.db.boltztrap.insert(d)
Esempio n. 3
0
    def run_task(self, fw_spec):

        from pymatgen.analysis.eos import EOS

        eos = self.get("eos", "vinet")
        tag = self["tag"]
        db_file = env_chk(self.get("db_file"), fw_spec)
        summary_dict = {"eos": eos}
        to_db = self.get("to_db", True)

        # collect and store task_id of all related tasks to make unique links with "tasks" collection
        all_task_ids = []

        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        # get the optimized structure
        d = mmdb.collection.find_one({"task_label": "{} structure optimization".format(tag)})
        all_task_ids.append(d["task_id"])
        structure = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure'])
        summary_dict["structure"] = structure.as_dict()
        summary_dict["formula_pretty"] = structure.composition.reduced_formula

        # get the data(energy, volume, force constant) from the deformation runs
        docs = mmdb.collection.find({"task_label": {"$regex": "{} bulk_modulus*".format(tag)},
                                     "formula_pretty": structure.composition.reduced_formula})
        energies = []
        volumes = []
        for d in docs:
            s = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure'])
            energies.append(d["calcs_reversed"][-1]["output"]['energy'])
            volumes.append(s.volume)
            all_task_ids.append(d["task_id"])
        summary_dict["energies"] = energies
        summary_dict["volumes"] = volumes
        summary_dict["all_task_ids"] = all_task_ids

        # fit the equation of state
        eos = EOS(eos)
        eos_fit = eos.fit(volumes, energies)
        summary_dict["bulk_modulus"] = eos_fit.b0_GPa

        # TODO: find a better way for passing tags of the entire workflow to db - albalu
        if fw_spec.get("tags", None):
            summary_dict["tags"] = fw_spec["tags"]
        summary_dict["results"] = dict(eos_fit.results)
        summary_dict["created_at"] = datetime.utcnow()

        # db_file itself is required but the user can choose to pass the results to db or not
        if to_db:
            mmdb.collection = mmdb.db["eos"]
            mmdb.collection.insert_one(summary_dict)
        else:
            with open("bulk_modulus.json", "w") as f:
                f.write(json.dumps(summary_dict, default=DATETIME_HANDLER))

        # TODO: @matk86 - there needs to be a builder to put it into materials collection... -computron
        logger.info("Bulk modulus calculation complete.")
Esempio n. 4
0
    def run_task(self, fw_spec):
        nm_eigenvecs = np.array(fw_spec["normalmodes"]["eigenvecs"])
        nm_eigenvals = np.array(fw_spec["normalmodes"]["eigenvals"])
        nm_norms = np.linalg.norm(nm_eigenvecs, axis=2)
        structure = fw_spec["normalmodes"]["structure"]
        masses = np.array([site.specie.data['Atomic mass'] for site in structure])
        nm_norms = nm_norms / np.sqrt(masses)  # eigenvectors in vasprun.xml are not divided by sqrt(M_i)
        # To get the actual eigenvals, the values read from vasprun.xml must be multiplied by -1.
        # frequency_i = sqrt(-e_i)
        # To convert the frequency to THZ: multiply sqrt(-e_i) by 15.633
        # To convert the frequency to cm^-1: multiply sqrt(-e_i) by 82.995
        nm_frequencies = np.sqrt(np.abs(nm_eigenvals)) * 82.995  # cm^-1

        d = {"structure": structure.as_dict(),
             "formula_pretty": structure.composition.reduced_formula,
             "normalmodes": {"eigenvals": fw_spec["normalmodes"]["eigenvals"],
                             "eigenvecs": fw_spec["normalmodes"]["eigenvecs"]
                             },
             "frequencies": nm_frequencies.tolist()}

        # store the displacement & epsilon for each mode in a dictionary
        mode_disps = fw_spec["raman_epsilon"].keys()
        modes_eps_dict = defaultdict(list)
        for md in mode_disps:
            modes_eps_dict[fw_spec["raman_epsilon"][md]["mode"]].append(
                [fw_spec["raman_epsilon"][md]["displacement"],
                 fw_spec["raman_epsilon"][md]["epsilon"]])

        # raman tensor = finite difference derivative of epsilon wrt displacement.
        raman_tensor_dict = {}
        scale = np.sqrt(structure.volume/2.0) / 4.0 / np.pi
        for k, v in modes_eps_dict.items():
            raman_tensor = (np.array(v[0][1]) - np.array(v[1][1])) / (v[0][0] - v[1][0])
            # frequency in cm^-1
            omega = nm_frequencies[k]
            if nm_eigenvals[k] > 0:
                logger.warn("Mode: {} is UNSTABLE. Freq(cm^-1) = {}".format(k, -omega))
            raman_tensor = scale * raman_tensor * np.sum(nm_norms[k]) / np.sqrt(omega)
            raman_tensor_dict[str(k)] = raman_tensor.tolist()

        d["raman_tensor"] = raman_tensor_dict
        d["state"] = "successful"

        # store the results
        db_file = env_chk(self.get("db_file"), fw_spec)
        if not db_file:
            with open("raman.json", "w") as f:
                f.write(json.dumps(d, default=DATETIME_HANDLER))
        else:
            db = VaspCalcDb.from_db_file(db_file, admin=True)
            db.collection = db.db["raman"]
            db.collection.insert_one(d)
            logger.info("Raman tensor calculation complete.")
        return FWAction()
Esempio n. 5
0
    def run_task(self, fw_spec):

        ref_file = self.get("json_filename", "task.json")
        calc_dir = self.get("calc_dir", os.getcwd())
        with open(os.path.join(calc_dir, ref_file), "r") as fp:
            task_doc = json.load(fp)

        db_file = env_chk(self.get('db_file'), fw_spec)
        if not db_file:
            with open("task.json", "w") as f:
                f.write(json.dumps(task_doc, default=DATETIME_HANDLER))
        else:
            mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
            mmdb.insert(task_doc)
Esempio n. 6
0
    def run_task(self, fw_spec):

        from atomate.vasp.analysis.phonopy import get_phonopy_thermal_expansion

        tag = self["tag"]
        db_file = env_chk(self.get("db_file"), fw_spec)
        t_step = self.get("t_step", 10)
        t_min = self.get("t_min", 0)
        t_max = self.get("t_max", 1000)
        mesh = self.get("mesh", [20, 20, 20])
        eos = self.get("eos", "vinet")
        pressure = self.get("pressure", 0.0)
        summary_dict = {}

        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        # get the optimized structure
        d = mmdb.collection.find_one({"task_label": "{} structure optimization".format(tag)})
        structure = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure'])
        summary_dict["structure"] = structure.as_dict()
        summary_dict["formula_pretty"] = structure.composition.reduced_formula

        # get the data(energy, volume, force constant) from the deformation runs
        docs = mmdb.collection.find({"task_label": {"$regex": "{} thermal_expansion*".format(tag)},
                                     "formula_pretty": structure.composition.reduced_formula})
        energies = []
        volumes = []
        force_constants = []
        for d in docs:
            s = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure'])
            energies.append(d["calcs_reversed"][-1]["output"]['energy'])
            volumes.append(s.volume)
            force_constants.append(d["calcs_reversed"][-1]["output"]['force_constants'])
        summary_dict["energies"] = energies
        summary_dict["volumes"] = volumes
        summary_dict["force_constants"] = force_constants

        alpha, T = get_phonopy_thermal_expansion(energies, volumes, force_constants, structure,
                                                 t_min, t_step, t_max, mesh, eos, pressure)

        summary_dict["alpha"] = alpha
        summary_dict["T"] = T

        with open("thermal_expansion.json", "w") as f:
            f.write(json.dumps(summary_dict, default=DATETIME_HANDLER))

        # TODO: @matk86 - there needs to be a way to insert this into a database! And also
        # a builder to put it into materials collection... -computron
        logger.info("Thermal expansion coefficient calculation complete.")
Esempio n. 7
0
    def run_task(self, fw_spec):

        from pymatgen.analysis.eos import EOS

        eos = self.get("eos", "vinet")
        tag = self["tag"]
        db_file = env_chk(self.get("db_file"), fw_spec)
        summary_dict = {"eos": eos}
        to_db = self.get("to_db", True)

        # collect and store task_id of all related tasks to make unique links with "tasks" collection
        all_task_ids = []

        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        # get the optimized structure
        d = mmdb.collection.find_one(
            {"task_label": "{} structure optimization".format(tag)})
        all_task_ids.append(d["task_id"])
        structure = Structure.from_dict(
            d["calcs_reversed"][-1]["output"]['structure'])
        summary_dict["structure"] = structure.as_dict()
        summary_dict["formula_pretty"] = structure.composition.reduced_formula

        # get the data(energy, volume, force constant) from the deformation runs
        docs = mmdb.collection.find({
            "task_label": {
                "$regex": "{} bulk_modulus*".format(tag)
            },
            "formula_pretty":
            structure.composition.reduced_formula
        })
        energies = []
        volumes = []
        for d in docs:
            s = Structure.from_dict(
                d["calcs_reversed"][-1]["output"]['structure'])
            energies.append(d["calcs_reversed"][-1]["output"]['energy'])
            volumes.append(s.volume)
            all_task_ids.append(d["task_id"])
        summary_dict["energies"] = energies
        summary_dict["volumes"] = volumes
        summary_dict["all_task_ids"] = all_task_ids

        # fit the equation of state
        eos = EOS(eos)
        eos_fit = eos.fit(volumes, energies)
        summary_dict["bulk_modulus"] = eos_fit.b0_GPa

        # TODO: find a better way for passing tags of the entire workflow to db - albalu
        if fw_spec.get("tags", None):
            summary_dict["tags"] = fw_spec["tags"]
        summary_dict["results"] = dict(eos_fit.results)
        summary_dict["created_at"] = datetime.utcnow()

        # db_file itself is required but the user can choose to pass the results to db or not
        if to_db:
            mmdb.collection = mmdb.db["eos"]
            mmdb.collection.insert_one(summary_dict)
        else:
            with open("bulk_modulus.json", "w") as f:
                f.write(json.dumps(summary_dict, default=DATETIME_HANDLER))

        # TODO: @matk86 - there needs to be a builder to put it into materials collection... -computron
        logger.info("Bulk modulus calculation complete.")
Esempio n. 8
0
    def run_task(self, fw_spec):
        additional_fields = self.get("additional_fields", {})

        # pass the additional_fields first to avoid overriding BoltztrapAnalyzer items
        d = additional_fields.copy()

        btrap_dir = os.path.join(os.getcwd(), "boltztrap")
        d["boltztrap_dir"] = btrap_dir

        bta = BoltztrapAnalyzer.from_files(btrap_dir)
        d.update(bta.as_dict())
        d["scissor"] = bta.intrans["scissor"]

        # trim the output
        for x in [
                'cond', 'seebeck', 'kappa', 'hall', 'mu_steps', 'mu_doping',
                'carrier_conc'
        ]:
            del d[x]

        if not self.get("hall_doping"):
            del d["hall_doping"]

        bandstructure_dir = os.getcwd()
        d["bandstructure_dir"] = bandstructure_dir

        # add the structure
        v, o = get_vasprun_outcar(bandstructure_dir,
                                  parse_eigen=False,
                                  parse_dos=False)
        structure = v.final_structure
        d["structure"] = structure.as_dict()
        d["formula_pretty"] = structure.composition.reduced_formula
        d.update(get_meta_from_structure(structure))

        # add the spacegroup
        sg = SpacegroupAnalyzer(Structure.from_dict(d["structure"]), 0.1)
        d["spacegroup"] = {
            "symbol": sg.get_space_group_symbol(),
            "number": sg.get_space_group_number(),
            "point_group": sg.get_point_group_symbol(),
            "source": "spglib",
            "crystal_system": sg.get_crystal_system(),
            "hall": sg.get_hall()
        }

        d["created_at"] = datetime.utcnow()

        db_file = env_chk(self.get('db_file'), fw_spec)

        if not db_file:
            del d["dos"]
            with open(os.path.join(btrap_dir, "boltztrap.json"), "w") as f:
                f.write(json.dumps(d, default=DATETIME_HANDLER))
        else:
            mmdb = VaspCalcDb.from_db_file(db_file, admin=True)

            # dos gets inserted into GridFS
            dos = json.dumps(d["dos"], cls=MontyEncoder)
            fsid, compression = mmdb.insert_gridfs(
                dos, collection="dos_boltztrap_fs", compress=True)
            d["dos_boltztrap_fs_id"] = fsid
            del d["dos"]

            mmdb.db.boltztrap.insert(d)
Esempio n. 9
0
    def run_task(self, fw_spec):
        nm_eigenvecs = np.array(fw_spec["normalmodes"]["eigenvecs"])
        nm_eigenvals = np.array(fw_spec["normalmodes"]["eigenvals"])
        nm_norms = np.linalg.norm(nm_eigenvecs, axis=2)
        structure = fw_spec["normalmodes"]["structure"]
        masses = np.array(
            [site.specie.data['Atomic mass'] for site in structure])
        nm_norms = nm_norms / np.sqrt(
            masses)  # eigenvectors in vasprun.xml are not divided by sqrt(M_i)
        # To get the actual eigenvals, the values read from vasprun.xml must be multiplied by -1.
        # frequency_i = sqrt(-e_i)
        # To convert the frequency to THZ: multiply sqrt(-e_i) by 15.633
        # To convert the frequency to cm^-1: multiply sqrt(-e_i) by 82.995
        nm_frequencies = np.sqrt(np.abs(nm_eigenvals)) * 82.995  # cm^-1

        d = {
            "structure": structure.as_dict(),
            "formula_pretty": structure.composition.reduced_formula,
            "normalmodes": {
                "eigenvals": fw_spec["normalmodes"]["eigenvals"],
                "eigenvecs": fw_spec["normalmodes"]["eigenvecs"]
            },
            "frequencies": nm_frequencies.tolist()
        }

        # store the displacement & epsilon for each mode in a dictionary
        mode_disps = fw_spec["raman_epsilon"].keys()
        modes_eps_dict = defaultdict(list)
        for md in mode_disps:
            modes_eps_dict[fw_spec["raman_epsilon"][md]["mode"]].append([
                fw_spec["raman_epsilon"][md]["displacement"],
                fw_spec["raman_epsilon"][md]["epsilon"]
            ])

        # raman tensor = finite difference derivative of epsilon wrt displacement.
        raman_tensor_dict = {}
        scale = np.sqrt(structure.volume / 2.0) / 4.0 / np.pi
        for k, v in modes_eps_dict.items():
            raman_tensor = (np.array(v[0][1]) - np.array(v[1][1])) / (v[0][0] -
                                                                      v[1][0])
            # frequency in cm^-1
            omega = nm_frequencies[k]
            if nm_eigenvals[k] > 0:
                logger.warn("Mode: {} is UNSTABLE. Freq(cm^-1) = {}".format(
                    k, -omega))
            raman_tensor = scale * raman_tensor * np.sum(
                nm_norms[k]) / np.sqrt(omega)
            raman_tensor_dict[str(k)] = raman_tensor.tolist()

        d["raman_tensor"] = raman_tensor_dict
        d["state"] = "successful"

        # store the results
        db_file = env_chk(self.get("db_file"), fw_spec)
        if not db_file:
            with open("raman.json", "w") as f:
                f.write(json.dumps(d, default=DATETIME_HANDLER))
        else:
            db = VaspCalcDb.from_db_file(db_file, admin=True)
            db.collection = db.db["raman"]
            db.collection.insert_one(d)
            logger.info("Raman tensor calculation complete.")
        return FWAction()
Esempio n. 10
0
    def run_task(self, fw_spec):
        # handle arguments and database setup
        db_file = env_chk(self.get("db_file"), fw_spec)
        tag = self["tag"]

        vasp_db = VaspCalcDb.from_db_file(db_file, admin=True)

        # get the energies, volumes and DOS objects by searching for the tag
        static_calculations = vasp_db.collection.find({"metadata.tag": tag})

        energies = []
        volumes = []
        dos_objs = []  # pymatgen.electronic_structure.dos.Dos objects
        structure = None  # single Structure for QHA calculation
        for calc in static_calculations:
            energies.append(calc['output']['energy'])
            volumes.append(calc['output']['structure']['lattice']['volume'])
            dos_objs.append(vasp_db.get_dos(calc['task_id']))
            # get a Structure. We only need one for the masses and number of atoms in the unit cell.
            if structure is None:
                structure = Structure.from_dict(calc['output']['structure'])

        # sort everything in volume order
        # note that we are doing volume last because it is the thing we are sorting by!

        energies = sort_x_by_y(energies, volumes)
        dos_objs = sort_x_by_y(dos_objs, volumes)
        volumes = sorted(volumes)


        qha_result = {}
        qha_result['structure'] = structure.as_dict()
        qha_result['formula_pretty'] = structure.composition.reduced_formula
        qha_result['metadata'] = self.get('metadata', {})
        qha_result['has_phonon'] = self['phonon']

        # phonon properties
        if self['phonon']:
            # get the vibrational properties from the FW spec
            phonon_calculations = list(vasp_db.db['phonon'].find({'metadata.tag': tag}))
            vol_vol = [calc['volume'] for calc in phonon_calculations]  # these are just used for sorting and will be thrown away
            vol_f_vib = [calc['F_vib'] for calc in phonon_calculations]
            # sort them order of the unit cell volumes
            vol_f_vib = sort_x_by_y(vol_f_vib, vol_vol)
            f_vib = np.vstack(vol_f_vib)
            qha = Quasiharmonic(energies, volumes, structure, dos_objects=dos_objs, F_vib=f_vib,
                                t_min=self['t_min'], t_max=self['t_max'], t_step=self['t_step'],
                                poisson=self.get('poisson', 0.25), bp2gru=self.get('bp2gru', 1))
            qha_result['phonon'] = qha.get_summary_dict()
            qha_result['phonon']['temperatures'] = qha_result['phonon']['temperatures'].tolist()

        # calculate the Debye model results no matter what
        qha_debye = Quasiharmonic(energies, volumes, structure, dos_objects=dos_objs, F_vib=None,
                                  t_min=self['t_min'], t_max=self['t_max'], t_step=self['t_step'],
                                  poisson=self.get('poisson', 0.25), bp2gru=self.get('bp2gru', 1))


        qha_result['debye'] = qha_debye.get_summary_dict()
        qha_result['debye']['temperatures'] = qha_result['debye']['temperatures'].tolist()

        # write to JSON for debugging purposes
        import json
        with open('qha_summary.json', 'w') as fp:
            json.dump(qha_result, fp)

        vasp_db.db['qha'].insert_one(qha_result)
Esempio n. 11
0
    def run_task(self, fw_spec):
        # handle arguments and database setup
        db_file = env_chk(self.get("db_file"), fw_spec)
        tag = self["tag"]

        vasp_db = VaspCalcDb.from_db_file(db_file, admin=True)

        # get the energies, volumes and DOS objects by searching for the tag
        static_calculations = vasp_db.collection.find({"metadata.tag": tag})

        energies = []
        volumes = []
        dos_objs = []  # pymatgen.electronic_structure.dos.Dos objects
        structure = None  # single Structure for QHA calculation
        for calc in static_calculations:
            energies.append(calc['output']['energy'])
            volumes.append(calc['output']['structure']['lattice']['volume'])
            dos_objs.append(vasp_db.get_dos(calc['task_id']))
            # get a Structure. We only need one for the masses and number of atoms in the unit cell.
            if structure is None:
                structure = Structure.from_dict(calc['output']['structure'])

        # sort everything in volume order
        # note that we are doing volume last because it is the thing we are sorting by!

        energies = sort_x_by_y(energies, volumes)
        dos_objs = sort_x_by_y(dos_objs, volumes)
        volumes = sorted(volumes)

        qha_result = {}
        qha_result['structure'] = structure.as_dict()
        qha_result['formula_pretty'] = structure.composition.reduced_formula
        qha_result['elements'] = sorted(
            [el.name for el in structure.composition.elements])
        qha_result['metadata'] = self.get('metadata', {})
        qha_result['has_phonon'] = self['phonon']

        poisson = self.get('poisson', 0.363615)
        bp2gru = self.get('bp2gru', 1)

        # phonon properties
        if self['phonon']:
            # get the vibrational properties from the FW spec
            phonon_calculations = list(vasp_db.db['phonon'].find(
                {'metadata.tag': tag}))
            vol_vol = [
                calc['volume'] for calc in phonon_calculations
            ]  # these are just used for sorting and will be thrown away
            vol_f_vib = [calc['F_vib'] for calc in phonon_calculations]
            # sort them order of the unit cell volumes
            vol_f_vib = sort_x_by_y(vol_f_vib, vol_vol)
            f_vib = np.vstack(vol_f_vib)
            qha = Quasiharmonic(energies,
                                volumes,
                                structure,
                                dos_objects=dos_objs,
                                F_vib=f_vib,
                                t_min=self['t_min'],
                                t_max=self['t_max'],
                                t_step=self['t_step'],
                                poisson=poisson,
                                bp2gru=bp2gru)
            qha_result['phonon'] = qha.get_summary_dict()
            qha_result['phonon']['temperatures'] = qha_result['phonon'][
                'temperatures'].tolist()

        # calculate the Debye model results no matter what
        qha_debye = Quasiharmonic(energies,
                                  volumes,
                                  structure,
                                  dos_objects=dos_objs,
                                  F_vib=None,
                                  t_min=self['t_min'],
                                  t_max=self['t_max'],
                                  t_step=self['t_step'],
                                  poisson=poisson,
                                  bp2gru=bp2gru)

        # fit 0 K EOS for good measure
        eos = Vinet(volumes, energies)
        eos.fit()
        errors = eos.func(volumes) - energies
        sum_square_error = float(np.sum(np.square(errors)))
        eos_res = {}
        eos_res['b0_GPa'] = float(eos.b0_GPa)
        eos_res['b0'] = float(eos.b0)
        eos_res['b1'] = float(eos.b1)
        eos_res['eq_volume'] = float(eos.v0)
        eos_res['eq_energy'] = float(eos.e0)
        eos_res['energies'] = energies
        eos_res['volumes'] = volumes
        eos_res['name'] = 'Vinet'
        eos_res['error'] = {}
        eos_res['error']['difference'] = errors.tolist(
        )  # volume by volume differences
        eos_res['error']['sum_square_error'] = sum_square_error
        qha_result['eos'] = eos_res

        qha_result['debye'] = qha_debye.get_summary_dict()
        qha_result['debye']['poisson'] = poisson
        qha_result['debye']['bp2gru'] = bp2gru
        qha_result['debye']['temperatures'] = qha_result['debye'][
            'temperatures'].tolist()

        qha_result['launch_dir'] = str(os.getcwd())

        # write to JSON for debugging purposes
        import json
        with open('qha_summary.json', 'w') as fp:
            json.dump(qha_result, fp)

        if self['phonon']:
            vasp_db.db['qha_phonon'].insert_one(qha_result)
        else:
            vasp_db.db['qha'].insert_one(qha_result)
Esempio n. 12
0
    def check_vol_coverage(self, volume, vol_spacing, vol_orig, run_num,
                           energy, structure, dos_objects, phonon, db_file,
                           tag, t_min, t_max, t_step, EVcheck_result):
        result = []
        volumer = volume.copy()

        # Check minimum spacing
        volumer = [vol_i / vol_orig for vol_i in volumer]
        """
        decimals = 4
        for m in range(len(volumer) - 1):
            vol_space_m = volumer[m + 1] - volumer[m]
            if np.around(vol_space_m, decimals) > np.around(vol_spacing, decimals):
                vol = np.linspace(volumer[m], volumer[m + 1], math.ceil(vol_space_m / vol_spacing) + 1).tolist()
                print('Additional volume({}) is appended for the volume space({}) is larger than specified({})'.format(vol[1:-1], vol_space_m, vol_spacing))
                result.append(vol[1:-1])
                #result.extend(vol[1:-1])
        """

        # To check (and extend) deformation coverage
        # To make sure that coverage extension smaller than interpolation spacing
        vol_spacing = vol_spacing * 0.98

        qha = Quasiharmonic(energy,
                            volume,
                            structure,
                            dos_objects=dos_objects,
                            F_vib=None,
                            t_min=t_min,
                            t_max=t_max,
                            t_step=t_step,
                            poisson=0.363615,
                            bp2gru=2. / 3.)
        vol_max = np.nanmax(qha.optimum_volumes)
        vol_min = np.nanmin(qha.optimum_volumes)
        EVcheck_result['debye'] = qha.get_summary_dict()
        EVcheck_result['debye']['temperatures'] = EVcheck_result['debye'][
            'temperatures'].tolist()
        if phonon:
            # get the vibrational properties from the FW spec
            # TODO: add a stable check in Quasiharmonic
            vasp_db = VaspCalcDb.from_db_file(db_file=db_file, admin=True)
            phonon_calculations = list(vasp_db.db['phonon'].find(
                {'$and': [{
                    'metadata.tag': tag
                }, {
                    'adopted': True
                }]}))
            #vol_vol = [calc['volume'] for calc in phonon_calculations]  # these are just used for sorting and will be thrown away
            #vol_f_vib = [calc['F_vib'] for calc in phonon_calculations]
            vol_vol = []
            vol_f_vib = []
            for calc in phonon_calculations:
                if calc['volume'] in vol_vol: continue
                if calc['volume'] not in volume: continue
                vol_vol.append(calc['volume'])
                vol_f_vib.append(calc['F_vib'])
            # sort them order of the unit cell volumes
            vol_f_vib = sort_x_by_y(vol_f_vib, vol_vol)
            f_vib = np.vstack(vol_f_vib)
            qha_phonon = Quasiharmonic(energy,
                                       volume,
                                       structure,
                                       dos_objects=dos_objects,
                                       F_vib=f_vib,
                                       t_min=t_min,
                                       t_max=t_max,
                                       t_step=t_step,
                                       poisson=0.363615,
                                       bp2gru=2. / 3.)
            vol_max = max(np.nanmax(qha_phonon.optimum_volumes), vol_max)
            vol_min = min(np.nanmax(qha_phonon.optimum_volumes), vol_min)
            EVcheck_result['phonon'] = qha_phonon.get_summary_dict()
            EVcheck_result['phonon']['temperatures'] = EVcheck_result[
                'phonon']['temperatures'].tolist()
        EVcheck_result['MIN_volume_Evaluated'] = '%.3f' % vol_min
        EVcheck_result['MAX_volume_Evaluated'] = '%.3f' % vol_max
        print('Evaluated MIN volume is %.3f;' % vol_min)
        print('Evaluated MAX volume is %.3f;' % vol_max)
        """
        vol_max = vol_max / vol_orig
        vol_min = vol_min / vol_orig
        counter = 1
        # Using max_append for reducing unnecessary calculations because of rough fitting
        max_append = 1 if phonon else 2
        # Over coverage ratio set to 1.01 as following
        if volumer[-1] * 1.01 < vol_max:
            print('The current maximum volume is smaller than maximum volume evaluated by quasiharmonic analysis')
            result.append(volumer[-1] + vol_spacing)
            # counter is set to limit calculation times when exception occurs
            while (counter < max_append) and (result[-1] < vol_max):
                result.append(result[-1] + vol_spacing)
                counter += 1
        counter = 1
        if volumer[0] * 0.99 > vol_min:
            print('The current minimum volume is larger than minimum volume evaluated by quasiharmonic analysis')
            result.append(volumer[0] - vol_spacing)
            while (counter < max_append) and (result[-1] > vol_min):
                result.append(result[-1] - vol_spacing)
                counter += 1
        """
        val, idx = min((val, idx) for (idx, val) in enumerate(energy))
        nV = len(energy)
        nV_addL = 3
        if nV_addL - idx > 0:
            vol_spacing = volumer[1] - volumer[0]
            for i in range(nV_addL - idx):
                result.append(volumer[0] - (nV_addL - idx - i) * vol_spacing)
        nV_addR = 4
        if idx + 1 + nV_addR - nV > 0:
            vol_spacing = volumer[-1] - volumer[-2]
            for i in range(idx + 1 + nV_addR - nV):
                result.append(volumer[-1] + (i + 1) * vol_spacing)
        return (np.array(result))
Esempio n. 13
0
    def run_task(self, fw_spec):
        # get the database connection
        db_file = env_chk(self["db_file"], fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        mmdb.collection = mmdb.db["approx_neb"]
        wf_uuid = self["approx_neb_wf_uuid"]
        launch_mode = self["launch_mode"]
        images_key = self["images_key"]

        approx_neb_doc = mmdb.collection.find_one({"wf_uuid": wf_uuid}, {"images": 1})
        all_images = approx_neb_doc["images"]

        # get structure_path of desired images and sort into structure_paths
        if images_key and isinstance(all_images, (dict)):
            images = all_images[images_key]
            max_n = len(images)
            if launch_mode == "all":
                structure_paths = [
                    "images." + images_key + "." + str(n) + ".input_structure"
                    for n in range(0, max_n)
                ]
            elif launch_mode == "screening":
                structure_paths = self.get_and_sort_paths(
                    max_n=max_n, images_key=images_key
                )
        elif isinstance(all_images, (dict)):
            structure_paths = dict()
            if launch_mode == "all":
                for key, images in all_images.items():
                    max_n = len(images)
                    structure_paths[key] = [
                        "images." + key + "." + str(n) + ".input_structure"
                        for n in range(0, max_n)
                    ]
            elif launch_mode == "screening":
                for key, images in all_images.items():
                    structure_paths[key] = self.get_and_sort_paths(
                        max_n=len(images), images_key=key
                    )

        # get list of fireworks to launch
        if isinstance(structure_paths, (list)):
            if isinstance(structure_paths[0], (str)):
                relax_image_fws = []
                for path in structure_paths:
                    relax_image_fws.append(self.get_fw(structure_path=path))
            else:
                relax_image_fws = self.get_screening_fws(sorted_paths=structure_paths)
        elif isinstance(structure_paths, (dict)):
            relax_image_fws = []
            if launch_mode == "all":
                for key in structure_paths.keys():
                    for path in structure_paths[key]:
                        relax_image_fws.append(self.get_fw(structure_path=path))
            elif launch_mode == "screening":
                for key in structure_paths.keys():
                    sorted_paths = structure_paths[key]
                    relax_image_fws.extend(
                        self.get_screening_fws(sorted_paths=sorted_paths)
                    )

        # place fws in temporary wf in order to use powerup_by_kwargs
        # to apply powerups to image fireworks
        if "vasp_powerups" in fw_spec.keys():
            temp_wf = Workflow(relax_image_fws)
            powerup_dicts = fw_spec["vasp_powerups"]
            temp_wf = powerup_by_kwargs(temp_wf, powerup_dicts)
            relax_image_fws = temp_wf.fws

        return FWAction(additions=relax_image_fws)
Esempio n. 14
0
    def run_task(self, fw_spec):
        d = {
            "analysis": {},
            "deformation_tasks": fw_spec["deformation_tasks"],
            "initial_structure": self['structure'].as_dict()
        }

        # Get optimized structure
        calc_locs_opt = [
            cl for cl in fw_spec['calc_locs'] if 'optimize' in cl['name']
        ]
        if calc_locs_opt:
            optimize_loc = calc_locs_opt[-1]['path']
            logger.info("Parsing initial optimization directory: {}".format(
                optimize_loc))
            drone = VaspDrone()
            optimize_doc = drone.assimilate(optimize_loc)
            opt_struct = Structure.from_dict(
                optimize_doc["calcs_reversed"][0]["output"]["structure"])
            d.update({"optimized_structure": opt_struct.as_dict()})

        # TODO: @montoyjh: does the below have anything to do with elastic tensor? If not, try
        # the more general fw_spec_field approach in the VaspToDb rather than hard-coding the
        # tags insertion here. -computron
        if fw_spec.get("tags", None):
            d["tags"] = fw_spec["tags"]

        results = fw_spec["deformation_tasks"].values()
        defos = [r["deformation_matrix"] for r in results]
        stresses = [r["stress"] for r in results]
        strains = np.array([Strain(r["strain"]).voigt for r in results])
        stress_dict = {
            IndependentStrain(defo): Stress(stress)
            for defo, stress in zip(defos, stresses)
        }

        logger.info("Analyzing stress/strain data")
        # Determine if we have 6 unique deformations
        # TODO: @montoyjh: what if it's a cubic system? don't need 6. -computron
        if np.linalg.matrix_rank(strains) == 6:
            # Perform Elastic tensor fitting and analysis
            result = ElasticTensor.from_stress_dict(stress_dict)
            d["elastic_tensor"] = result.voigt.tolist()
            d.update(result.property_dict)

        else:
            raise ValueError("Fewer than 6 unique deformations")

        d["state"] = "successful"

        # Save analysis results in json or db
        db_file = env_chk(self.get('db_file'), fw_spec)
        if not db_file:
            with open("elasticity.json", "w") as f:
                f.write(json.dumps(d, default=DATETIME_HANDLER))
        else:
            db = VaspCalcDb.from_db_file(db_file, admin=True)
            db.collection = db.db["elasticity"]
            db.collection.insert_one(d)
            logger.info("Elastic analysis complete.")
        return FWAction()
Esempio n. 15
0
    def run_task(self, fw_spec):
        # get the database connection
        db_file = env_chk(self["db_file"], fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        wf_uuid = self.get("approx_neb_wf_uuid")

        insert_specie = self["insert_specie"]
        insert_coords = self["insert_coords"]
        end_points_index = self["end_points_index"]
        # put in list if insert_coords provided as a single coordinate to avoid error
        if isinstance(insert_coords[0], (float, int)):
            insert_coords = [insert_coords]

        # get output structure from host_task_id or approx_neb collection
        t_id = self.get("host_task_id", fw_spec.get("host_task_id"))
        if t_id:
            structure_doc = mmdb.collection.find_one({"task_id": t_id})
        else:
            mmdb.collection = mmdb.db["approx_neb"]
            approx_neb_doc = mmdb.collection.find_one({"wf_uuid": wf_uuid})
            structure_doc = approx_neb_doc["host"]["output"]["structure"]

        structure = Structure.from_dict(structure_doc["output"]["structure"])
        # removes site properties to avoid error
        if structure.site_properties != {}:
            for p in structure.site_properties.keys():
                structure.remove_site_property(p)

        # insert site(s) in structure and stores corresponding site index in inserted_site_indexes
        inserted_site_indexes = []
        for coords in sorted(insert_coords, reverse=True):
            structure.insert(
                0,
                insert_specie,
                coords,
                coords_are_cartesian=self.get("coords_are_cartesian", False),
            )
            inserted_site_indexes = [i + 1 for i in inserted_site_indexes]
            inserted_site_indexes.insert(0, 0)

        # store end point input structures in approx_neb collection
        mmdb.collection = mmdb.db["approx_neb"]
        mmdb.collection.update_one(
            {"wf_uuid": wf_uuid},
            {
                "$set": {
                    "end_points." + str(end_points_index): {
                        "input_structure": structure.as_dict(),
                        "inserted_site_indexes": inserted_site_indexes,
                        "insert_coords": insert_coords,
                    }
                }
            },
        )

        stored_data = {
            "modified_structure":
            structure.as_dict(),
            "inserted_site_indexes":
            inserted_site_indexes,
            "structure_path":
            "end_points." + str(end_points_index) + ".input_structure",
        }

        return FWAction(
            update_spec={
                "insert_specie": insert_specie,
                "inserted_site_indexes": inserted_site_indexes,
            },
            stored_data=stored_data,
        )
Esempio n. 16
0
    def run_task(self, fw_spec):

        surfaces = ["kx_0", "kx_1", "ky_0", "ky_1", "kz_0", "kz_1"]
        structure = self["structure"]
        symmetry_reduction = self["symmetry_reduction"]
        equiv_planes = self["equiv_planes"]

        # Get invariants for each surface
        uuid = self["wf_uuid"]
        db_file = env_chk(self.get("db_file"), fw_spec)
        db = VaspCalcDb.from_db_file(db_file, admin=True)
        db.collection = db.db["z2pack"]

        task_docs = db.collection.find({"wf_uuid": uuid})

        z2_dict = {}
        chern_dict = {}
        for doc in task_docs:
            for s in surfaces:
                if s in doc.keys():
                    z2_dict[s] = doc[s]["z2_invariant"]
                    chern_dict[s] = doc[s]["chern_number"]

        # Write invariants for equivalent planes
        if symmetry_reduction and len(z2_dict) < 6:  # some equivalent planes
            for surface in equiv_planes.keys():
                # Z2
                if surface in z2_dict.keys() and len(equiv_planes[surface]) > 0:
                    for ep in equiv_planes[surface]:
                        if ep not in z2_dict.keys():
                            z2_dict[ep] = z2_dict[surface]
                # Chern
                if surface in chern_dict.keys() and len(equiv_planes[surface]) > 0:
                    for ep in equiv_planes[surface]:
                        if ep not in chern_dict.keys():
                            chern_dict[ep] = chern_dict[surface]

        # Compute Z2 invariant
        if all(
            surface in z2_dict.keys() for surface in ["kx_1", "ky_1", "kz_0", "kz_1"]
        ):
            v0 = (z2_dict["kz_0"] + z2_dict["kz_1"]) % 2
            v1 = z2_dict["kx_1"]
            v2 = z2_dict["ky_1"]
            v3 = z2_dict["kz_1"]
            z2 = (v0, v1, v2, v3)
        else:
            z2 = (np.nan, np.nan, np.nan, np.nan)

        # store the results
        d = {
            "wf_uuid": uuid,
            "task_label": "topological invariants",
            "formula": structure.composition.formula,
            "reduced_formula": structure.composition.reduced_formula,
            "structure": structure.as_dict(),
            "z2_dict": z2_dict,
            "chern_dict": chern_dict,
            "z2": z2,
            "equiv_planes": equiv_planes,
            "symmetry_reduction": symmetry_reduction,
        }

        d = jsanitize(d)

        db.collection.insert_one(d)

        return FWAction()
Esempio n. 17
0
def test_get_static_calculations():
    tag = '8e7b216d-c6b6-4da4-905e-e7afd44195aa'
    vasp_db = VaspCalcDb.from_db_file(db_file=db_file, admin=True)
    volumes, energies, dos_objs, _ = get_static_calculations(vasp_db, tag)
    #print(volumes, energies)
    assert False
Esempio n. 18
0
    def run_task(self, fw_spec):

        ncl_magmoms = self["ncl_magmoms"]

        # Get num of electrons and bands from static calc
        uuid = self["wf_uuid"]
        db_file = env_chk(self.get("db_file"), fw_spec)
        db = VaspCalcDb.from_db_file(db_file, admin=True)
        db.collection = db.db["tasks"]

        task_doc = db.collection.find_one(
            {"wf_meta.wf_uuid": uuid, "task_label": "static"}, ["input.parameters"]
        )

        nelec = int(task_doc["input"]["parameters"]["NELECT"])
        nbands = int(task_doc["input"]["parameters"]["NBANDS"])

        incar = Incar.from_file("INCAR")

        # Modify INCAR for Z2Pack
        incar_update = {
            "PREC": "Accurate",
            "LSORBIT": ".TRUE.",
            "GGA_COMPAT": ".FALSE.",
            "LASPH": ".TRUE.",
            "ISMEAR": 0,
            "SIGMA": 0.05,
            "ISYM": -1,
            "LPEAD": ".FALSE.",
            "LWANNIER90": ".TRUE.",
            "LWRITE_MMN_AMN": ".TRUE.",
            "LWAVE": ".FALSE.",
            "ICHARG": 11,
            "MAGMOM": "%s" % ncl_magmoms,
            "NBANDS": "%d" % (2 * nbands),
        }

        incar.update(incar_update)
        incar.write_file("INCAR")

        try:
            struct = Structure.from_file("POSCAR")
            formula = struct.composition.formula
            reduced_formula = struct.composition.reduced_formula
            structure = struct.as_dict()

        except:
            formula = None
            structure = None
            reduced_formula = None

        files_to_copy = ["CHGCAR", "INCAR", "POSCAR", "POTCAR", "wannier90.win"]

        os.mkdir("input")
        for file in files_to_copy:
            shutil.move(file, "input")

        return FWAction(
            update_spec={
                "structure": structure,
                "formula": formula,
                "reduced_formula": reduced_formula,
            }
        )
Esempio n. 19
0
    def run_task(self, fw_spec):
        # get the database connection
        db_file = env_chk(self["db_file"], fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        wf_uuid = self["approx_neb_wf_uuid"]
        t_id = self.get("image_task_id", fw_spec.get("image_task_id"))

        # get any workflow inputs provided in fw_spec to store in task_doc
        wf_input_host_structure = fw_spec.get("wf_input_host_structure")
        wf_input_insert_coords = []
        for key, value in fw_spec.items():
            if "wf_input_insert_coords" in key:
                wf_input_insert_coords.append(value)

        # get task doc (parts stored in approx_neb collection) and update for record keeping
        task_doc = mmdb.collection.find_one_and_update(
            {
                "task_id": t_id,
                "approx_neb.calc_type": "image"
            },
            {
                "$push": {
                    "approx_neb.wf_uuids": wf_uuid
                },
                "$set": {
                    "approx_neb._wf_input_host_structure":
                    wf_input_host_structure,
                    "approx_neb._wf_input_insert_coords":
                    wf_input_insert_coords,
                },
            },
        )
        if task_doc == None:
            raise ValueError(
                "Error updating approx neb image with task_id: {}".format(
                    t_id))

        # Store info in approx_neb collection for record keeping
        images_key = task_doc["approx_neb"]["images_key"]
        index = task_doc["approx_neb"]["image_index"]
        mmdb.collection = mmdb.db["approx_neb"]
        images_subdoc = mmdb.collection.find_one({"wf_uuid": wf_uuid}, {
            "images": 1,
            "_id": 0
        })
        images_subdoc = images_subdoc["images"]
        image_output = {
            "dir_name": task_doc["dir_name"],
            "formula_pretty": task_doc["formula_pretty"],
            "output": task_doc["output"],
            "task_id": task_doc["task_id"],
        }
        images_subdoc[images_key][index].update(image_output)

        # path = "images." + images_key + "." + str(index) + "."
        # image_output = {
        #    path + "dir_name": task_doc["dir_name"],
        #    path + "formula_pretty": task_doc["formula_pretty"],
        #    path + "output": task_doc["output"],
        #    path + "task_id": task_doc["task_id"],
        #    "last_updated": datetime.utcnow(),
        # }

        mmdb.collection.update_one(
            {"wf_uuid": wf_uuid},
            {
                "$set": {
                    "images": images_subdoc,
                    "last_updated": datetime.utcnow()
                }
            },
        )

        return FWAction(
            stored_data={
                "wf_uuid": wf_uuid,
                "image_index": index,
                "image_output": image_output,
            })
Esempio n. 20
0
    def run_task(self, fw_spec):
        n_images = self["n_images"]
        end_points_combo = self["end_points_combo"]
        # checks if format of end_points_combo is correct and if so
        # get two desired end_points indexes for end point structures
        try:
            combo = end_points_combo.split("+")
            if len(combo) == 2:
                c = [int(combo[0]), int(combo[1])]
            else:
                raise ValueError(
                    "NEBPathfinder requires exactly two end points")
        except:
            raise ValueError("{} end_points_combo input is incorrect".format(
                str(end_points_combo)))

        # get the database connection
        db_file = env_chk(self["db_file"], fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        mmdb.collection = mmdb.db["approx_neb"]
        wf_uuid = self["approx_neb_wf_uuid"]

        # get end_points and task_id of host from approx_neb collection
        approx_neb_doc = mmdb.collection.find_one({"wf_uuid": wf_uuid}, {
            "end_points": 1,
            "host.task_id": 1,
            "_id": 0
        })
        end_points = approx_neb_doc["end_points"]
        task_id = approx_neb_doc["host"]["task_id"]

        # get potential gradient, v, from host chgcar
        mmdb.collection = mmdb.db["tasks"]
        host_chgcar = mmdb.get_chgcar(task_id)
        v_chgcar = ChgcarPotential(host_chgcar)
        host_v = v_chgcar.get_v()

        # get start and end point structures from end_points
        start_struct = Structure.from_dict(
            end_points[c[0]]["output"]["structure"])
        end_struct = Structure.from_dict(
            end_points[c[1]]["output"]["structure"])

        # checks if inserted site indexes match
        inserted_site_indexes = end_points[c[0]]["inserted_site_indexes"]
        if inserted_site_indexes != end_points[c[1]]["inserted_site_indexes"]:
            raise ValueError(
                "Inserted site indexes of end point structures must match for NEBPathfinder"
            )

        # applies NEBPathFinder to interpolate and get images to store in
        # pathfinder_output.
        neb_pf = NEBPathfinder(
            start_struct,
            end_struct,
            relax_sites=inserted_site_indexes,
            v=host_v,
            n_images=n_images + 1,
        )
        # note NEBPathfinder currently returns n_images+1 images (rather than n_images)
        # and the first and last images generated are very similar to the end points
        # provided so they are discarded
        pathfinder_output = {
            "images":
            [structure.as_dict() for structure in neb_pf.images[1:-1]],
            "relax_site_indexes": inserted_site_indexes,
        }

        # stores images generated by NEBPathFinder in approx_neb collection
        # pathfinder field which is a nested dictionary using
        # end_points_combo as a key.
        mmdb.collection = mmdb.db["approx_neb"]
        pf_subdoc = mmdb.collection.find_one({"wf_uuid": wf_uuid}, {
            "pathfinder": 1,
            "_id": 0
        })
        if "pathfinder" not in pf_subdoc.keys():
            pf_subdoc = {}
        else:
            pf_subdoc = pf_subdoc["pathfinder"]
        pf_subdoc.update({end_points_combo: pathfinder_output})

        mmdb.collection.update_one(
            {"wf_uuid": wf_uuid},
            {
                "$set": {
                    "pathfinder": pf_subdoc,
                    "last_updated": datetime.utcnow()
                }
            },
        )

        return FWAction(
            stored_data={
                "wf_uuid": wf_uuid,
                "end_points_combo": c,
                "pathfinder": pathfinder_output,
            })
Esempio n. 21
0
    def run_task(self, fw_spec):
        # get the database connection
        db_file = env_chk(self["db_file"], fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        wf_uuid = self["approx_neb_wf_uuid"]

        # check if provided approx_neb_wf_uuid is unique
        # e.g. not already used in approx_neb collection
        approx_neb_db = mmdb.db["approx_neb"]
        if approx_neb_db.count_documents({"wf_uuid": wf_uuid}) != 0:
            raise ValueError(
                "Provided approx_neb_wf_uuid is not unique. A unique workflow id is required for querying in the approx_neb workflow."
            )

        # update host task doc (from host_task_id) with unique wf_uuid
        # (tracks approx_neb workflows generated from this host task doc)
        t_id = self.get("host_task_id", fw_spec.get("host_task_id"))
        host_tasks_doc = mmdb.collection.find_one_and_update(
            {
                "task_id": t_id,
                "approx_neb.calc_type": "host"
            },
            {"$push": {
                "approx_neb.wf_uuids": wf_uuid
            }},
        )
        if host_tasks_doc == None:
            raise ValueError(
                "Error updating approx neb host with task_id: {}".format(t_id))

        # Initialize and store select host task doc fields in approx_neb_doc
        # (to be stored in the approx_neb collection)
        approx_neb_doc = {
            "wf_uuid": wf_uuid,
            "host": {
                "dir_name": host_tasks_doc["dir_name"],
                "chemsys": host_tasks_doc["chemsys"],
                "formula_pretty": host_tasks_doc["formula_pretty"],
                "input_structure": host_tasks_doc["input"]["structure"],
                "output": host_tasks_doc["output"],
                "task_id": host_tasks_doc["task_id"],
            },
            "end_points": [],
        }

        # ensure tags and additional_fields are the same
        # in both the approx_neb and tasks collections
        additional_fields = self.get("additional_fields", {})
        if isinstance(additional_fields, dict):
            for key, value in additional_fields.items():
                if key not in approx_neb_doc.keys():
                    approx_neb_doc[key] = value

        tags = self.get("tags")
        if tags:
            approx_neb_doc["tags"] = tags

        # insert approx_neb_doc in the approx_neb collection of provided database
        # includes fix to ensure approx_neb_doc is a json serializable dict
        approx_neb_doc = MontyEncoder().encode(approx_neb_doc)
        approx_neb_doc = loads(approx_neb_doc)
        approx_neb_doc["last_updated"] = datetime.utcnow()
        mmdb.collection = mmdb.db["approx_neb"]
        mmdb.collection.insert_one(approx_neb_doc)

        # Update fw_spec with approx_neb_doc and store wf_uuid
        # in launches collection for record keeping
        return FWAction(stored_data={
            "wf_uuid": wf_uuid,
            "approx_neb_doc": approx_neb_doc
        })
Esempio n. 22
0
def remove_data_by_metadata(tag,
                            db_file=None,
                            rem_mode='vol',
                            forcedelete=False):
    '''
    rem_mode: str/list
        allvol: remove all volume collection
        vol: remove volume collection except bandstructure and dos
        property: other collections except volume
        all: all
        aeccar: remove all aeccar related
        chgcar: remove chgcar
        locpot: remove locpot

    '''
    if (db_file is None) or (db_file == '>>db_file<<'):
        db_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"]
    vasp_db = VaspCalcDb.from_db_file(db_file, admin=True)
    metadata = {'tag': tag}

    VOL1_COLLECTION = [
        'aeccar0', 'aeccar1', 'aeccar2', 'chgcar', 'locpot', 'elfcar'
    ]
    VOL2_COLLECTION = ['bandstructure', 'dos']
    VOL_COLLECTION = VOL1_COLLECTION + VOL2_COLLECTION
    OTHER_COLLECTION = [
        'borncharge', 'phonon', 'qha', 'qha_phonon', 'relax', 'relax_scheme',
        'relaxations', 'tasks', 'xmlgz'
    ]
    if isinstance(rem_mode, str):
        rem_mode = rem_mode.lower()
        if rem_mode == 'all':
            collections = VOL_COLLECTION + OTHER_COLLECTION
        elif rem_mode == 'allvol':
            collections = VOL_COLLECTION
        elif rem_mode == 'vol':
            collections = VOL1_COLLECTION
        elif rem_mode == 'property':
            collections = OTHER_COLLECTION
        elif rem_mode == 'aeccar':
            collections = ['aeccar0', 'aeccar1', 'aeccar2']
        else:
            collections = [rem_mode]
    elif isinstance(rem_mode, list):
        collections = rem_mode
    else:
        raise ValueError(
            'Unsupported remove mode, please provide a str or list')

    flag_remove = False
    if forcedelete:
        flag_remove = True
    else:
        if tag:
            if input(
                    'Are you sure? This will remove all data in {} collection with metadata.tag={}. (Y/N)'
                    .format(collections, tag))[0].upper() == 'Y':
                flag_remove = True
        else:
            #tag is None, which means remove the collection
            if input(
                    'Are you sure? This will remove the {} collections. (Y/N)'.
                    format(collections))[0].upper() == 'Y':
                flag_remove = True

    if flag_remove:
        for collectioni in collections:
            if collectioni in VOL_COLLECTION:
                collectioni_file = collectioni + '_fs.files'
                collectioni_chunk = collectioni + '_fs.chunks'
                #It has files and chunks
                if tag:
                    static_items = list(vasp_db.db['tasks'].find(
                        {'metadata.tag': tag}))
                    for itemi in static_items:
                        task_id = itemi['task_id']
                        files_id = list(vasp_db.db[collectioni_file].find(
                            {'metadata.task_id': task_id}))
                        if files_id:
                            vasp_db.db[collectioni_chunk].remove(
                                {'files_id': files_id[0]['_id']})
                            vasp_db.db[collectioni_file].remove(
                                {'metadata.task_id': task_id})
                            print(
                                'The volume data with metadata.tag={} in {} collection is removed'
                                .format(tag, collectioni))
                else:
                    vasp_db.db[collectioni_chunk].remove()
                    vasp_db.db[collectioni_file].remove()
                    print('The data in {} collection is removed'.format(
                        collectioni))
            else:
                if tag:
                    vasp_db.db[collectioni].remove({'metadata.tag': tag})
                    print(
                        'The data with metadata.tag={} in {} collection is removed'
                        .format(tag, collectioni))
                else:
                    if input(
                            'Are you really sure to remove all the {} collections. (Yes/N)'
                            .format(collections))[0].upper() == 'Yes':
                        vasp_db.db[collectioni].remove()
                        print('The data in {} collection is removed'.format(
                            collectioni))
Esempio n. 23
0
    def run_task(self, fw_spec):

        get_rdf = self.get('get_rdf') or True
        get_diffusion = self.get('get_diffusion') or True
        get_viscosity = self.get('get_viscosity') or True
        get_vdos = self.get('get_vdos') or True
        get_run_data = self.get('get_run_data') or True
        time_step = self.get('time_step') or 2
        checkpoint_dirs = fw_spec.get('checkpoint_dirs', False)

        calc_dir = get_calc_loc(True, fw_spec["calc_locs"])["path"]
        calc_loc = os.path.join(calc_dir, 'XDATCAR.gz')

        ionic_step_skip = self.get('ionic_step_skip') or 1
        ionic_step_offset = self.get('ionic_step_offset') or 0

        analysis_spec = self.get('analysis_spec') or {}

        logger.info("Reading in ionic_steps...")

        decompress_file("ionic_steps.json.gz")
        ionic_steps = loadfn("ionic_steps.json")
        structures = [s.structure for s in ionic_steps]
        compress_file("ionic_steps.json")

        db_dict = {}
        db_dict.update({'density': float(structures[0].density)})
        db_dict.update(structures[0].composition.to_data_dict)

        if get_rdf:
            logger.info("LOGGER: Calculating radial distribution functions...")
            rdf = RadialDistributionFunction(structures=structures)
            rdf_dat = rdf.get_radial_distribution_functions(nproc=4)
            db_dict.update({'rdf': rdf.get_rdf_db_dict()})
            del rdf
            del rdf_dat

        if get_vdos:
            logger.info("LOGGER: Calculating vibrational density of states...")
            vdos = VDOS(structures)
            vdos_dat = vdos.calc_vdos_spectrum(time_step=time_step *
                                               ionic_step_skip)
            vdos_diff = vdos.calc_diffusion_coefficient(time_step=time_step *
                                                        ionic_step_skip)
            db_dict.update({'vdos': vdos_dat})
            del vdos
            del vdos_dat

        if get_diffusion:
            logger.info("LOGGER: Calculating the diffusion coefficients...")
            diffusion = Diffusion(structures,
                                  t_step=time_step,
                                  l_lim=50,
                                  skip_first=250,
                                  block_l=1000,
                                  ci=0.95)
            D = {'msd': {}, 'vdos': {}}
            for s in structures[0].types_of_specie:
                D['msd'][s.symbol] = diffusion.getD(s.symbol)
            if vdos_diff:
                D['vdos'] = vdos_diff
            db_dict.update({'diffusion': D})
            del D

        if get_viscosity:
            logger.info("LOGGER: Calculating the viscosity...")
            viscosities = []
            if checkpoint_dirs:
                for dir in checkpoint_dirs:
                    visc = Viscosity(dir).calc_viscosity()
                    viscosities.append(visc['viscosity'])
            viscosity_dat = {
                'viscosity': np.mean(viscosities),
                'StdDev': np.std(viscosities)
            }
            db_dict.update({'viscosity': viscosity_dat})
            del viscosity_dat

        if get_run_data:
            if checkpoint_dirs:
                logger.info("LOGGER: Assimilating run stats...")
                data = MD_Data()
                for directory in checkpoint_dirs:
                    data.parse_md_data(directory)
                md_stats = data.get_md_stats()
            else:
                logger.info("LOGGER: Getting run stats...")
                data = MD_Data()
                data.parse_md_data(calc_dir)
                md_stats = data.get_md_stats()
            db_dict.update({'md_data': md_stats})

        if analysis_spec:
            logger.info("LOGGER: Adding user-specified data...")
            db_dict.update(analysis_spec)

        logger.info("LOGGER: Pushing data to database collection...")
        db_file = env_chk(">>db_file<<", fw_spec)
        db = VaspCalcDb.from_db_file(db_file, admin=True)
        db.collection = db.db["md_data"]
        db.collection.insert_one(db_dict)

        return FWAction()
Esempio n. 24
0
    def run_task(self, fw_spec):
        ref_struct = self['structure']
        d = {
            "analysis": {},
            "initial_structure": self['structure'].as_dict()
        }

        # Get optimized structure
        calc_locs_opt = [cl for cl in fw_spec.get('calc_locs', []) if 'optimiz' in cl['name']]
        if calc_locs_opt:
            optimize_loc = calc_locs_opt[-1]['path']
            logger.info("Parsing initial optimization directory: {}".format(optimize_loc))
            drone = VaspDrone()
            optimize_doc = drone.assimilate(optimize_loc)
            opt_struct = Structure.from_dict(optimize_doc["calcs_reversed"][0]["output"]["structure"])
            d.update({"optimized_structure": opt_struct.as_dict()})
            ref_struct = opt_struct
            eq_stress = -0.1*Stress(optimize_doc["calcs_reversed"][0]["output"]["ionic_steps"][-1]["stress"])
        else:
            eq_stress = None

        if self.get("fw_spec_field"):
            d.update({self.get("fw_spec_field"): fw_spec.get(self.get("fw_spec_field"))})

        # Get the stresses, strains, deformations from deformation tasks
        defo_dicts = fw_spec["deformation_tasks"].values()
        stresses, strains, deformations = [], [], []
        for defo_dict in defo_dicts:
            stresses.append(Stress(defo_dict["stress"]))
            strains.append(Strain(defo_dict["strain"]))
            deformations.append(Deformation(defo_dict["deformation_matrix"]))
            # Add derived stresses and strains if symmops is present
            for symmop in defo_dict.get("symmops", []):
                stresses.append(Stress(defo_dict["stress"]).transform(symmop))
                strains.append(Strain(defo_dict["strain"]).transform(symmop))
                deformations.append(Deformation(defo_dict["deformation_matrix"]).transform(symmop))

        stresses = [-0.1*s for s in stresses]
        pk_stresses = [stress.piola_kirchoff_2(deformation)
                       for stress, deformation in zip(stresses, deformations)]

        d['fitting_data'] = {'cauchy_stresses': stresses,
                             'eq_stress': eq_stress,
                             'strains': strains,
                             'pk_stresses': pk_stresses,
                             'deformations': deformations
                             }

        logger.info("Analyzing stress/strain data")
        # TODO: @montoyjh: what if it's a cubic system? don't need 6. -computron
        # TODO: Can add population method but want to think about how it should
        #           be done. -montoyjh
        order = self.get('order', 2)
        if order > 2:
            method = 'finite_difference'
        else:
            method = self.get('fitting_method', 'finite_difference')

        if method == 'finite_difference':
            result = ElasticTensorExpansion.from_diff_fit(
                    strains, pk_stresses, eq_stress=eq_stress, order=order)
            if order == 2:
                result = ElasticTensor(result[0])
        elif method == 'pseudoinverse':
            result = ElasticTensor.from_pseudoinverse(strains, pk_stresses)
        elif method == 'independent':
            result = ElasticTensor.from_independent_strains(strains, pk_stresses, eq_stress=eq_stress)
        else:
            raise ValueError("Unsupported method, method must be finite_difference, "
                             "pseudoinverse, or independent")

        ieee = result.convert_to_ieee(ref_struct)
        d.update({
            "elastic_tensor": {
                "raw": result.voigt,
                "ieee_format": ieee.voigt
            }
        })
        if order == 2:
            d.update({"derived_properties": ieee.get_structure_property_dict(ref_struct)})
        else:
            soec = ElasticTensor(ieee[0])
            d.update({"derived_properties": soec.get_structure_property_dict(ref_struct)})

        d["formula_pretty"] = ref_struct.composition.reduced_formula
        d["fitting_method"] = method
        d["order"] = order

        d = jsanitize(d)

        # Save analysis results in json or db
        db_file = env_chk(self.get('db_file'), fw_spec)
        if not db_file:
            with open("elasticity.json", "w") as f:
                f.write(json.dumps(d, default=DATETIME_HANDLER))
        else:
            db = VaspCalcDb.from_db_file(db_file, admin=True)
            db.collection = db.db["elasticity"]
            db.collection.insert_one(d)
            logger.info("Elastic analysis complete.")
        
        return FWAction()
Esempio n. 25
0
    def run_task(self, fw_spec):

        vasp_calc_dir = self.get("calc_dir", None)
        vasp_calc_loc = (
            get_calc_loc(self["calc_loc"], fw_spec["calc_locs"])
            if self.get("calc_loc")
            else {}
        )

        # get the directory that contains the Lobster dir to parse
        current_dir = os.getcwd()
        # parse the Lobster directory
        logger.info("PARSING DIRECTORY: {}".format(current_dir))
        task_doc = {}
        struct = Structure.from_file(self._find_gz_file("POSCAR"))
        Lobsterout_here = Lobsterout(self._find_gz_file("lobsterout"))
        task_doc["output"] = Lobsterout_here.get_doc()
        Lobsterin_here = Lobsterin.from_file(self._find_gz_file("lobsterin"))
        task_doc["input"] = Lobsterin_here
        try:
            Lobsterin_orig = Lobsterin.from_file(self._find_gz_file("lobsterin.orig"))
            task_doc["orig_input"] = Lobsterin_orig
        except ValueError:
            pass
        # save custodian details
        if os.path.exists("custodian.json"):
            task_doc["custodian"] = loadfn("custodian.json")

        additional_fields = self.get("additional_fields", {})
        if additional_fields:
            task_doc.update(additional_fields)

        task_doc.update(get_meta_from_structure(struct))
        if vasp_calc_dir != None:
            task_doc["vasp_dir_name"] = vasp_calc_dir
        else:
            task_doc["vasp_dir_name"] = vasp_calc_loc["path"]
        task_doc["dir_name"] = current_dir

        # Check for additional keys to set based on the fw_spec
        if self.get("fw_spec_field"):
            task_doc.update(fw_spec[self.get("fw_spec_field")])

        task_doc["state"] = "successful"

        task_doc = jsanitize(task_doc)
        # get the database connection
        db_file = env_chk(self.get("db_file"), fw_spec)

        # db insertion or taskdoc dump
        if not db_file:
            with open("task_lobster.json", "w") as f:
                f.write(json.dumps(task_doc, default=DATETIME_HANDLER))
        else:
            db = VaspCalcDb.from_db_file(db_file, admin=True)
            db.collection = db.db["lobster"]
            additional_outputs = self.get("additional_outputs", None)
            if additional_outputs:
                for filename in additional_outputs:

                    fs_id = None
                    if os.path.isfile(filename):
                        fs_id = put_file_in_gridfs(
                            filename, db, collection_name="lobster_files", compress=True
                        )
                    elif os.path.isfile(filename + ".gz"):
                        fs_id = put_file_in_gridfs(
                            filename + ".gz",
                            db,
                            collection_name="lobster_files",
                            compress=False,
                            compression_type="zlib",
                        )

                    if fs_id:
                        key_name = filename.split(".")[0].lower() + "_id"
                        task_doc[key_name] = fs_id

            db.insert(task_doc)
        return FWAction()
Esempio n. 26
0
from atomate.vasp.database import VaspCalcDb

x = VaspCalcDb.from_db_file("db.json")
x.reset()

print("SUCCESS")
Esempio n. 27
0
def ext_thelec(args, plotfiles=None, vasp_db=None):
    global no_MongoDB
    print ("Postprocess for thermodynamic properties, Seebeck, Lorenz number etc. Yi Wang\n")
    """
    Postprocess for thermodynamic properties, Seebeck, Lorenz number etc

    Parameters
        STR_FOLDER = args.STRUCTURE_FOLDER
            folder/file containing structures
        MATCH_PATTERN = args.MATCH_PATTERN
            Match patterns for structure file, e.g. *POSCAR
        RECURSIVE = args.RECURSIVE
            recursive or not
        WORKFLOW = args.WORKFLOW
            workflow, current only get_wf_gibbs
        LAUNCH = args.LAUNCH
            Launch to lpad or not
        MAX_JOB = args.MAX_JOB
            Max job to submit
        SETTINGS = args.SETTINGS
            Settings file
        WRITE_OUT_WF = args.WRITE_OUT_WF
            Write out wf file or not
    """
    t0 = args.t0
    t1 = args.t1
    td = args.td
    xdn = args.xdn
    xup = args.xup
    ndosmx = args.ndosmx
    natom = args.natom
    gaussian = args.gaussian
    dope = args.dope
    doscar = args.doscar
    outf = args.outf
    qhamode = args.qhamode
    eqmode = args.eqmode
    elmode = args.elmode
    metatag = args.metatag
    everyT = args.everyT
    noel = args.noel
    smooth = args.smooth
    expt = args.expt
    xlim = args.xlim
    if abs(dope)<5.e-9:
        ndosmx = max(100001, int(ndosmx))
        gaussian = max(10000., float(gaussian))

    formula = None
    if args.local != "":
        print("\nRun using local data\n")

        readme = {}
        record_cmd(readme)
        proc = thelecMDB(t0, t1, td, xdn, xup, dope, ndosmx, gaussian, natom, outf,
            noel=noel, qhamode=qhamode, eqmode=eqmode, elmode=elmode,
            smooth=smooth, debug=args.debug, phasename=args.local,
            pyphon=True, renew=args.renew, fitF=args.fitF, args=args)
        volumes, energies, thermofile, comments = proc.run_console()

        if comments!=None: readme.update(comments)
        else: return
        if "ERROR" in readme.keys():
            record_cmd_print(thermofile, readme, dir=args.phasename)
            return

        print("\nFull thermodynamic properties have outputed into:", thermofile)
        #print(args.plot, "eeeeeeeee", volumes, energies, thermofile, comments)
        if args.plot==None: print("\nSupply '-plot phasename' for plot\n")
        else:
            from dfttk.analysis.ywplot import plotAPI
            #print("xxxxxxx",proc.get_formula())
            if plotAPI(readme, thermofile, volumes, energies, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
                formula = proc.get_formula(), debug=args.debug,
                plotlabel=args.plot, local=args.local):
                #print ("xxxxxxx",proc.get_formula())
                vtof = proc.get_free_energy_for_plot(readme)
                if vtof is not None:
                    plotAPI(readme, thermofile, volumes, energies, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
                    formula = proc.get_formula(), vtof=vtof, plotlabel=args.plot)
            """
            """
        #print("xxxxxxxxxxxx",readme)
        record_cmd_print(thermofile, readme)
    elif no_MongoDB:
            print("\n*********WARNING: CANNOT get MongoDB service, so I will proceed using local data")
            print("*********WARNING: CANNOT get MongoDB service, so I will proceed using local data")
            print("*********WARNING: CANNOT get MongoDB service, so I will proceed using local data\n")
    elif not args.plotonly:
        #if True:
        try:
            if vasp_db is None:
                db_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"]
                vasp_db = VaspCalcDb.from_db_file(db_file, admin=False)
            static_calculations = vasp_db.collection.\
                find({'$and':[ {'metadata.tag': metatag}, {'adopted': True} ]})
            structure = Structure.from_dict(static_calculations[0]['output']['structure'])
            formula = reduced_formula(structure.composition.alphabetical_formula)
        except:
            no_MongoDB = True
            print("\n*********WARNING: CANNOT get MongoDB service, so I will proceed using local data")
            print("*********WARNING: CANNOT get MongoDB service, so I will proceed using local data")
            print("*********WARNING: CANNOT get MongoDB service, so I will proceed using local data\n")
        """
        """

    #call API
    if args.plotonly and plotfiles!=None:
        metatag, thermofile, volumes, energies, dir, formula = plotfiles
        sys.stdout.write('Processing {}, dir: {}, formula: {}\n'.format(metatag, dir, formula))

        #print(thermofile, volumes, energies, formula)
        #print(thermofile, dir, formula)
        readme={}
        from dfttk.analysis.ywplot import plotAPI
        plotAPI(readme, thermofile, None, energies, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
            formula = formula, vtof=None, plotlabel=args.plot)
    elif vasp_db==None and plotfiles!=None:
        metatag, thermofile, volumes, energies, dir, formula = plotfiles
        sys.stdout.write('Processing {}, dir: {}, formula: {}\n'.format(metatag, dir, formula))
        #print("xxxxxxxxxx", plotfiles)
        if expt!=None:
            _t1 = get_melting_temperature(expt, formula)
            if _t1!=None: t1 = _t1

        readme = {}
        record_cmd(readme)
        proc = thelecMDB(t0, t1, td, xdn, xup, dope, ndosmx, gaussian, natom, outf, vasp_db=vasp_db,
            noel=noel, metatag=metatag, qhamode=qhamode, eqmode=eqmode, elmode=elmode, everyT=everyT,
            smooth=smooth, debug=args.debug,
            phasename=dir, pyphon=args.pyphon, renew=args.renew, fitF=args.fitF, args=args)
        volumes, energies, thermofile, comments = proc.run_console()
        #print ("xxxxxxx", comments)
        if comments!=None: readme.update(comments)
        else: return
        if "ERROR" in readme.keys():
            #record_cmd_print(thermofile, readme, dir=args.phasename)
            return

        print("\nFull thermodynamic properties have outputed into:", thermofile)
        #print(args.plot, "eeeeeeeee", volumes, energies, thermofile, comments)
        if args.plot==None: print("\nSupply '-plot phasename' for plot\n")
        else:
            from dfttk.analysis.ywplot import plotAPI
            if plotAPI(readme, thermofile, volumes, energies, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
                formula = proc.get_formula(), debug=args.debug,
                plotlabel=args.plot):
                vtof = proc.get_free_energy_for_plot(readme)
                if vtof is not None:
                    plotAPI(readme, thermofile, volumes, energies, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
                    formula = proc.get_formula(), vtof=vtof, plotlabel=args.plot)
            """
            """
        record_cmd_print(thermofile, readme)

    elif metatag != None:
        if expt!=None:
            _t1 = get_melting_temperature(expt, formula)
            if _t1!=None: t1 = _t1
        readme = {}
        record_cmd(readme)
        proc = thelecMDB(t0, t1, td, xdn, xup, dope, ndosmx, gaussian, natom, outf, vasp_db=vasp_db,
            noel=noel, metatag=metatag, qhamode=qhamode, eqmode=eqmode, elmode=elmode, everyT=everyT,
            smooth=smooth, debug=args.debug,
            phasename=args.phasename, pyphon=args.pyphon, renew=args.renew, fitF=args.fitF, args=args)
        volumes, energies, thermofile, comments = proc.run_console()

        if comments!=None: readme.update(comments)
        else: return
        if "ERROR" in readme.keys():
            record_cmd_print(thermofile, readme, dir=args.phasename)
            return

        print("\nFull thermodynamic properties have outputed into:", thermofile)
        #print(args.plot, "eeeeeeeee", volumes, energies, thermofile, comments)
        if args.plot==None: print("\nSupply '-plot phasename' for plot\n")
        else:
            from dfttk.analysis.ywplot import plotAPI
            if plotAPI(readme, thermofile, volumes, energies, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
                formula = proc.get_formula(), debug=args.debug,
                plotlabel=args.plot):
                vtof = proc.get_free_energy_for_plot(readme)
                if vtof is not None:
                    plotAPI(readme, thermofile, volumes, energies, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
                    formula = proc.get_formula(), vtof=vtof, plotlabel=args.plot)
            """
            """
        record_cmd_print(thermofile, readme)
    elif args.vdos is not None:
        readme = {}
        record_cmd(readme)
        proc = thelecMDB(t0, t1, td, xdn, xup, dope, ndosmx, gaussian, natom, outf, renew=True, args=args)
        thermofile, comments, natoms = proc.run_single()
        if thermofile is None: return
        readme.update(comments)
        #record_cmd(thermofile, readme)

        print("\nFull thermodynamic properties have outputed into:", thermofile)
        if args.plot!=None:
            from dfttk.analysis.ywplot import plotAPI
            if plotAPI(readme, thermofile, None, None, expt=expt, xlim=xlim, _fitCp=args.SGTEfitCp,
                formula = proc.get_formula(), debug=args.debug,
                poscar=args.poscar,vdos=args.vdos, doscar=args.doscar, natoms=natoms, plotlabel=args.plot):
                record_cmd_print(thermofile, readme)
    elif args.local == "":
        pythelec.thelecAPI(t0, t1, td, xdn, xup, dope, ndosmx, gaussian, natom, outf, doscar)
Esempio n. 28
0
    def run_task(self, fw_spec):

        gibbs_dict = {}

        tag = self["tag"]
        t_step = self.get("t_step", 10)
        t_min = self.get("t_min", 0)
        t_max = self.get("t_max", 1000)
        mesh = self.get("mesh", [20, 20, 20])
        eos = self.get("eos", "vinet")
        qha_type = self.get("qha_type", "debye_model")
        pressure = self.get("pressure", 0.0)
        poisson = self.get("poisson", 0.25)
        anharmonic_contribution = self.get("anharmonic_contribution", False)
        gibbs_dict["metadata"] = self.get("metadata", {})

        db_file = env_chk(self.get("db_file"), fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        # get the optimized structure
        d = mmdb.collection.find_one({"task_label": "{} structure optimization".format(tag)},
                                     {"calcs_reversed": 1})
        structure = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure'])
        gibbs_dict["structure"] = structure.as_dict()
        gibbs_dict["formula_pretty"] = structure.composition.reduced_formula

        # get the data(energy, volume, force constant) from the deformation runs
        docs = mmdb.collection.find({"task_label": {"$regex": "{} gibbs*".format(tag)},
                                     "formula_pretty": structure.composition.reduced_formula},
                                    {"calcs_reversed": 1})
        energies = []
        volumes = []
        force_constants = []
        for d in docs:
            s = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure'])
            energies.append(d["calcs_reversed"][-1]["output"]['energy'])
            if qha_type not in ["debye_model"]:
                force_constants.append(d["calcs_reversed"][-1]["output"]['force_constants'])
            volumes.append(s.volume)
        gibbs_dict["energies"] = energies
        gibbs_dict["volumes"] = volumes
        if qha_type not in ["debye_model"]:
            gibbs_dict["force_constants"] = force_constants

        try:
            # use quasi-harmonic debye approximation
            if qha_type in ["debye_model"]:

                from pymatgen.analysis.quasiharmonic import QuasiharmonicDebyeApprox

                qhda = QuasiharmonicDebyeApprox(energies, volumes, structure, t_min, t_step, t_max,
                                                eos, pressure=pressure, poisson=poisson,
                                                anharmonic_contribution=anharmonic_contribution)
                gibbs_dict.update(qhda.get_summary_dict())
                gibbs_dict["anharmonic_contribution"] = anharmonic_contribution
                gibbs_dict["success"] = True

            # use the phonopy interface
            else:

                from atomate.vasp.analysis.phonopy import get_phonopy_gibbs

                G, T = get_phonopy_gibbs(energies, volumes, force_constants, structure, t_min,
                                         t_step, t_max, mesh, eos, pressure)
                gibbs_dict["gibbs_free_energy"] = G
                gibbs_dict["temperatures"] = T
                gibbs_dict["success"] = True

        # quasi-harmonic analysis failed, set the flag to false
        except:
            import traceback

            logger.warn("Quasi-harmonic analysis failed!")
            gibbs_dict["success"] = False
            gibbs_dict["traceback"] = traceback.format_exc()
            gibbs_dict['metadata'].update({"task_label_tag": tag})
            gibbs_dict["created_at"] = datetime.utcnow()

        gibbs_dict = jsanitize(gibbs_dict)

        # TODO: @matk86: add a list of task_ids that were used to construct the analysis to DB?
        # -computron
        if not db_file:
            dump_file = "gibbs.json"
            logger.info("Dumping the analysis summary to {}".format(dump_file))
            with open(dump_file, "w") as f:
                f.write(json.dumps(gibbs_dict, default=DATETIME_HANDLER))
        else:
            coll = mmdb.db["gibbs_tasks"]
            coll.insert_one(gibbs_dict)

        logger.info("Gibbs free energy calculation complete.")

        if not gibbs_dict["success"]:
            return FWAction(defuse_children=True)
import re
import pprint
import copy
from pymatgen import Structure, MPRester
from pymatgen.analysis.phase_diagram import PhaseDiagram
from pymatgen.io.vasp import Vasprun
from pymatgen.io.vasp.sets import get_vasprun_outcar
from pymatgen.core.structure import Structure
from pymatgen.core.composition import Composition
from pymatgen.entries.computed_entries import ComputedEntry
from pymatgen.entries.compatibility import MaterialsProjectCompatibility
from atomate.vasp.database import VaspCalcDb
import pandas as pd

PATH_TO_MY_DB_JSON = '/work/04391/tg836903/stampede2/atomate/config/db.json'
atomate_db = VaspCalcDb.from_db_file(
    PATH_TO_MY_DB_JSON)  #database of ALL calcs
output_dict = {}

comp_list = [
    # 'LaPbNO2','SbPbNO2', 'AsPbNO2', 'TlSnNO2', 'BaBiNO2', #'LaSeNO2'
    # ,'CeGeN2O', 'ZrSiN2O', 'LaSbN2O', 'TaGaNO2', 'CeAsNO2', 'CeGaNO2',
    #    'CeGeNO2', 'BiAsN2O', 'CeSnN2O', 'TiGeNO2', 'LaSnNO2', 'LaBiN2O', 'BaBiNO2', 'SrBiNO2',
    #    'CeBiN2O', 'SrSbNO2', 'CaSbNO2', 'CaBiNO2', 'CeSiN2O', 'ZrGeN2O', 'ZrAsNO2', 'LaGeNO2',
    #    'CeSbNO2', 'CeInNO2', 'GeBiNO2', 'NdSnNO2', 'ScGeNO2', 'LaAsN2O', 'CeSbN2O', 'YSbN2O',
    #    'YSnNO2', 'BaTeN2O', 'SrTeN2O', 'LuSnNO2', 'CaTeN2O', 'HfSiN2O', 'NbSiN2O', 'TiSiN2O',
    #    'VSiN2O', 'HfGeN2O', 'SiWN2O', 'SiMoN2O', 'ReSiN2O', 'NbGeN2O', 'CeSnNO2', 'NdGeNO2',
    #    'GaBiN2O', 'ZrGaNO2', 'HfAsNO2', 'LuGeNO2', 'NdBiN2O', 'SnBiNO2', 'LuSbN2O', 'NbAsN2O',
    #    'NbAsNO2', 'NdSbN2O', 'YGeNO2', 'CeAsN2O', 'YAsN2O', 'LuAsN2O', 'LuSiNO2', 'SiBiNO2',
    #    'NdSiNO2', 'VGeN2O', 'CeSiNO2', 'LaSiNO2', 'NbSiNO2', 'BaSbNO2', 'SiMoNO2', 'CaAsNO2',
    #    'SrAsNO2', 'MgAsNO2', 'YBiN2O', 'MgTeN2O', 'MgSbNO2', 'NdZrNO2', 'CaNbNO2', 'LaZrNO2',
    #    'LaVNO2', 'NdVNO2', 'SrNbNO2', 'BaNbNO2', 'LaNbN2O', 'CaMoNO2', 'SrMoNO2', 'CeTaN2O',
Esempio n. 30
0
    def run_task(self, fw_spec):

        wfid = list(filter(lambda x: 'wfid' in x, fw_spec['tags'])).pop()
        db_file = env_chk(self.get("db_file"), fw_spec)
        vaspdb = VaspCalcDb.from_db_file(db_file, admin=True)

        # ferroelectric workflow groups calculations by generated wfid tag
        polarization_tasks = vaspdb.collection.find({
            "tags": wfid,
            "task_label": {
                "$regex": ".*polarization"
            }
        })

        tasks = []
        outcars = []
        structure_dicts = []
        sort_weight = []
        energies_per_atom = []
        energies = []
        zval_dicts = []

        for p in polarization_tasks:
            # Grab data from each polarization task
            energies_per_atom.append(
                p['calcs_reversed'][0]['output']['energy_per_atom'])
            energies.append(p['calcs_reversed'][0]['output']['energy'])
            tasks.append(p['task_label'])
            outcars.append(p['calcs_reversed'][0]['output']['outcar'])
            structure_dicts.append(
                p['calcs_reversed'][0]['input']['structure'])
            zval_dicts.append(
                p['calcs_reversed'][0]['output']['outcar']['zval_dict'])

            # Add weight for sorting
            # Want polarization calculations in order of nonpolar to polar for Polarization object

            # This number needs to be bigger than the number of calculations
            max_sort_weight = 1000000

            if 'nonpolar_polarization' in p['task_label']:
                sort_weight.append(0)
            elif "polar_polarization" in p['task_label']:
                sort_weight.append(max_sort_weight)
            elif "interpolation_" in p['task_label']:
                num = 0
                part = re.findall(r'interpolation_[0-9]+_polarization',
                                  p['task_label'])
                if part != []:
                    part2 = re.findall(r'[0-9]+', part.pop())
                    if part2 != []:
                        num = part2.pop()
                sort_weight.append(max_sort_weight - int(num))

        # Sort polarization tasks
        # nonpolar -> interpolation_n -> interpolation_n-1 -> ...  -> interpolation_1 -> polar
        data = zip(tasks, structure_dicts, outcars, energies_per_atom,
                   energies, sort_weight)
        data = sorted(data, key=lambda x: x[-1])

        # Get the tasks, structures, etc in sorted order from the zipped data.
        tasks, structure_dicts, outcars, energies_per_atom, energies, sort_weight = zip(
            *data)

        structures = [
            Structure.from_dict(structure) for structure in structure_dicts
        ]

        # If LCALCPOL = True then Outcar will parse and store the pseudopotential zvals.
        zval_dict = zval_dicts.pop()

        # Assumes that we want to calculate the ionic contribution to the dipole moment.
        # VASP's ionic contribution is sometimes strange.
        # See pymatgen.analysis.ferroelectricity.polarization.Polarization for details.
        p_elecs = [outcar['p_elec'] for outcar in outcars]
        p_ions = [
            get_total_ionic_dipole(structure, zval_dict)
            for structure in structures
        ]

        polarization = Polarization(p_elecs, p_ions, structures)

        p_change = polarization.get_polarization_change().A1.tolist()
        p_norm = polarization.get_polarization_change_norm()
        polarization_max_spline_jumps = polarization.max_spline_jumps()
        same_branch = polarization.get_same_branch_polarization_data(
            convert_to_muC_per_cm2=True)
        raw_elecs, raw_ions = polarization.get_pelecs_and_pions()
        quanta = polarization.get_lattice_quanta(convert_to_muC_per_cm2=True)

        energy_trend = EnergyTrend(energies_per_atom)
        energy_max_spline_jumps = energy_trend.max_spline_jump()

        polarization_dict = {}

        def split_abc(var, var_name):
            d = {}
            for i, j in enumerate('abc'):
                d.update({var_name + "_{}".format(j): var[:, i].A1.tolist()})
            return d

        # Add some sort of id for the structures? Like cid but more general?
        # polarization_dict.update({'cid': cid})

        # General information
        polarization_dict.update(
            {'pretty_formula': structures[0].composition.reduced_formula})
        polarization_dict.update({'wfid': wfid})
        polarization_dict.update({'task_label_order': tasks})

        # Polarization information
        polarization_dict.update({'polarization_change': p_change})
        polarization_dict.update({'polarization_change_norm': p_norm})
        polarization_dict.update(
            {'polarization_max_spline_jumps': polarization_max_spline_jumps})
        polarization_dict.update(
            split_abc(same_branch, "same_branch_polarization"))
        polarization_dict.update(
            split_abc(raw_elecs, "raw_electron_polarization"))
        polarization_dict.update(
            split_abc(raw_ions, "raw_electron_polarization"))
        polarization_dict.update(split_abc(quanta, "polarization_quanta"))
        polarization_dict.update({"zval_dict": zval_dict})

        # Energy information
        polarization_dict.update(
            {'energy_per_atom_max_spline_jumps': energy_max_spline_jumps})
        polarization_dict.update({"energies": energies})
        polarization_dict.update({"energies_per_atom": energies_per_atom})
        polarization_dict.update({'outcars': outcars})
        polarization_dict.update({"structures": structure_dicts})

        # Write all the info to db.
        coll = vaspdb.db["polarization_tasks"]
        coll.insert_one(polarization_dict)
Esempio n. 31
0
    def __init__(self, args):
        self.plotonly = args.plotonly
        if args.qhamode is not None:
            self.qhamode = args.qhamode
        else:
            self.qhamode = 'phonon'
        if args.qhamode == 'debye': self.qhamode = 'qha'
        from fireworks.fw_config import config_to_dict
        from monty.serialization import loadfn
        db_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"]
        if not self.plotonly:
            try:
                self.vasp_db = VaspCalcDb.from_db_file(db_file, admin=True)
                self.items = (self.vasp_db).db[self.qhamode].find({})
                if self.qhamode == 'phonon':
                    self.items = list((self.vasp_db).db['phonon'].find({"S_vib": { "$exists": True } },\
                        {'metadata':1, 'unitcell':1, 'volume':1, 'supercell_matrix':1}))
                else:
                    self.items = list((self.vasp_db).db['qha'].find({"debye": { "$exists": True } },\
                        {'metadata':1, 'structure':1}))
            except:
                self.vasp_db = None
                print(
                    "\n*********WARNING: CANNOT get MongoDB service, so I will proceed using local data"
                )
                print(
                    "*********WARNING: CANNOT get MongoDB service, so I will proceed using local data"
                )
                print(
                    "*********WARNING: CANNOT get MongoDB service, so I will proceed using local data\n"
                )

        #items = vasp_db.db['phonon'].find(properties=['metadata.tag','F_vib', 'CV_vib', 'S_vib'])
        #items = vasp_db.db['phonon'].find({F_vib: {$gt: 0}})
        #items = vasp_db.db['phonon'].find({'metadata.tag': "djdjd"})
        #items = vasp_db.db['phonon'].find({})
        self.check = args.check
        self.remove = args.remove

        self.tags = []
        self._Yphon = []
        self.within = []
        self.containall = []
        self.containany = []
        self.excludeall = []
        self.excludeany = []
        self.nV = args.nV
        self.metatag = args.metatag
        self.get = args.get
        self.supercellN = args.supercellN
        self.t0 = args.t0
        self.t1 = args.t1
        self.td = args.td
        self.jobpath = args.jobpath
        self.findbandgap = args.findbandgap
        if args.within is not None:
            self.within, tmp = formula2composition(args.within)
        if args.containall is not None:
            self.containall, tmp = formula2composition(args.containall)
        if args.containany is not None:
            self.containany, tmp = formula2composition(args.containany)
        if args.excludeall is not None:
            self.excludeall, tmp = formula2composition(args.excludeall)
Esempio n. 32
0
    def run_task(self):
        tag = self["tag"]
        admin = self.get('admin', False)
        _db_file = self.get('db_file', db_file)

        vasp_db = VaspCalcDb.from_db_file(db_file=_db_file, admin=admin)

        # get the energies, volumes and DOS objects by searching for the tag
        static_calculations = vasp_db.collection.find(
            {'$and': [{
                'metadata.tag': tag
            }, {
                'adopted': True
            }]})

        energies = []
        volumes = []
        dos_objs = []  # pymatgen.electronic_structure.dos.Dos objects
        structure = None  # single Structure for QHA calculation
        for calc in static_calculations:
            energies.append(calc['output']['energy'])
            volumes.append(calc['output']['structure']['lattice']['volume'])
            dos_objs.append(vasp_db.get_dos(calc['task_id']))
            # get a Structure. We only need one for the masses and number of atoms in the unit cell.
            if structure is None:
                structure = Structure.from_dict(calc['output']['structure'])

        # sort everything in volume order
        # note that we are doing volume last because it is the thing we are sorting by!

        energies = sort_x_by_y(energies, volumes)
        dos_objs = sort_x_by_y(dos_objs, volumes)
        volumes = sorted(volumes)

        qha_result = {}
        qha_result['structure'] = structure.as_dict()
        qha_result['formula_pretty'] = structure.composition.reduced_formula
        qha_result['elements'] = sorted(
            [el.name for el in structure.composition.elements])
        qha_result['metadata'] = self.get('metadata', {'tag': tag})
        #qha_result['has_phonon'] = self['phonon']

        poisson = self.get('poisson', 0.363615)
        bp2gru = self.get('bp2gru', 1)

        # phonon properties
        # check if phonon calculations existed
        #always perform phonon calculations when when enough phonon calculations found
        num_phonons = len(
            list(vasp_db.db['phonon'].find(
                {'$and': [{
                    'metadata.tag': tag
                }, {
                    'adopted': True
                }]})))
        qha_result['has_phonon'] = num_phonons >= 5
        #if self['phonon']:
        if qha_result['has_phonon']:
            # get the vibrational properties from the FW spec
            phonon_calculations = list(vasp_db.db['phonon'].find(
                {'$and': [{
                    'metadata.tag': tag
                }, {
                    'adopted': True
                }]}))
            vol_vol = []
            vol_f_vib = []
            vol_s_vib = []
            vol_c_vib = []
            for calc in phonon_calculations:
                if calc['volume'] in vol_vol: continue
                vol_vol.append(calc['volume'])
                vol_f_vib.append(calc['F_vib'])
                vol_s_vib.append(calc['S_vib'])
                vol_c_vib.append(calc['CV_vib'])
            # sort them order of the unit cell volumes
            vol_f_vib = sort_x_by_y(vol_f_vib, vol_vol)
            vol_s_vib = sort_x_by_y(vol_s_vib, vol_vol)
            vol_c_vib = sort_x_by_y(vol_c_vib, vol_vol)
            f_vib = np.vstack(vol_f_vib)

            # by Yi Wang, after a long day debug, finally I fixex the bug below
            # i.e, sometimes, the number of phonon volumes is less than that of static!
            _volumes = []
            _energies = []
            _dos_objs = []
            for iv, vol in enumerate(volumes):
                if vol not in vol_vol: continue
                _volumes.append(vol)
                _energies.append(energies[iv])
                _dos_objs.append(dos_objs[iv])
            volumes = _volumes
            energies = _energies
            dos_objs = _dos_objs

            qha = Quasiharmonic(energies,
                                volumes,
                                structure,
                                dos_objects=dos_objs,
                                F_vib=f_vib,
                                t_min=self['t_min'],
                                t_max=self['t_max'],
                                t_step=self['t_step'],
                                poisson=poisson,
                                bp2gru=bp2gru)
            qha_result['phonon'] = qha.get_summary_dict()
            qha_result['phonon']['entropies'] = vol_s_vib
            qha_result['phonon']['heat_capacities'] = vol_c_vib
            qha_result['phonon']['temperatures'] = qha_result['phonon'][
                'temperatures'].tolist()

        # calculate the Debye model results no matter what
        qha_debye = Quasiharmonic(energies,
                                  volumes,
                                  structure,
                                  dos_objects=dos_objs,
                                  F_vib=None,
                                  t_min=self['t_min'],
                                  t_max=self['t_max'],
                                  t_step=self['t_step'],
                                  poisson=poisson,
                                  bp2gru=bp2gru)

        # fit 0 K EOS for good measure
        eos = Vinet(volumes, energies)
        eos.fit()
        errors = eos.func(volumes) - energies
        sum_square_error = float(np.sum(np.square(errors)))
        eos_res = {}
        eos_res['b0_GPa'] = float(eos.b0_GPa)
        eos_res['b0'] = float(eos.b0)
        eos_res['b1'] = float(eos.b1)
        eos_res['eq_volume'] = float(eos.v0)
        eos_res['eq_energy'] = float(eos.e0)
        eos_res['energies'] = energies
        eos_res['volumes'] = volumes
        eos_res['name'] = 'Vinet'
        eos_res['error'] = {}
        eos_res['error']['difference'] = errors.tolist(
        )  # volume by volume differences
        eos_res['error']['sum_square_error'] = sum_square_error
        qha_result['eos'] = eos_res

        qha_result['debye'] = qha_debye.get_summary_dict()
        qha_result['debye']['poisson'] = poisson
        qha_result['debye']['bp2gru'] = bp2gru
        qha_result['debye']['temperatures'] = qha_result['debye'][
            'temperatures'].tolist()

        qha_result['version_atomate'] = atomate_ver
        qha_result['version_dfttk'] = dfttk_ver
        volumes_false = []
        energies_false = []
        static_falses = vasp_db.collection.find(
            {'$and': [{
                'metadata.tag': tag
            }, {
                'adopted': False
            }]})
        for static_false in static_falses:
            volumes_false.append(
                static_false['output']['structure']['lattice']['volume'])
            energies_false.append(static_false['output']['energy'])
        qha_result['Volumes_fitting_false'] = volumes_false
        qha_result['Energies_fitting_false'] = energies_false
        print('Volumes_fitting_false : %s' % volumes_false)
        print('Energies_fitting_false: %s' % energies_false)
        print('number of phonon calculations found : %s' % num_phonons)
        """
        # write to JSON for debugging purposes
        import json
        with open('qha_summary.json', 'w') as fp:
            json.dump(qha_result, fp, indent=4)
        """

        if self.get("test_failure", False): return
        #if self['phonon']:
        if qha_result['has_phonon']:
            vasp_db.db['qha_phonon'].insert_one(qha_result)
        else:
            vasp_db.db['qha'].insert_one(qha_result)
Esempio n. 33
0
    def run_task(self, fw_spec):
        ref_struct = self['structure']
        d = {"analysis": {}, "initial_structure": self['structure'].as_dict()}

        # Get optimized structure
        calc_locs_opt = [
            cl for cl in fw_spec.get('calc_locs', [])
            if 'optimiz' in cl['name']
        ]
        if calc_locs_opt:
            optimize_loc = calc_locs_opt[-1]['path']
            logger.info("Parsing initial optimization directory: {}".format(
                optimize_loc))
            drone = VaspDrone()
            optimize_doc = drone.assimilate(optimize_loc)
            opt_struct = Structure.from_dict(
                optimize_doc["calcs_reversed"][0]["output"]["structure"])
            d.update({"optimized_structure": opt_struct.as_dict()})
            ref_struct = opt_struct
            eq_stress = -0.1 * Stress(optimize_doc["calcs_reversed"][0]
                                      ["output"]["ionic_steps"][-1]["stress"])
        else:
            eq_stress = None

        if self.get("fw_spec_field"):
            d.update({
                self.get("fw_spec_field"):
                fw_spec.get(self.get("fw_spec_field"))
            })

        # Get the stresses, strains, deformations from deformation tasks
        defo_dicts = fw_spec["deformation_tasks"].values()
        stresses, strains, deformations = [], [], []
        for defo_dict in defo_dicts:
            stresses.append(Stress(defo_dict["stress"]))
            strains.append(Strain(defo_dict["strain"]))
            deformations.append(Deformation(defo_dict["deformation_matrix"]))
            # Add derived stresses and strains if symmops is present
            for symmop in defo_dict.get("symmops", []):
                stresses.append(Stress(defo_dict["stress"]).transform(symmop))
                strains.append(Strain(defo_dict["strain"]).transform(symmop))
                deformations.append(
                    Deformation(
                        defo_dict["deformation_matrix"]).transform(symmop))

        stresses = [-0.1 * s for s in stresses]
        pk_stresses = [
            stress.piola_kirchoff_2(deformation)
            for stress, deformation in zip(stresses, deformations)
        ]

        d['fitting_data'] = {
            'cauchy_stresses': stresses,
            'eq_stress': eq_stress,
            'strains': strains,
            'pk_stresses': pk_stresses,
            'deformations': deformations
        }

        logger.info("Analyzing stress/strain data")
        # TODO: @montoyjh: what if it's a cubic system? don't need 6. -computron
        # TODO: Can add population method but want to think about how it should
        #           be done. -montoyjh
        order = self.get('order', 2)
        if order > 2:
            method = 'finite_difference'
        else:
            method = self.get('fitting_method', 'finite_difference')

        if method == 'finite_difference':
            result = ElasticTensorExpansion.from_diff_fit(strains,
                                                          pk_stresses,
                                                          eq_stress=eq_stress,
                                                          order=order)
            if order == 2:
                result = ElasticTensor(result[0])
        elif method == 'pseudoinverse':
            result = ElasticTensor.from_pseudoinverse(strains, pk_stresses)
        elif method == 'independent':
            result = ElasticTensor.from_independent_strains(
                strains, pk_stresses, eq_stress=eq_stress)
        else:
            raise ValueError(
                "Unsupported method, method must be finite_difference, "
                "pseudoinverse, or independent")

        ieee = result.convert_to_ieee(ref_struct)
        d.update({
            "elastic_tensor": {
                "raw": result.voigt,
                "ieee_format": ieee.voigt
            }
        })
        if order == 2:
            d.update({
                "derived_properties":
                ieee.get_structure_property_dict(ref_struct)
            })
        else:
            soec = ElasticTensor(ieee[0])
            d.update({
                "derived_properties":
                soec.get_structure_property_dict(ref_struct)
            })

        d["formula_pretty"] = ref_struct.composition.reduced_formula
        d["fitting_method"] = method
        d["order"] = order

        d = jsanitize(d)

        # Save analysis results in json or db
        db_file = env_chk(self.get('db_file'), fw_spec)
        if not db_file:
            with open("elasticity.json", "w") as f:
                f.write(json.dumps(d, default=DATETIME_HANDLER))
        else:
            db = VaspCalcDb.from_db_file(db_file, admin=True)
            db.collection = db.db["elasticity"]
            db.collection.insert_one(d)
            logger.info("Elastic analysis complete.")

        return FWAction()
Esempio n. 34
0
    def run_task(self, fw_spec):

        wfid = list(filter(lambda x: 'wfid' in x, fw_spec['tags'])).pop()
        db_file = env_chk(self.get("db_file"), fw_spec)
        vaspdb = VaspCalcDb.from_db_file(db_file, admin=True)

        # ferroelectric workflow groups calculations by generated wfid tag
        polarization_tasks = vaspdb.collection.find({"tags": wfid, "task_label": {"$regex": ".*polarization"}})

        tasks = []
        outcars = []
        structure_dicts = []
        sort_weight = []
        energies_per_atom = []
        energies = []
        zval_dicts = []

        for p in polarization_tasks:
            # Grab data from each polarization task
            energies_per_atom.append(p['calcs_reversed'][0]['output']['energy_per_atom'])
            energies.append(p['calcs_reversed'][0]['output']['energy'])
            tasks.append(p['task_label'])
            outcars.append(p['calcs_reversed'][0]['output']['outcar'])
            structure_dicts.append(p['calcs_reversed'][0]['input']['structure'])
            zval_dicts.append(p['calcs_reversed'][0]['output']['outcar']['zval_dict'])

            # Add weight for sorting
            # Want polarization calculations in order of nonpolar to polar for Polarization object

            # This number needs to be bigger than the number of calculations
            max_sort_weight = 1000000

            if 'nonpolar_polarization' in p['task_label']:
                sort_weight.append(0)
            elif "polar_polarization" in p['task_label']:
                sort_weight.append(max_sort_weight)
            elif "interpolation_" in p['task_label']:
                num = 0
                part = re.findall(r'interpolation_[0-9]+_polarization', p['task_label'])
                if part != []:
                    part2 = re.findall(r'[0-9]+', part.pop())
                    if part2 != []:
                        num = part2.pop()
                sort_weight.append(max_sort_weight - int(num))

        # Sort polarization tasks
        # nonpolar -> interpolation_n -> interpolation_n-1 -> ...  -> interpolation_1 -> polar
        data = zip(tasks, structure_dicts, outcars, energies_per_atom, energies, sort_weight)
        data = sorted(data,key=lambda x: x[-1])

        # Get the tasks, structures, etc in sorted order from the zipped data.
        tasks, structure_dicts, outcars, energies_per_atom, energies, sort_weight = zip(*data)

        structures = [Structure.from_dict(structure) for structure in structure_dicts]

        # If LCALCPOL = True then Outcar will parse and store the pseudopotential zvals.
        zval_dict = zval_dicts.pop()

        # Assumes that we want to calculate the ionic contribution to the dipole moment.
        # VASP's ionic contribution is sometimes strange.
        # See pymatgen.analysis.ferroelectricity.polarization.Polarization for details.
        p_elecs = [outcar['p_elec'] for outcar in outcars]
        p_ions = [get_total_ionic_dipole(structure, zval_dict) for structure in structures]

        polarization = Polarization(p_elecs, p_ions, structures)

        p_change = polarization.get_polarization_change().A1.tolist()
        p_norm = polarization.get_polarization_change_norm()
        polarization_max_spline_jumps = polarization.max_spline_jumps()
        same_branch = polarization.get_same_branch_polarization_data(convert_to_muC_per_cm2=True)
        raw_elecs, raw_ions = polarization.get_pelecs_and_pions()
        quanta = polarization.get_lattice_quanta(convert_to_muC_per_cm2=True)

        energy_trend = EnergyTrend(energies_per_atom)
        energy_max_spline_jumps = energy_trend.max_spline_jump()

        polarization_dict = {}

        def split_abc(var, var_name):
            d = {}
            for i, j in enumerate('abc'):
                d.update({var_name + "_{}".format(j): var[:, i].A1.tolist()})
            return d

        # Add some sort of id for the structures? Like cid but more general?
        # polarization_dict.update({'cid': cid})

        # General information
        polarization_dict.update({'pretty_formula': structures[0].composition.reduced_formula})
        polarization_dict.update({'wfid': wfid})
        polarization_dict.update({'task_label_order': tasks})

        # Polarization information
        polarization_dict.update({'polarization_change': p_change})
        polarization_dict.update({'polarization_change_norm': p_norm})
        polarization_dict.update({'polarization_max_spline_jumps': polarization_max_spline_jumps})
        polarization_dict.update(split_abc(same_branch, "same_branch_polarization"))
        polarization_dict.update(split_abc(raw_elecs, "raw_electron_polarization"))
        polarization_dict.update(split_abc(raw_ions, "raw_electron_polarization"))
        polarization_dict.update(split_abc(quanta, "polarization_quanta"))
        polarization_dict.update({"zval_dict": zval_dict})

        # Energy information
        polarization_dict.update({'energy_per_atom_max_spline_jumps': energy_max_spline_jumps})
        polarization_dict.update({"energies": energies})
        polarization_dict.update({"energies_per_atom": energies_per_atom})
        polarization_dict.update({'outcars': outcars})
        polarization_dict.update({"structures": structure_dicts})

        # Write all the info to db.
        coll = vaspdb.db["polarization_tasks"]
        coll.insert_one(polarization_dict)
Esempio n. 35
0
    def run_task(self, fw_spec):

        gibbs_dict = {}

        tag = self["tag"]
        t_step = self.get("t_step", 10)
        t_min = self.get("t_min", 0)
        t_max = self.get("t_max", 1000)
        mesh = self.get("mesh", [20, 20, 20])
        eos = self.get("eos", "vinet")
        qha_type = self.get("qha_type", "debye_model")
        pressure = self.get("pressure", 0.0)
        poisson = self.get("poisson", 0.25)
        anharmonic_contribution = self.get("anharmonic_contribution", False)
        gibbs_dict["metadata"] = self.get("metadata", {})

        db_file = env_chk(self.get("db_file"), fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        # get the optimized structure
        d = mmdb.collection.find_one(
            {"task_label": "{} structure optimization".format(tag)},
            {"calcs_reversed": 1})
        structure = Structure.from_dict(
            d["calcs_reversed"][-1]["output"]['structure'])
        gibbs_dict["structure"] = structure.as_dict()
        gibbs_dict["formula_pretty"] = structure.composition.reduced_formula

        # get the data(energy, volume, force constant) from the deformation runs
        docs = mmdb.collection.find(
            {
                "task_label": {
                    "$regex": "{} gibbs*".format(tag)
                },
                "formula_pretty": structure.composition.reduced_formula
            }, {"calcs_reversed": 1})
        energies = []
        volumes = []
        force_constants = []
        for d in docs:
            s = Structure.from_dict(
                d["calcs_reversed"][-1]["output"]['structure'])
            energies.append(d["calcs_reversed"][-1]["output"]['energy'])
            if qha_type not in ["debye_model"]:
                force_constants.append(
                    d["calcs_reversed"][-1]["output"]['force_constants'])
            volumes.append(s.volume)
        gibbs_dict["energies"] = energies
        gibbs_dict["volumes"] = volumes
        if qha_type not in ["debye_model"]:
            gibbs_dict["force_constants"] = force_constants

        try:
            # use quasi-harmonic debye approximation
            if qha_type in ["debye_model"]:

                from pymatgen.analysis.quasiharmonic import QuasiharmonicDebyeApprox

                qhda = QuasiharmonicDebyeApprox(
                    energies,
                    volumes,
                    structure,
                    t_min,
                    t_step,
                    t_max,
                    eos,
                    pressure=pressure,
                    poisson=poisson,
                    anharmonic_contribution=anharmonic_contribution)
                gibbs_dict.update(qhda.get_summary_dict())
                gibbs_dict["anharmonic_contribution"] = anharmonic_contribution
                gibbs_dict["success"] = True

            # use the phonopy interface
            else:

                from atomate.vasp.analysis.phonopy import get_phonopy_gibbs

                G, T = get_phonopy_gibbs(energies, volumes, force_constants,
                                         structure, t_min, t_step, t_max, mesh,
                                         eos, pressure)
                gibbs_dict["gibbs_free_energy"] = G
                gibbs_dict["temperatures"] = T
                gibbs_dict["success"] = True

        # quasi-harmonic analysis failed, set the flag to false
        except:
            import traceback

            logger.warn("Quasi-harmonic analysis failed!")
            gibbs_dict["success"] = False
            gibbs_dict["traceback"] = traceback.format_exc()
            gibbs_dict['metadata'].update({"task_label_tag": tag})
            gibbs_dict["created_at"] = datetime.utcnow()

        gibbs_dict = jsanitize(gibbs_dict)

        # TODO: @matk86: add a list of task_ids that were used to construct the analysis to DB?
        # -computron
        if not db_file:
            dump_file = "gibbs.json"
            logger.info("Dumping the analysis summary to {}".format(dump_file))
            with open(dump_file, "w") as f:
                f.write(json.dumps(gibbs_dict, default=DATETIME_HANDLER))
        else:
            coll = mmdb.db["gibbs_tasks"]
            coll.insert_one(gibbs_dict)

        logger.info("Gibbs free energy calculation complete.")

        if not gibbs_dict["success"]:
            return FWAction(defuse_children=True)
Esempio n. 36
0
    def run_task(self, fw_spec):
        # get the directory that contains the VASP dir to parse
        calc_dir = os.getcwd()
        if "calc_dir" in self:
            calc_dir = self["calc_dir"]
        elif self.get("calc_loc"):
            calc_dir = get_calc_loc(self["calc_loc"], fw_spec["calc_locs"])["path"]

        # parse the VASP directory
        logger.info("PARSING DIRECTORY: {}".format(calc_dir))

        drone = VaspDrone(additional_fields=self.get("additional_fields"),
                          parse_dos=self.get("parse_dos", False),
                          bandstructure_mode=self.get("bandstructure_mode", False),
                          parse_chgcar=self.get("parse_chgcar", False),
                          parse_aeccar=self.get("parse_aeccar", False))

        # assimilate (i.e., parse)
        task_doc = drone.assimilate(calc_dir)

        # Check for additional keys to set based on the fw_spec
        if self.get("fw_spec_field"):
            task_doc.update(fw_spec[self.get("fw_spec_field")])

        # get the database connection
        db_file = env_chk(self.get('db_file'), fw_spec)

        # db insertion or taskdoc dump
        if not db_file:
            with open("task.json", "w") as f:
                f.write(json.dumps(task_doc, default=DATETIME_HANDLER))
        else:
            mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
            t_id = mmdb.insert_task(
                task_doc, use_gridfs=self.get("parse_dos", False)
                or bool(self.get("bandstructure_mode", False))
                or self.get("parse_chgcar", False)
                or self.get("parse_aeccar", False))
            logger.info("Finished parsing with task_id: {}".format(t_id))

        defuse_children = False
        if task_doc["state"] != "successful":
            defuse_unsuccessful = self.get("defuse_unsuccessful",
                                           DEFUSE_UNSUCCESSFUL)
            if defuse_unsuccessful is True:
                defuse_children = True
            elif defuse_unsuccessful is False:
                pass
            elif defuse_unsuccessful == "fizzle":
                raise RuntimeError(
                    "VaspToDb indicates that job is not successful "
                    "(perhaps your job did not converge within the "
                    "limit of electronic/ionic iterations)!")
            else:
                raise RuntimeError("Unknown option for defuse_unsuccessful: "
                                   "{}".format(defuse_unsuccessful))

        task_fields_to_push = self.get("task_fields_to_push", None)
        update_spec = {}
        if task_fields_to_push:
            if isinstance(task_fields_to_push, dict):
                for key, path_in_task_doc in task_fields_to_push.items():
                    if has(task_doc, path_in_task_doc):
                        update_spec[key] = get(task_doc, path_in_task_doc)
                    else:
                        logger.warn("Could not find {} in task document. Unable to push to next firetask/firework".format(path_in_task_doc))
            else:
                raise RuntimeError("Inappropriate type {} for task_fields_to_push. It must be a "
                                   "dictionary of format: {key: path} where key refers to a field "
                                   "in the spec and path is a full mongo-style path to a "
                                   "field in the task document".format(type(task_fields_to_push)))

        return FWAction(stored_data={"task_id": task_doc.get("task_id", None)},
                        defuse_children=defuse_children, update_spec=update_spec)
Esempio n. 37
0
    def run_task(self, fw_spec):
        # get the directory that contains the VASP dir to parse
        calc_dir = os.getcwd()
        if "calc_dir" in self:
            calc_dir = self["calc_dir"]
        elif self.get("calc_loc"):
            calc_dir = get_calc_loc(self["calc_loc"],
                                    fw_spec["calc_locs"])["path"]

        # parse the VASP directory
        logger.info("PARSING DIRECTORY: {}".format(calc_dir))

        drone = VaspDrone(additional_fields=self.get("additional_fields"),
                          parse_dos=self.get("parse_dos", False),
                          bandstructure_mode=self.get("bandstructure_mode",
                                                      False),
                          parse_chgcar=self.get("parse_chgcar", False),
                          parse_aeccar=self.get("parse_aeccar", False))

        # assimilate (i.e., parse)
        task_doc = drone.assimilate(calc_dir)

        # Check for additional keys to set based on the fw_spec
        if self.get("fw_spec_field"):
            task_doc.update(fw_spec[self.get("fw_spec_field")])

        # get the database connection
        db_file = env_chk(self.get('db_file'), fw_spec)

        # db insertion or taskdoc dump
        if not db_file:
            with open("task.json", "w") as f:
                f.write(json.dumps(task_doc, default=DATETIME_HANDLER))
        else:
            mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
            t_id = mmdb.insert_task(
                task_doc,
                use_gridfs=self.get("parse_dos", False)
                or bool(self.get("bandstructure_mode", False))
                or self.get("parse_chgcar", False)
                or self.get("parse_aeccar", False))
            logger.info("Finished parsing with task_id: {}".format(t_id))

        defuse_children = False
        if task_doc["state"] != "successful":
            defuse_unsuccessful = self.get("defuse_unsuccessful",
                                           DEFUSE_UNSUCCESSFUL)
            if defuse_unsuccessful is True:
                defuse_children = True
            elif defuse_unsuccessful is False:
                pass
            elif defuse_unsuccessful == "fizzle":
                raise RuntimeError(
                    "VaspToDb indicates that job is not successful "
                    "(perhaps your job did not converge within the "
                    "limit of electronic/ionic iterations)!")
            else:
                raise RuntimeError("Unknown option for defuse_unsuccessful: "
                                   "{}".format(defuse_unsuccessful))

        task_fields_to_push = self.get("task_fields_to_push", None)
        update_spec = {}
        if task_fields_to_push:
            if isinstance(task_fields_to_push, dict):
                for key, path_in_task_doc in task_fields_to_push.items():
                    if has(task_doc, path_in_task_doc):
                        update_spec[key] = get(task_doc, path_in_task_doc)
                    else:
                        logger.warn(
                            "Could not find {} in task document. Unable to push to next firetask/firework"
                            .format(path_in_task_doc))
            else:
                raise RuntimeError(
                    "Inappropriate type {} for task_fields_to_push. It must be a "
                    "dictionary of format: {key: path} where key refers to a field "
                    "in the spec and path is a full mongo-style path to a "
                    "field in the task document".format(
                        type(task_fields_to_push)))

        return FWAction(stored_data={"task_id": task_doc.get("task_id", None)},
                        defuse_children=defuse_children,
                        update_spec=update_spec)
Esempio n. 38
0
    def run_task(self, fw_spec):
        # get the database connection
        db_file = env_chk(self["db_file"], fw_spec)
        mmdb = VaspCalcDb.from_db_file(db_file, admin=True)
        wf_uuid = self["approx_neb_wf_uuid"]
        index = self["end_points_index"]
        t_id = self.get("end_point_task_id",
                        fw_spec.get("end_points_" + str(index) + "_task_id"))
        print(t_id)

        # get any workflow inputs provided in fw_spec to store in task_doc
        wf_input_host_structure = fw_spec.get("wf_input_host_structure")
        wf_input_insert_coords = self.get("wf_input_insert_coords")
        wf_insertion_site_specie = fw_spec.get("insert_specie")
        wf_insertion_site_index = fw_spec.get("inserted_site_indexes")

        # get task doc (parts stored in approx_neb collection) and update for record keeping
        task_doc = mmdb.collection.find_one_and_update(
            {
                "task_id": t_id,
                "approx_neb.calc_type": "end_point"
            },
            {
                "$push": {
                    "approx_neb.wf_uuids": wf_uuid,
                    "approx_neb.end_points_indexes": index,
                },
                "$set": {
                    "approx_neb._wf_input_host_structure":
                    wf_input_host_structure,
                    "approx_neb._wf_input_insert_coords":
                    wf_input_insert_coords,
                    "approx_neb._wf_insertion_site_specie":
                    wf_insertion_site_specie,
                    "approx_neb._wf_insertion_site_index":
                    wf_insertion_site_index,
                },
            },
        )
        if task_doc == None:
            raise ValueError(
                "Error updating approx neb end point with task_id: {}".format(
                    t_id))

        # Store info in approx_neb collection for record keeping
        mmdb.collection = mmdb.db["approx_neb"]

        ep_subdoc = mmdb.collection.find_one(
            {"wf_uuid": wf_uuid},
            {
                "end_points": 1,
                "_id": 0
            },
        )
        ep_subdoc = ep_subdoc["end_points"]
        end_point_output = {
            "dir_name": task_doc["dir_name"],
            "formula_pretty": task_doc["formula_pretty"],
            "output": task_doc["output"],
            "task_id": task_doc["task_id"],
        }
        ep_subdoc[index].update(end_point_output)
        mmdb.collection.update_one(
            {"wf_uuid": wf_uuid},
            {
                "$set": {
                    "end_points": ep_subdoc,
                    "last_updated": datetime.utcnow()
                }
            },
        )

        return FWAction(
            stored_data={
                "wf_uuid": wf_uuid,
                "end_points_index": index,
                "end_point_output": end_point_output,
            })
Esempio n. 39
0
import pytest
import shutil
import os
import time
import copy
from os import walk
from atomate.vasp.database import VaspCalcDb
from dfttk.scripts.run_dfttk_ext import ext_EVfind, ext_thfind, ext_thelec
from dfttk.utils import check_symmetry
from dfttk.scripts.run_dfttk import parse_magmom
from pymatgen.core import Structure

head, tail = os.path.split(__file__)
db_file = os.path.join(head, "db.json")
print("db_file", db_file)
vasp_db = VaspCalcDb.from_db_file(db_file, admin=False)


def _thargs():
    parser = run_ext_thfind(None)
    args, unknown = parser.parse_known_args()
    return args


@pytest.mark.get_thargs
def test_args():
    args = _thargs()
    for arg in vars(args):
        print(arg, getattr(args, arg))

Esempio n. 40
0
def test_get_static_calculations():
    tag = '0267947f-b5a0-4993-8b5e-58f9dfb4e362'
    vasp_db = VaspCalcDb.from_db_file(db_file=db_file, admin=True)
    volumes, energies, dos_objs, _ = get_static_calculations(vasp_db, tag)
    #print(volumes, energies)
    assert False