示例#1
0
 def test_as_dict(self):
     filepath = os.path.join(test_dir, "vasprun.xml")
     vasprun = Vasprun(filepath, parse_potcar_file=False)
     # Test that as_dict() is json-serializable
     self.assertIsNotNone(json.dumps(vasprun.as_dict()))
     self.assertEqual(
         vasprun.as_dict()["input"]["potcar_type"], ["PAW_PBE", "PAW_PBE", "PAW_PBE", "PAW_PBE", "PAW_PBE"]
     )
示例#2
0
 def test_as_dict(self):
     filepath = os.path.join(test_dir, 'vasprun.xml')
     vasprun = Vasprun(filepath, parse_potcar_file=False)
     #Test that as_dict() is json-serializable
     self.assertIsNotNone(json.dumps(vasprun.as_dict()))
     self.assertEqual(
         vasprun.as_dict()["input"]["potcar_type"],
         ['PAW_PBE', 'PAW_PBE', 'PAW_PBE', 'PAW_PBE', 'PAW_PBE'])
def get_structure(vasprun_dos, vasprun_bands):
    ## get structure object and "save" in hidden div in json format
    if vasprun_dos:
        structure = Vasprun(vasprun_dos).structures[-1]
    elif vasprun_bands:
        structure = Vasprun(vasprun_bands).structures[-1]
    return json.dumps(structure.as_dict())
示例#4
0
def parse_fols(hkl=None, bulk_per_atom=None, **kwargs):
    """
    Parses the convergence folders to get the surface energy, total energy,
    energy per atom and time taken for each slab and vacuum thickness
    combination

    Args:
        hkl (tuple): Miller index of the slab
        bulk_per_atom (float): bulk energy per atom from a converged bulk
        calculation

    Returns:
        hkl_data.csv
    """
     # Check all neccessary input parameters are present 
    if not any ([hkl, bulk_per_atom]): 
        raise ValueError('One or more of the required arguments (bulk_per_atom, '
                         'hkl) were not supplied.')

    df_list = []
    hkl_sorted = ''.join(map(str, hkl))

    for root, fols in os.walk('.'):
        for fol in fols:
            if not any([fol==root, fol=='.ipynb_checkpoints']):
                path = os.path.join(root, fol)
                vsp_path = '{}/vasprun.xml'.format(path)

                # instantiate structure, slab and vasprun objects
                vsp = Vasprun(vsp_path, **kwargs)
                slab = slab_from_file(vsp_path, hkl)
                vsp_dict = vsp.as_dict()

                # extract the data
                area = slab.surface_area
                atoms = vsp_dict['nsites']
                slab_energy = vsp.final_energy
                energy_per_atom = slab_energy / atoms
                surface_energy = (slab_energy - bulk_per_atom * atoms)/(2 * area) * 16.02

                # name of fol has to be ./slabthickness_vacthickness_index
                slab_vac_index = fol.split('_')

                # reads the outcar to get the time taken
                with open('{}/OUTCAR'.format(path), 'r') as otc:
                    lines = list(otc)
                    line = lines[-8].split(':')

                df_list.append({'slab_thickness': slab_vac_index[0],
                          'vac_thickness': slab_vac_index[1],
                          'slab_index': slab_vac_index[2],
                          'surface_energy': surface_energy,
                          'slab_toten': slab_energy,
                          'slab_per_atom': energy_per_atom,
                          'time_taken': line[1].strip()})

    df = pd.DataFrame(df_list)
    df.to_csv('{}_data.csv'.format(hkl_sorted), index=False)
示例#5
0
    def check_dft_calcs(self):
        """
        Helper function to check DFT calculations via polling
        AWS batch.  Updates current data with latest AWS batch
        response.
        """
        for structure_id, calc in self.current_data.iterrows():
            if calc["status"] in ["SUCCEEDED", "FAILED"]:
                continue
            path = calc["path"]
            print("Checking status of {}: {}".format(path, structure_id))
            aws_cmd = "aws batch describe-jobs --jobs " "--region=us-east-1 {}".format(
                calc["jobId"])
            result = subprocess.check_output(shlex.split(aws_cmd))
            result = json.loads(result)
            aws_status = result["jobs"][0]["status"]
            if aws_status == "SUCCEEDED":
                os.chdir(path)
                subprocess.call("trisync")
                os.chdir("simulation")
                try:
                    vr = Vasprun("static/vasprun.xml")
                    vr_dict = vr.as_dict()
                    delta_e = get_qmpy_formation_energy(
                        vr_dict["output"]["final_energy_per_atom"],
                        vr_dict["pretty_formula"],
                        1,
                    )
                    data = {
                        "status": "SUCCEEDED",
                        "error": None,
                        "result": vr,
                        "delta_e": delta_e,
                    }
                except Exception as e:
                    error_doc = {}
                    if os.path.isfile("err"):
                        with open("err") as errfile:
                            error_doc.update({"trisub_stderr": errfile.read()})
                    error_doc.update({
                        "camd_exception": "{}".format(e),
                        "camd_traceback": traceback.format_exc(),
                    })

                    # Dump error docs to avoid Pandas issues with dict values
                    data = {"status": "FAILED", "error": json.dumps(error_doc)}
                os.chdir(path)

            elif aws_status == "FAILED":
                error_doc = {
                    "aws_fail":
                    result["jobs"][0]["attempts"][-1]["statusReason"]
                }
                data = {"status": "FAILED", "error": json.dumps(error_doc)}
            else:
                data = {"status": aws_status}
            update_dataframe_row(self.current_data, structure_id, data)
示例#6
0
def check_dft_calcs(calc_status):
    """

    Args:
        calc_status (dict):

    Returns:
        updated calc_status dictionary

    """
    for structure_id, calc in calc_status.items():
        if calc['status'] in ['SUCCEEDED', 'FAILED']:
            continue
        path = calc['path']
        print("Checking status of {}: {}".format(path, structure_id))
        aws_cmd = "aws batch describe-jobs --jobs " \
                  "--region=us-east-1 {}".format(calc['jobId'])
        result = subprocess.check_output(shlex.split(aws_cmd))
        result = json.loads(result)
        aws_status = result["jobs"][0]["status"]
        if aws_status == "SUCCEEDED":
            os.chdir(path)
            subprocess.call('trisync')
            os.chdir('simulation')
            try:
                vr = Vasprun('static/vasprun.xml')
                calc.update({
                    "status": "SUCCEEDED",
                    "error": None,
                    "result": vr.as_dict()
                })
            except Exception as e:
                error_doc = {}
                with open('err') as errfile:
                    error_doc.update({"trisub_stderr": errfile.read()})
                error_doc.update({
                    "camd_exception": "{}".format(e),
                    "camd_traceback": traceback.format_exc()
                })
                calc.update({
                    "status": "FAILED",
                    "error": error_doc,
                    "result": None
                })
        elif aws_status == "FAILED":
            error_doc = {
                "aws_fail": result['jobs'][0]['attempts'][-1]['statusReason']
            }
            calc.update({"status": "FAILED", "error": error_doc})
        else:
            calc.update({"status": aws_status})
    return calc_status
示例#7
0
def test_get_vasprun_method(testdata):
    from pymatgen.io.vasp.outputs import Vasprun
    from aiida_cusp.data.outputs.vasp_vasprun import VaspVasprunData
    from aiida_cusp.utils.defaults import VasprunParsingDefaults
    default_parsing_args = VasprunParsingDefaults.PARSER_ARGS
    vasprun_xml = testdata / 'vasprun.xml'
    vasprun_node = VaspVasprunData(file=vasprun_xml)
    # create vasprun object from node and compare to the original
    # pymatgen class generated from the test file
    vasprun_obj_node = vasprun_node.get_vasprun()
    vasprun_obj_pmg = Vasprun(vasprun_xml, **default_parsing_args)
    node_contents = json.dumps(vasprun_obj_node.as_dict(), sort_keys=True)
    pmg_contents = json.dumps(vasprun_obj_pmg.as_dict(), sort_keys=True)
    assert node_contents == pmg_contents
示例#8
0
def data(vasprun_file, data="basic"):
    """
    Extract data from a vasprun.xml file and write it as a data.json. Mainly used to
    make the data files more compact.

    Args:
        vasprun_file (str): Path to the vasprun.xml file.
        data: String or List of strings that details the data to extract from the
            vasprun.xml. Defaults to "basic", which simply parses the vasprun.xml file
            with the standard kwargs of the Vasprun class,
            see pymatgen.io.vasp.outputs.Vasprun. Other options include:

            "energy": The final energy
            "structure": The final structure
            "dos": The CompleteDos

    Returns:

    """
    directory = os.path.dirname(os.path.abspath(vasprun_file))
    vr = Vasprun(vasprun_file)

    data_dict = {}

    if "basic" in data:
        data_dict.update(vr.as_dict())
    if "energy" in data:
        data_dict.update({"energy": vr.final_energy})
    if "structure" in data:
        data_dict.update({"structure": vr.final_structure.to_json()})
    if "dos" in data:
        data_dict.update({"dos": vr.complete_dos.as_dict()})

    with zopen(os.path.join(directory, "data.json"), "w") as file:

        file.write(json.dumps(data_dict))
示例#9
0
def convert_xml_to_pickle():
    import pickle
    from pymatgen.io.vasp.outputs import Vasprun
    vasprun = Vasprun('./vasprun.xml')
    pickle.dump(vasprun.as_dict(), open('./vasprun.p', 'wb'))
示例#10
0
    def test_properties(self):

        filepath = os.path.join(test_dir, 'vasprun.xml.nonlm')
        vasprun = Vasprun(filepath, parse_potcar_file=False)
        orbs = list(vasprun.complete_dos.pdos[vasprun.final_structure[
            0]].keys())
        self.assertIn(OrbitalType.s, orbs)
        filepath = os.path.join(test_dir, 'vasprun.xml')
        vasprun = Vasprun(filepath, parse_potcar_file=False)

        #Test NELM parsing.
        self.assertEqual(vasprun.parameters["NELM"], 60)
        #test pdos parsing

        pdos0 = vasprun.complete_dos.pdos[vasprun.final_structure[0]]
        self.assertAlmostEqual(pdos0[Orbital.s][Spin.up][16], 0.0026)
        self.assertAlmostEqual(pdos0[Orbital.pz][Spin.down][16], 0.0012)
        self.assertEqual(pdos0[Orbital.s][Spin.up].shape, (301, ))


        filepath2 = os.path.join(test_dir, 'lifepo4.xml')
        vasprun_ggau = Vasprun(filepath2, parse_projected_eigen=True,
                               parse_potcar_file=False)
        totalscsteps = sum([len(i['electronic_steps'])
                            for i in vasprun.ionic_steps])
        self.assertEqual(29, len(vasprun.ionic_steps))
        self.assertEqual(len(vasprun.structures), len(vasprun.ionic_steps))
        self.assertEqual(vasprun.lattice,
                         vasprun.lattice_rec.reciprocal_lattice)

        for i, step in enumerate(vasprun.ionic_steps):
            self.assertEqual(vasprun.structures[i], step["structure"])

        self.assertTrue(all([vasprun.structures[i] == vasprun.ionic_steps[i][
            "structure"] for i in range(len(vasprun.ionic_steps))]))

        self.assertEqual(308, totalscsteps,
                         "Incorrect number of energies read from vasprun.xml")

        self.assertEqual(['Li'] + 4 * ['Fe'] + 4 * ['P'] + 16 * ["O"],
                         vasprun.atomic_symbols)
        self.assertEqual(vasprun.final_structure.composition.reduced_formula,
                         "LiFe4(PO4)4")
        self.assertIsNotNone(vasprun.incar, "Incar cannot be read")
        self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read")
        self.assertIsNotNone(vasprun.eigenvalues, "Eigenvalues cannot be read")
        self.assertAlmostEqual(vasprun.final_energy, -269.38319884, 7)
        self.assertAlmostEqual(vasprun.tdos.get_gap(), 2.0589, 4)
        expectedans = (2.539, 4.0906, 1.5516, False)
        (gap, cbm, vbm, direct) = vasprun.eigenvalue_band_properties
        self.assertAlmostEqual(gap, expectedans[0])
        self.assertAlmostEqual(cbm, expectedans[1])
        self.assertAlmostEqual(vbm, expectedans[2])
        self.assertEqual(direct, expectedans[3])
        self.assertFalse(vasprun.is_hubbard)
        self.assertEqual(vasprun.potcar_symbols,
                         ['PAW_PBE Li 17Jan2003', 'PAW_PBE Fe 06Sep2000',
                          'PAW_PBE Fe 06Sep2000', 'PAW_PBE P 17Jan2003',
                          'PAW_PBE O 08Apr2002'])
        self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read")
        self.assertIsNotNone(vasprun.actual_kpoints,
                             "Actual kpoints cannot be read")
        self.assertIsNotNone(vasprun.actual_kpoints_weights,
                             "Actual kpoints weights cannot be read")
        for atomdoses in vasprun.pdos:
            for orbitaldos in atomdoses:
                self.assertIsNotNone(orbitaldos, "Partial Dos cannot be read")

        # test skipping ionic steps.
        vasprun_skip = Vasprun(filepath, 3, parse_potcar_file=False)
        self.assertEqual(vasprun_skip.nionic_steps, 29)
        self.assertEqual(len(vasprun_skip.ionic_steps),
                         int(vasprun.nionic_steps / 3) + 1)
        self.assertEqual(len(vasprun_skip.ionic_steps),
                         len(vasprun_skip.structures))
        self.assertEqual(len(vasprun_skip.ionic_steps),
                         int(vasprun.nionic_steps / 3) + 1)
        # Check that nionic_steps is preserved no matter what.
        self.assertEqual(vasprun_skip.nionic_steps,
                         vasprun.nionic_steps)

        self.assertNotAlmostEqual(vasprun_skip.final_energy,
                                  vasprun.final_energy)

        # Test with ionic_step_offset
        vasprun_offset = Vasprun(filepath, 3, 6, parse_potcar_file=False)
        self.assertEqual(len(vasprun_offset.ionic_steps),
                         int(len(vasprun.ionic_steps) / 3) - 1)
        self.assertEqual(vasprun_offset.structures[0],
                         vasprun_skip.structures[2])

        self.assertTrue(vasprun_ggau.is_hubbard)
        self.assertEqual(vasprun_ggau.hubbards["Fe"], 4.3)
        self.assertAlmostEqual(vasprun_ggau.projected_eigenvalues[Spin.up][
                                   0][0][96][0], 0.0032)
        d = vasprun_ggau.as_dict()
        self.assertEqual(d["elements"], ["Fe", "Li", "O", "P"])
        self.assertEqual(d["nelements"], 4)

        filepath = os.path.join(test_dir, 'vasprun.xml.unconverged')
        with warnings.catch_warnings(record=True) as w:
            # Cause all warnings to always be triggered.
            warnings.simplefilter("always")
            # Trigger a warning.
            vasprun_unconverged = Vasprun(filepath, parse_potcar_file=False)
            # Verify some things
            self.assertEqual(len(w), 1)
            self.assertTrue(issubclass(w[-1].category,
                                       UnconvergedVASPWarning))

            self.assertTrue(vasprun_unconverged.converged_ionic)
            self.assertFalse(vasprun_unconverged.converged_electronic)
            self.assertFalse(vasprun_unconverged.converged)

        filepath = os.path.join(test_dir, 'vasprun.xml.dfpt')
        vasprun_dfpt = Vasprun(filepath, parse_potcar_file=False)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][0], 3.26105533)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][1], -0.00459066)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static[2][2], 3.24330517)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][0], 3.33402531)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][1], -0.00559998)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[2][2], 3.31237357)
        self.assertTrue(vasprun_dfpt.converged)

        entry = vasprun_dfpt.get_computed_entry()
        entry = MaterialsProjectCompatibility(check_potcar_hash=False).process_entry(entry)
        self.assertAlmostEqual(entry.uncorrected_energy + entry.correction,
                               entry.energy)

        filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.ionic')
        vasprun_dfpt_ionic = Vasprun(filepath, parse_potcar_file=False)
        self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][0], 515.73485838)
        self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][1], -0.00263523)
        self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[2][2], 19.02110169)

        filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.unconverged')
        vasprun_dfpt_unconv = Vasprun(filepath, parse_potcar_file=False)
        self.assertFalse(vasprun_dfpt_unconv.converged_electronic)
        self.assertTrue(vasprun_dfpt_unconv.converged_ionic)
        self.assertFalse(vasprun_dfpt_unconv.converged)

        vasprun_uniform = Vasprun(os.path.join(test_dir, "vasprun.xml.uniform"),
                                  parse_potcar_file=False)
        self.assertEqual(vasprun_uniform.kpoints.style,
                         Kpoints.supported_modes.Reciprocal)

        vasprun_no_pdos = Vasprun(os.path.join(test_dir, "Li_no_projected.xml"),
                                  parse_potcar_file=False)
        self.assertIsNotNone(vasprun_no_pdos.complete_dos)
        self.assertFalse(vasprun_no_pdos.dos_has_errors)

        vasprun_diel = Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric"),
                               parse_potcar_file=False)
        self.assertAlmostEqual(0.4294,vasprun_diel.dielectric[0][10])
        self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][0])
        self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][1])
        self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][2])
        self.assertAlmostEqual(0.0,vasprun_diel.dielectric[1][51][3])
        self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][0])
        self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][1])
        self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][2])
        self.assertAlmostEqual(0.0,vasprun_diel.dielectric[2][85][3])

        v = Vasprun(os.path.join(test_dir, "vasprun.xml.indirect.gz"))
        (gap, cbm, vbm, direct) = v.eigenvalue_band_properties
        self.assertFalse(direct)
示例#11
0
def boltztrap(tmax=1001,
              tstep=50,
              tmin=None,
              doping=np.logspace(18, 21, 17),
              ke_mode='boltzmann',
              vasprun='vasprun.xml',
              kpoints=None,
              relaxation_time=1e-14,
              lpfac=10,
              run=True,
              analyse=True,
              output='boltztrap.hdf5',
              **kwargs):
    """Runs BoltzTraP from a VASP density of states (DoS).

    Runs quicker and more robustly than the pymatgen from_files version,
    and outputs an hdf5 file.
    Note: BoltzTraP can be a fickle friend, so if you're getting errors,
    it may be worth reinstalling or trying on a different machine.

    Arguments
    ---------

        tmax : float, optional
            maximum temperature in K. Default: 1000.
        tstep : float, optional
            temperature step in K. Default: 50.
        tmin : float, optional
            minimum temperature in K. This does not reduce how many
            temperatures are run in BoltzTraP, only how many are saved
            to hdf5. Default: tstep.
        doping : array-like, optional
            doping concentrations in cm-1.
            Default: np.logspace(18, 21, 17).
        k_mode : str, optional
            method for calculating the electronic thermal conductivity.
            Options:

                boltzmann (default):
                    standard boltztrap method. Madsen and Singh,
                    Comput. Phys. Commun. 2006, 175, 67.
                wiedemann:
                    Wiedemann-Franz law with constant L = 2.44E-8.
                    Franz and Wiedemann, Ann. Phys. 1853, 165, 497.
                snyder:
                    Wiedemann-Franz law, with L varying with Seebeck.
                    Kim et al., APL Mat. 2015, 3, 041506.

        vasprun : str, optional
            path to vasprun. Default: vasprun.xml.
        kpoints : str, optional
            path to KPOINTS file if there are zero-weighted k-points.
            Default: KPOINTS.
        relaxation_time : float, optional
            charge carrier relaxation time. Default: 1e-14.
        lpfac : int, optional
            DoS interpolation factor. Default: 10.

        run : bool, optional
            run BoltzTraP. Default: True.
        analyse : bool, optional
            analyse BoltzTraP. Default: True.
        output : str, optional
            output hdf5 filename. Default: boltztrap.hdf5.

        kwargs
            passed to pymatgen.electronic.structure.boltztrap.BoltztrapRunner.

    Returns
    -------

        None
            instead prints to hdf5 (see below).

    hdf5 File Contents
    ------------------

        average_eff_mass : dict
            the charge carrier effective mass in units of m_e, taking
            into account all bands, as opposed to the single parabolic
            band model.
            Data is a dictionary with an array each for n and p doping,
            of shape (temperatures, concentrations, 3, 3).
        conductivity : dict
            electric conductivity in S m-1.
            Data is a dictionary with an array each for n and p doping,
            of shape (temperatures, concentrations, 3, 3).
        doping : array-like
            carrier concentration in cm-1. Identical to input.
        electronic_thermal_conductivity : dict
            electronic thermal conductivity in W m-1 K-1.
            Data is a dictionary with an array each for n and p doping,
            of shape (temperatures, concentrations, 3, 3).
        fermi_level : dict
            fermi level at different temperatures in units of eV.
            Data is a dictionary with an array each for n and p doping,
            of shape (temperatures, concentrations).
        power_factor : dict
            power factor in W m-1 K-2.
            Data is a dictionary with an array each for n and p doping,
            of shape (temperatures, concentrations, 3, 3).
        seebeck : dict
            Seebeck coefficient in muV K-1.
            Data is a dictionary with an array each for n and p doping,
            of shape (temperatures, concentrations, 3, 3).
        temperature : numpy array
            temperatures in K.
        meta : dict
            metadata:

                interpolation_factor : int
                    lpfac.
                ke_mode : str
                    as input.
                relaxation_time : float
                    as input.
                soc : bool
                    spin-orbit coupling calculation.
                units : dict
                    units of each property above.
    """

    import h5py
    import os
    from pymatgen.electronic_structure.boltztrap \
         import BoltztrapRunner, BoltztrapAnalyzer, BoltztrapError
    from pymatgen.io.vasp.outputs import Vasprun
    from scipy import constants

    # check inputs

    for name, value in zip(['run', 'analyse'], [run, analyse]):
        assert isinstance(value, bool), '{} must be True or False'.format(name)

    ke_mode = ke_mode.lower()
    ke_modes = ['boltzmann', 'wiedemann', 'snyder']
    assert ke_mode in ke_modes, 'ke_mode must be {} or {}.'.format(
        ', '.join(ke_modes[:-1]), ke_modes[-1])

    tmax += tstep
    tmin = tstep if tmin is None else tmin
    temperature = np.arange(tmin, tmax, tstep)

    if run:  # run boltztrap from vasprun.xml -> boltztrap directory
        doping = np.array(doping)
        vr = Vasprun(vasprun, parse_potcar_file=False)
        soc = vr.as_dict()['input']['parameters']['LSORBIT']
        try:
            bs = vr.get_band_structure(line_mode=False)
            nelect = vr.parameters['NELECT']
            btr = BoltztrapRunner(bs,
                                  nelect,
                                  doping=list(doping),
                                  tmax=tmax,
                                  tgrid=tstep,
                                  soc=soc,
                                  lpfac=lpfac,
                                  **kwargs)
            print('Running Boltztrap...', end='')
            btr_dir = btr.run(path_dir='.')
            print('Done.')
        except BoltztrapError:
            bs = vr.get_band_structure(line_mode=True,
                                       kpoints_filename=kpoints)
            nelect = vr.parameters['NELECT']
            btr = BoltztrapRunner(bs,
                                  nelect,
                                  doping=list(doping),
                                  tmax=tmax,
                                  tgrid=tstep,
                                  soc=soc,
                                  lpfac=lpfac,
                                  **kwargs)
            btr_dir = btr.run(path_dir='.')
            print('Done.')
        """
        Detects whether the BoltzTraP build on this computer writes the
        doping concentrations correctly, and if it doesn't, writes them.
        """
        with open('boltztrap/boltztrap.outputtrans', 'r') as f:
            line = f.readlines()[-2]
        if len(line) >= 23 and line[:23] == ' Calling FermiIntegrals':
            with open(os.path.join(btr_dir, 'boltztrap.outputtrans'),
                      'a') as f:
                for i, x in enumerate(np.concatenate((doping, -doping))):
                    f.write(
                        'Doping level number {} n = {} carriers/cm3\n'.format(
                            i, x))

    else:
        btr_dir = 'boltztrap'

    if analyse:  # run boltztrap from boltztrap directory -> hdf5 file
        print('Analysing Boltztrap...', end='')
        bta = BoltztrapAnalyzer.from_files(btr_dir)
        print('Done.')

        data = {
            'average_eff_mass': {},
            'conductivity': {},
            'doping': doping,
            'electronic_thermal_conductivity': {},
            'power_factor': {},
            'seebeck': {},
            'temperature': temperature,
            'meta': {
                'units': {
                    'average_eff_mass': 'm_e',
                    'conductivity': 'S m-1',
                    'doping': 'cm-1',
                    'electronic_thermal_conductivity': 'W m-1 K-1',
                    'fermi_level': 'eV',
                    'power_factor': 'W m-1 K-2',
                    'seebeck': 'muV K-1',
                    'temperature': 'K'
                },
                'interpolation_factor': lpfac,
                'ke_mode': ke_mode,
                'relaxation_time': relaxation_time,
                'soc': soc
            }
        }

        # load data

        print('Calculating transport...', end='')
        c = bta._cond_doping
        dp = bta.doping
        e = constants.e
        f = bta.mu_doping
        k = bta._kappa_doping
        me = constants.m_e
        s = bta._seebeck_doping

        # calculate transport properties

        for d in ['n', 'p']:
            c[d] = np.array([c[d][t] for t in temperature])
            dp[d] = np.array(dp[d])
            k[d] = np.array([k[d][t] for t in temperature])
            f[d] = np.array([f[d][t] for t in temperature])
            s[d] = np.array([s[d][t] for t in temperature])

            data['average_eff_mass'][d] = np.linalg.inv(c[d]) \
                                        * dp[d][None, :, None, None] \
                                        * 1e6 * e ** 2 / me
            data['conductivity'][d] = np.multiply(c[d], relaxation_time)
            data['seebeck'][d] = np.multiply(s[d], 1e6)
            data['power_factor'][d] = tp.calculate.power_factor(
                data['conductivity'][d], data['seebeck'][d])
            if ke_mode == 'boltztrap':
                data['electronic_thermal_conductivity'][d] = \
                      k[d] * relaxation_time \
                      - data['power_factor'][d] * temperature[:,None,None,None]
            else:
                if ke_mode == 'wiedemann':
                    L = 2.44E-8
                else:
                    L = (1.5 +
                         np.exp(-np.abs(data['seebeck'][d]) / 116)) * 1e-8
                data['electronic_thermal_conductivity'][d] = \
                    L * data['conductivity'][d] * temperature[:,None,None,None]

        data['fermi_level'] = f
        print('Done.')

        tp.data.save.hdf5(data, output)

    return
示例#12
0
def process_data(bulk_per_atom,
                 parse_hkl=True,
                 path_to_fols=None,
                 hkl_dict=None,
                 parse_core_energy=False,
                 core_atom=None,
                 bulk_nn=None,
                 parse_vacuum=False,
                 save_csv=True,
                 csv_fname='data.csv',
                 **kwargs):
    """
    Parses the folders to collect all final data on relevant input and output 
    parameters, and optionally core and vacuum level energies. 

    If you are processing data for folder structures generated with 
    `generation` make sure you use `convergence.parse_fols` function. This 
    function is for parsing full sets of information from the output of 
    production run calculations. 

    The folder structure for parsing of data is fairly flexible and can be: 
    1. automatically parsed if `parse_hkl=True` - the function searches for 
    folders with names three digits long in cwd (default)
        e.g. it finds folders cwd/100 and cwd/010 that correspond to Miller 
        indices (1,0,0) and (0,1,0)
    2. automatically parsed from a specific working directory if `path_to_fols`
    is specified
    3. manually specified using `hkl_dict`, where the Miller index is mapped 
    directly to the path to where the files are. If you are only interested in 
    the specified folders, do not forget to change `parse_hkl=False`.
        e.g. hkl_dict = {(0,1,1): 'path/to/001/files/', 
                         (2,0,1): 'path/to/201/files/'}
    4. automatically parsed from cwd or a specific working directory in addition 
    to a defined `hkl_dict`

    Each of the folders must contain POSCAR and vasprun.xml files and optionally 
    LOCPOT (or potential.csv) and OUTCAR files if vacuum or core energy are 
    parsed. 

    The function returns None by default and saves the DataFrame to a csv file. 
    Optionally, it can return the DataFrame. 

    Args:
        bulk_per_atom (`float`): Bulk energy per atom in eV per atom. 
        parse_hkl (`bool`, optional): If ``True`` the script parses the names   
            of the folders to get the Miller indices. Defaults to ``True``.
        path_to_fols (`str`, optional): Path to where surfaxe should look for 
            the hkl folders are. Defaults to None which searches in cwd.     
        hkl_dict (`dict`, optional): dictionary of tuples of Miller indices 
            and paths to the folders the relevant outputs. Defaults to ``None``. 
            E.g. If the outputs of the calculations on the (1,-1,2) slab are in 
            folder ``path/to/folder/112``, the ``hkl_dict`` would be: 
            {(1,-1,2): 'path/to/folder/112'}
        parse_core_energy (`bool`, optional): If True the scripts attempts to 
            parse core energies from a supplied OUTCAR. Defaults to ``False``. 
        core_atom (`str`, optional): The symbol of atom the core state energy 
            level should be parsed from. Defaults to ``None``. 
        bulk_nn (`list`, optional): The symbols of the nearest neighbours of the 
            `core_atom`. Defaults to ``None``. 
        parse_vacuum (`bool`, optional): if ``True`` the script attempts 
            to parse LOCPOT using analysis.electrostatic_potential to use the 
            maximum value of planar potential as the vacuum energy level. 
            Defaults to ``True``. 
        save_csv (`bool`, optional): If ``True``, it writes data to a csv file.
            Defaults to ``True``.
        csv_fname (`str`, optional): The filename of the csv. Defaults to 
            data.csv 
    Returns: 
        DataFrame
    """
    # Check if hkl_dict is correctly set up
    if hkl_dict:
        for key, value in hkl_dict.items():
            if not isinstance(key, tuple):
                raise TypeError(
                    'The keys supplied to hkl_dict are not tuples.')
            if not isinstance(value, str):
                raise TypeError(
                    'The values supplied to hkl_dict are not strings.')

    cwd = os.getcwd()
    if path_to_fols:
        cwd = path_to_fols

    # Get the Miller indices as tuples and strings from folders in root dir
    if parse_hkl:
        if not hkl_dict:
            hkl_dict = {}
        for fol in os.listdir(cwd):
            if os.path.isdir(os.path.join(cwd, fol)) and len(fol)==3 and\
                fol.isdigit():
                hkl_dict[tuple(map(int, fol))] = os.path.join(cwd, fol)

    # Set up additional arguments for get_core_energy
    get_core_energy_kwargs = {
        'orbital': '1s',
        'ox_states': None,
        'nn_method': CrystalNN()
    }
    get_core_energy_kwargs.update(
        (k, kwargs[k]) for k in get_core_energy_kwargs.keys() & kwargs.keys())
    get_core = False
    if parse_core_energy:
        if core_atom is not None and bulk_nn is not None:
            get_core = True
        else:
            warnings.formatwarning = _custom_formatwarning
            warnings.warn(('Core atom or bulk nearest neighbours were not '
                           'supplied. Core energy will not be parsed.'))

    # For each miller index, check if the folders specified are there and
    # parse them for data
    df_list, electrostatic_list, core_energy_list = ([] for i in range(3))

    for hkl_tuple, path in hkl_dict.items():
        vsp_path = '{}/vasprun.xml'.format(path)
        psc_path = '{}/POSCAR'.format(path)
        vsp = Vasprun(vsp_path, parse_potcar_file=False)
        slab = slab_from_file(psc_path, hkl_tuple)
        vsp_dict = vsp.as_dict()

        df_list.append({
            'hkl':
            ''.join(map(str, hkl_tuple)),
            'hkl_tuple':
            hkl_tuple,
            'area':
            slab.surface_area,
            'atoms':
            vsp_dict['nsites'],
            'functional':
            vsp_dict['run_type'],
            'encut':
            vsp_dict['input']['incar']['ENCUT'],
            'algo':
            vsp_dict['input']['incar']['ALGO'],
            'ismear':
            vsp_dict['input']['parameters']['ISMEAR'],
            'sigma':
            vsp_dict['input']['parameters']['SIGMA'],
            'kpoints':
            vsp_dict['input']['kpoints']['kpoints'],
            'bandgap':
            vsp_dict['output']['bandgap'],
            'slab_energy':
            vsp_dict['output']['final_energy'],
            'slab_per_atom':
            vsp_dict['output']['final_energy_per_atom']
        })

        if parse_vacuum:
            electrostatic_list.append(vacuum(path))

        if get_core:
            otc_path = '{}/OUTCAR'.format(path)
            core_energy_list.append(
                core_energy(core_atom,
                            bulk_nn,
                            outcar=otc_path,
                            structure=psc_path,
                            **get_core_energy_kwargs))

    df = pd.DataFrame(df_list)
    df['surface_energy'] = ((df['slab_energy'] - bulk_per_atom * df['atoms']) /
                            (2 * df['area']) * 16.02)
    df['surface_energy_ev'] = (
        (df['slab_energy'] - bulk_per_atom * df['atoms']) / (2 * df['area']))

    if electrostatic_list:
        df['vacuum_potential'] = electrostatic_list

    if core_energy_list:
        df['core_energy'] = core_energy_list

    # Save to csv or return DataFrame
    if save_csv:
        if not csv_fname.endswith('.csv'):
            csv_fname += '.csv'
        df.to_csv(csv_fname, header=True, index=False)
    else:
        return df
示例#13
0
def _mp_helper_energy(parse_vacuum,
                      get_core,
                      hkl,
                      path,
                      slab_thickness,
                      vac_thickness,
                      slab_index,
                      core_atom=None,
                      bulk_nn=None,
                      **kwargs):
    """
    Helper function for multiprocessing, returns a list of lists of the main 
    extracted data, electrostatic potential and core energies
    Same args as for parse_fols, only that path is the path to the folder in 
    which the vasprun and OUTCAR for the specific slab/vacuum/index slab are. 
    """
    df_list, electrostatic_list, core_energy_list, gradient_list = (
        [] for i in range(4))

    # instantiate structure, slab, vasprun and outcar objects
    vsp_path = '{}/vasprun.xml'.format(path)
    otc_path = '{}/OUTCAR'.format(path)
    vsp = Vasprun(vsp_path, parse_potcar_file=False)
    otc = Outcar(otc_path)
    slab = slab_from_file(vsp.final_structure, hkl)
    vsp_dict = vsp.as_dict()

    # extract the time data
    otc_times = otc.run_stats

    df_list.append({
        'hkl_string': ''.join(map(str, hkl)),
        'hkl_tuple': hkl,
        'slab_thickness': slab_thickness,
        'vac_thickness': vac_thickness,
        'slab_index': slab_index,
        'atoms': vsp_dict['nsites'],
        'area': slab.surface_area,
        'bandgap': vsp_dict['output']['bandgap'],
        'slab_energy': vsp_dict['output']['final_energy'],
        'slab_per_atom': vsp_dict['output']['final_energy_per_atom'],
        'time_taken': otc_times['Elapsed time (sec)']
    })

    if parse_vacuum:
        electrostatic_list.append(vacuum(path))

        lpt = '{}/LOCPOT'.format(path)
        p = electrostatic_potential(lpt, save_plt=False, save_csv=False)
        # gradient in eV
        g = p['gradient'].to_numpy()
        ratio = int(vac_thickness) / (int(vac_thickness) + int(slab_thickness))
        # check if slab is centred so can get the gradient
        if 0.45 < slab.center_of_mass[2] < 0.55:
            # divide by 2 bc two regions, 0.75 is a scaling factor that
            # should hopefully work to avoid any charge from dangling
            # bonds?
            a = int(len(g) * ratio / 2 * 0.75)
            gradient_list.append(np.mean(g[:a]) * 1000)

        else:
            a = int(len(g) * ratio * 0.75)
            # if atoms are more towards the end of the slab, the start
            # should be vacuum
            if slab.center_of_mass[2] > 0.5:
                gradient_list.append(np.mean(g[:a]) * 1000)
            # and then if atoms are at the start, the vacuum is at
            # the end
            else:
                gradient_list.append(np.mean(g[(len(g) - a):]) * 1000)

    if get_core:
        core_energy_list.append(
            core_energy(core_atom,
                        bulk_nn,
                        outcar=otc_path,
                        structure=slab,
                        **kwargs))

    return [df_list, electrostatic_list, core_energy_list, gradient_list]
#!/shared/apps/.intel/2019/python/3.6.8/bin/python

import numpy as np
import matplotlib.pyplot as plt
from pymatgen.io.vasp.outputs import Vasprun

vaspout = Vasprun("./vasprun.xml")
vaspout_dict = vaspout.as_dict()
incar_input = vaspout.incar
print('')
if 'LOPTICS' in incar_input:
    if incar_input['LOPTICS'] == True:
        print('"LOPTICS = .TRUE." found in INCAR \n')
        epsilon = vaspout.dielectric
        real_part_0 = epsilon[1][0]
        print('Real part of dielectric function at 0 frequency:')
        print(real_part_0)
        print('')
if 'LEPSILON' in incar_input:
    if incar_input['LEPSILON'] == True:        
        print('"LEPSILON = .TRUE." found in INCAR \n')
        if incar_input['IBRION'] == 8:
            print('"IBRION = 8" found in INCAR \n')
        epsilon_static = vaspout.epsilon_static
        print('Macroscopic static dielectric tensor:')
        print(epsilon_static)
        print('')



示例#15
0
    def fetch_cached(self, candidate_data):
        """
        Fetches cached data based on candidate data

        Args:
            candidate_data (pd.DataFrame): Pandas dataframe

        Returns:
            (pandas.DataFrame) dataframe with data filled out

        """
        tri_path = os.environ.get("TRI_PATH")
        tri_bucket = os.environ.get("TRI_BUCKET")
        s3_client = boto3.client("s3")
        cached_experiments = pd.DataFrame()
        for structure_id, row in candidate_data.iterrows():
            calc_path = os.path.join(self.parent_dir,
                                     get_chemsys(row['structure']),
                                     structure_id.replace('-', ''), "_1/")
            # Scrub tri_path and replace model with simulation
            # to get s3 key
            calc_path = calc_path.replace(tri_path + '/', "")
            calc_path = calc_path.replace('model', 'simulation')
            with ScratchDir('.'):
                # Figure out whether prior submission exists
                response = s3_client.list_objects_v2(Bucket=tri_bucket,
                                                     Prefix=calc_path,
                                                     Delimiter='/')
                if response.get('Contents'):
                    cached_experiments = cached_experiments.append(row)
                    # TODO: figure out whether file exists in s3
                    # TODO: this is a little crude, could use boto3
                    try:
                        # import pdb; pdb.set_trace()
                        vr_path = os.path.join(calc_path, "static",
                                               "vasprun.xml")
                        cmd = "aws s3 cp s3://{}/{} .".format(
                            tri_bucket, vr_path)
                        subprocess.call(shlex.split(cmd))
                        vr = Vasprun("vasprun.xml")
                        vr_dict = vr.as_dict()
                        delta_e = get_qmpy_formation_energy(
                            vr_dict["output"]["final_energy_per_atom"],
                            vr_dict["pretty_formula"],
                            1,
                        )
                        data = {
                            "status": "SUCCEEDED",
                            "error": None,
                            "result": vr,
                            "delta_e": delta_e,
                        }
                    except Exception as e:
                        error_doc = {}
                        try:
                            err_obj = s3_client.get_object(Bucket=tri_bucket,
                                                           Key=os.path.join(
                                                               calc_path,
                                                               'err'))
                            errtxt = err_obj['Body'].read().decode('utf-8')
                            error_doc.update({"mc1_stderr": errtxt})
                        except ClientError:
                            print('No error file for {}'.format(calc_path))
                        error_doc.update({
                            "camd_exception":
                            "{}".format(e),
                            "camd_traceback":
                            traceback.format_exc(),
                        })
                        # Dump error docs to avoid Pandas issues with dict values
                        data = {
                            "status": "FAILED",
                            "error": json.dumps(error_doc)
                        }
                    update_dataframe_row(cached_experiments,
                                         structure_id,
                                         data,
                                         add_columns=True)
        return cached_experiments
示例#16
0
def parse_energies(hkl,
                   bulk_per_atom,
                   path_to_fols=None,
                   parse_core_energy=False,
                   core_atom=None,
                   bulk_nn=None,
                   parse_vacuum=False,
                   remove_first_energy=False,
                   plt_surfen=True,
                   plt_surfen_fname='surface_energy.png',
                   save_csv=True,
                   csv_fname=None,
                   verbose=False,
                   **kwargs):
    """
    Parses the convergence folders to get the surface energy, total energy,
    energy per atom, band gap and time taken for each slab and vacuum thickness
    combination. Calculates surface energies using Fiorentini-Methfessel and 
    Boettger methods. It can optionally parse vacuum and core level energies.

    ``path_to_fols`` specifies the parent directory containing subdirectories 
    that must include the miller index specified. e.g. if ``hkl=(0,0,1)`` there 
    must be a ``001/`` subdirectory present somewhere on the path. Each 
    directory within the subdirectory must contain a vasprun.xml and OUTCAR file.  

    Args:
        hkl (`tuple`): Miller index of the slab.
        bulk_per_atom (`float`): Bulk energy per atom from a converged 
            bulk calculation in eV per atom.
        path_to_fols (`str`, optional): Path to the convergence folders. 
            Defaults to None which is cwd
        parse_core_energy (`bool`, optional): If ``True`` the script attempts to 
            parse core energies from a supplied OUTCAR. Defaults to ``False``. 
        core_atom (`str`, optional): The symbol of atom the core state energy 
            level should be parsed from. Defaults to ``None``. 
        bulk_nn (`list`, optional): The symbols of the nearest neighbours of the 
            `core_atom`. Defaults to ``None``. 
        parse_vacuum (`bool`, optional): if ``True`` the script attempts 
            to parse LOCPOT using analysis.electrostatic_potential to use the 
            max value of planar potential as the vacuum energy level (eV). 
            It also calculates the average gradient of the vacuum region (meV). Defaults to ``False``. 
        remove_first_energy (`bool`, optional): Remove the first data point in 
            calculation of Fiorentini-Metfessel and Boettger surface energy. 
            Use if the first energy is somewhat of an outlier.
        plt_surfen (`bool`, optional): Plots the surface energy. Defaults to 
            ``True``.
        plt_surfen_fname (`str`, optional): The name of the surface energy plot.
            Defaults to ``surface_energy.png``
        save_csv (`bool`, optional): Saves the csv. Defaults to ``True``.
        csv_fname (`str`, optional): Name of the csv file to save. Defaults to
            hkl_data.csv, where hkl are the miller indices.
        verbose (`bool`, optional): Whether or not to print extra info about the
            folders being parsed. Defaults to ``False``. 

    Returns:
        DataFrame 
    """

    # Update kwargs for core energy
    get_core_energy_kwargs = {
        'orbital': '1s',
        'ox_states': None,
        'nn_method': CrystalNN()
    }
    get_core_energy_kwargs.update(
        (k, kwargs[k]) for k in get_core_energy_kwargs.keys() & kwargs.keys())
    get_core = False
    if parse_core_energy:
        if core_atom is not None and bulk_nn is not None:
            get_core = True
        else:
            warnings.formatwarning = _custom_formatwarning
            warnings.warn(('Core atom or bulk nearest neighbours were not '
                           'supplied. Core energy will not be parsed.'))

    # Set directory
    cwd = os.getcwd() if path_to_fols is None else path_to_fols

    # Get all paths to slab_vac_index folders
    list_of_paths = []
    for root, fols, files in os.walk(cwd):
        for fol in fols:
            # Perform a loose check that we are looking in the right place,
            # also avoid .ipynb_checkpoint files
            if ''.join(map(str, hkl)) in root.split('/') and '.' not in fol:
                if len(fol.split('_')) == 3:
                    list_of_paths.append([
                        os.path.join(root, fol),
                        fol.split('_')[0],
                        fol.split('_')[1],
                        fol.split('_')[2]
                    ])
                    if verbose:
                        print(root, fol)

    if len(list_of_paths) > 20 and parse_core_energy:
        warnings.formatwarning = _custom_formatwarning
        warnings.warn(
            ('Determining core energies for {} slabs may be slow. '
             'Running on {} cores.').format(len(list_of_paths),
                                            multiprocessing.cpu_count()))

    # Check if multiple cores are available, iterate through paths to folders
    # and parse folders
    if multiprocessing.cpu_count() > 1:
        with multiprocessing.Pool() as pool:
            mp_list = pool.starmap(
                functools.partial(_mp_helper_energy,
                                  parse_vacuum,
                                  get_core,
                                  hkl,
                                  core_atom=core_atom,
                                  bulk_nn=bulk_nn,
                                  **get_core_energy_kwargs), list_of_paths)

        # len(mp_list) == len(list_of_paths), mp_list[0][0] the is main data
        # collected for the dataframe, mp_list[0][1] are the potentials,
        # mp_list[0][2] are the core energies
        df_list = list(itertools.chain.from_iterable([i[0] for i in mp_list]))
        electrostatic_list = list(
            itertools.chain.from_iterable([i[1] for i in mp_list]))
        core_energy_list = list(
            itertools.chain.from_iterable([i[2] for i in mp_list]))
        gradient_list = list(
            itertools.chain.from_iterable([i[3] for i in mp_list]))

    else:
        df_list, electrostatic_list, core_energy_list, gradient_list = (
            [] for i in range(4))
        for path, slab_thickness, vac_thickness, slab_index in list_of_paths:
            vsp_path = '{}/vasprun.xml'.format(path)
            otc_path = '{}/OUTCAR'.format(path)

            # instantiate structure, slab, vasprun and outcar objects
            vsp = Vasprun(vsp_path, parse_potcar_file=False)
            otc = Outcar(otc_path)
            slab = slab_from_file(vsp.final_structure, hkl)
            vsp_dict = vsp.as_dict()

            # extract the time data
            otc_times = otc.run_stats

            df_list.append({
                'hkl_string':
                ''.join(map(str, hkl)),
                'hkl_tuple':
                hkl,
                'slab_thickness':
                slab_thickness,
                'vac_thickness':
                vac_thickness,
                'slab_index':
                slab_index,
                'atoms':
                vsp_dict['nsites'],
                'area':
                slab.surface_area,
                'bandgap':
                vsp_dict['output']['bandgap'],
                'slab_energy':
                vsp_dict['output']['final_energy'],
                'slab_per_atom':
                vsp_dict['output']['final_energy_per_atom'],
                'time_taken':
                otc_times['Elapsed time (sec)']
            })

            if parse_vacuum:
                # get value of potential in vacuum
                electrostatic_list.append(vacuum(path))

                lpt = '{}/LOCPOT'.format(path)
                p = electrostatic_potential(lpt,
                                            save_plt=False,
                                            save_csv=False)
                # gradient in eV
                g = p['gradient'].to_numpy()
                ratio = int(vac_thickness) / (int(vac_thickness) +
                                              int(slab_thickness))
                # check if slab is centred so can get the gradient
                if 0.45 < slab.center_of_mass[2] < 0.55:
                    # divide by 2 bc two regions, 0.75 is a scaling factor that
                    # should hopefully work to avoid any charge from dangling
                    # bonds?
                    # mean is in meV
                    a = int(len(g) * ratio / 2 * 0.75)
                    gradient_list.append(np.mean(g[:a]) * 1000)

                else:
                    a = int(len(g) * ratio * 0.75)
                    # if atoms are more towards the end of the slab, the start
                    # should be vacuum
                    if slab.center_of_mass[2] > 0.5:
                        gradient_list.append(np.mean(g[:a]) * 1000)  # meV
                    # and then if atoms are at the start, the vacuum is at
                    # the end
                    else:
                        gradient_list.append(np.mean(g[(len(g) - a):]) * 1000)

            if get_core:
                core_energy_list.append(
                    core_energy(core_atom,
                                bulk_nn,
                                outcar=otc_path,
                                structure=slab,
                                **get_core_energy_kwargs))

    df = pd.DataFrame(df_list)

    if electrostatic_list:
        df['vacuum_potential'] = electrostatic_list

    if gradient_list:
        df['vacuum_gradient'] = gradient_list  # in meV

    if core_energy_list:
        df['core_energy'] = core_energy_list

    df['surface_energy'] = ((df['slab_energy'] - bulk_per_atom * df['atoms']) /
                            (2 * df['area']) * 16.02)

    # Add Fiorentini-Methfessel and Boettger methods for calculating
    # surface energies
    dfs = []
    for index in df.groupby('slab_index'):
        df_index = index[1].sort_values('vac_thickness')
        for group in df_index.groupby('vac_thickness'):
            df2 = group[1].sort_values('slab_thickness')
            # deepcopy to keep it fresh
            df3 = copy.deepcopy(df2)
            # Fiorentini-methfessel
            # remove first data point if it's too much of an outlier and there are
            # more than three data points
            if remove_first_energy and len(df2['atoms']) >= 3:
                x = np.delete(df2['atoms'].to_numpy(), 0).reshape(-1, 1)
                y = np.delete(df2['slab_energy'].to_numpy(), 0)
            else:
                x = df2['atoms'].to_numpy().reshape(-1, 1)
                y = df2['slab_energy'].to_numpy()

            model = LinearRegression().fit(x, y)
            df3['surface_energy_fm'] = (
                (df3['slab_energy'] - model.coef_ * df3['atoms']) /
                (2 * df3['area']) * 16.02)

            # Boettger
            # new dataframe, just in case
            df4 = group[1].sort_values('slab_thickness')
            if remove_first_energy and len(df4['atoms']) >= 3:
                # big energy = M+1 layers energy, small energy = M layers,
                # calculating bulk energy for M layers
                # remove first two from M+1 energy, add a nan in place of one and
                # at the end; also replace the first from the M energies with nan;
                # same with atoms
                big_energy = df4['slab_energy'].iloc[2:].to_numpy()
                big_energy = np.append(big_energy, np.nan)
                big_energy = np.insert(big_energy, 0, np.nan)

                small_energy = df4['slab_energy'].iloc[1:].to_numpy()
                small_energy = np.insert(small_energy, 0, np.nan)

                big_atoms = df4['atoms'].iloc[2:].to_numpy()
                big_atoms = np.append(big_atoms, np.nan)
                big_atoms = np.insert(big_atoms, 0, np.nan)
                small_atoms = df4['atoms'].astype('float').iloc[1:].to_numpy()
                small_atoms = np.insert(small_atoms, 0, np.nan)

            else:
                # need to remove the first from big energy and add a nan at the end
                big_energy = df4['slab_energy'].iloc[1:].to_numpy()
                big_energy = np.append(big_energy, np.nan)

                small_energy = df4['slab_energy'].to_numpy()

                big_atoms = df4['atoms'].iloc[1:].to_numpy()
                big_atoms = np.append(big_atoms, np.nan)
                small_atoms = df4['atoms'].to_numpy()

            # difference M+1 - M, get bulk energy from E(M+1)-E(M) / (M+1)-M
            diff_energy = big_energy - small_energy
            diff_atoms = big_atoms - small_atoms
            bulk_energies = diff_energy / diff_atoms
            # make last energy a nan to get a nan surface energy

            small_energy[-1] = np.nan

            df3['surface_energy_boettger'] = (
                (small_energy - df3['atoms'] * bulk_energies) /
                (2 * df3['area']) * 16.02)

            dfs.append(df3)

    # Concat list back to one dataframe
    df = pd.concat(dfs)

    if remove_first_energy and len(df2['atoms']) < 3:
        warnings.formatwarning = _custom_formatwarning
        warnings.warn('First data point was not removed - less than three '
                      'data points were present in dataset')

    # Plot surface energy
    plt_kwargs = {'colors': None, 'width': 6, 'height': 5}
    plt_kwargs.update(
        (k, kwargs[k]) for k in plt_kwargs.keys() & kwargs.keys())

    if plt_surfen:
        plot_surfen(df, plt_fname=plt_surfen_fname, **plt_kwargs)

    # Save the csv or return the dataframe
    if save_csv:
        csv_fname = '{}_data.csv'.format(''.join(map(
            str, hkl))) if csv_fname is None else csv_fname
        if not csv_fname.endswith('.csv'):
            csv_fname += '.csv'

        df.to_csv(csv_fname, header=True, index=False)

    else:
        return df
print('Phase  total energy p.f.u.\n')

for dir in list_dir:

    path = os.path.dirname(dir)
    # identifying last folder of path
    subfold = os.path.basename(path)
    # getting name for the phase from the directory name
    phase = subfold

    # build path of OUTCAR file
    path_vasprun = (dir + 'vasprun.xml')
    vasprun = Vasprun(path_vasprun)
    # getting total energy PER FORMULA UNIT
    total_energy = vasprun.final_energy
    vasprun_dict = vasprun.as_dict()
    # n° atoms in calculation
    nsites = vasprun_dict['nsites']
    # dictionary for reduced cell composition
    reduced_cell_formula = vasprun_dict['reduced_cell_formula']
    # n° atoms per formula unit
    nsites_pfu = 0
    for el in reduced_cell_formula:
        nsites_pfu += reduced_cell_formula[el]
    # n° of formula units in calculation
    n_formula_units = nsites / nsites_pfu
    total_energy_pfu = total_energy / n_formula_units

    # writing computed phases dictionary
    computed_phases.update({phase: total_energy_pfu})
示例#18
0
    def test_properties(self):

        filepath = os.path.join(test_dir, 'vasprun.xml.nonlm')
        vasprun = Vasprun(filepath, parse_potcar_file=False)
        orbs = list(vasprun.complete_dos.pdos[vasprun.final_structure[
            0]].keys())
        self.assertIn(OrbitalType.s, orbs)
        filepath = os.path.join(test_dir, 'vasprun.xml')
        vasprun = Vasprun(filepath, parse_potcar_file=False)

        #Test NELM parsing.
        self.assertEqual(vasprun.parameters["NELM"], 60)
        #test pdos parsing

        pdos0 = vasprun.complete_dos.pdos[vasprun.final_structure[0]]
        self.assertAlmostEqual(pdos0[Orbital.s][Spin.up][16], 0.0026)
        self.assertAlmostEqual(pdos0[Orbital.pz][Spin.down][16], 0.0012)
        self.assertEqual(pdos0[Orbital.s][Spin.up].shape, (301, ))


        filepath2 = os.path.join(test_dir, 'lifepo4.xml')
        vasprun_ggau = Vasprun(filepath2, parse_projected_eigen=True,
                               parse_potcar_file=False)
        totalscsteps = sum([len(i['electronic_steps'])
                            for i in vasprun.ionic_steps])
        self.assertEqual(29, len(vasprun.ionic_steps))
        self.assertEqual(len(vasprun.structures), len(vasprun.ionic_steps))
        self.assertEqual(vasprun.lattice,
                         vasprun.lattice_rec.reciprocal_lattice)

        for i, step in enumerate(vasprun.ionic_steps):
            self.assertEqual(vasprun.structures[i], step["structure"])

        self.assertTrue(all([vasprun.structures[i] == vasprun.ionic_steps[i][
            "structure"] for i in range(len(vasprun.ionic_steps))]))

        self.assertEqual(308, totalscsteps,
                         "Incorrect number of energies read from vasprun.xml")

        self.assertEqual(['Li'] + 4 * ['Fe'] + 4 * ['P'] + 16 * ["O"],
                         vasprun.atomic_symbols)
        self.assertEqual(vasprun.final_structure.composition.reduced_formula,
                         "LiFe4(PO4)4")
        self.assertIsNotNone(vasprun.incar, "Incar cannot be read")
        self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read")
        self.assertIsNotNone(vasprun.eigenvalues, "Eigenvalues cannot be read")
        self.assertAlmostEqual(vasprun.final_energy, -269.38319884, 7)
        self.assertAlmostEqual(vasprun.tdos.get_gap(), 2.0589, 4)
        expectedans = (2.539, 4.0906, 1.5516, False)
        (gap, cbm, vbm, direct) = vasprun.eigenvalue_band_properties
        self.assertAlmostEqual(gap, expectedans[0])
        self.assertAlmostEqual(cbm, expectedans[1])
        self.assertAlmostEqual(vbm, expectedans[2])
        self.assertEqual(direct, expectedans[3])
        self.assertFalse(vasprun.is_hubbard)
        self.assertEqual(vasprun.potcar_symbols,
                         ['PAW_PBE Li 17Jan2003', 'PAW_PBE Fe 06Sep2000',
                          'PAW_PBE Fe 06Sep2000', 'PAW_PBE P 17Jan2003',
                          'PAW_PBE O 08Apr2002'])
        self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read")
        self.assertIsNotNone(vasprun.actual_kpoints,
                             "Actual kpoints cannot be read")
        self.assertIsNotNone(vasprun.actual_kpoints_weights,
                             "Actual kpoints weights cannot be read")
        for atomdoses in vasprun.pdos:
            for orbitaldos in atomdoses:
                self.assertIsNotNone(orbitaldos, "Partial Dos cannot be read")

        # test skipping ionic steps.
        vasprun_skip = Vasprun(filepath, 3, parse_potcar_file=False)
        self.assertEqual(vasprun_skip.nionic_steps, 29)
        self.assertEqual(len(vasprun_skip.ionic_steps),
                         int(vasprun.nionic_steps / 3) + 1)
        self.assertEqual(len(vasprun_skip.ionic_steps),
                         len(vasprun_skip.structures))
        self.assertEqual(len(vasprun_skip.ionic_steps),
                         int(vasprun.nionic_steps / 3) + 1)
        # Check that nionic_steps is preserved no matter what.
        self.assertEqual(vasprun_skip.nionic_steps,
                         vasprun.nionic_steps)

        self.assertNotAlmostEqual(vasprun_skip.final_energy,
                                  vasprun.final_energy)

        # Test with ionic_step_offset
        vasprun_offset = Vasprun(filepath, 3, 6, parse_potcar_file=False)
        self.assertEqual(len(vasprun_offset.ionic_steps),
                         int(len(vasprun.ionic_steps) / 3) - 1)
        self.assertEqual(vasprun_offset.structures[0],
                         vasprun_skip.structures[2])

        self.assertTrue(vasprun_ggau.is_hubbard)
        self.assertEqual(vasprun_ggau.hubbards["Fe"], 4.3)
        self.assertAlmostEqual(vasprun_ggau.projected_eigenvalues[(Spin.up, 0,
                                                                   0, 96,
                                                                   Orbital.s)],
                               0.0032)
        d = vasprun_ggau.as_dict()
        self.assertEqual(d["elements"], ["Fe", "Li", "O", "P"])
        self.assertEqual(d["nelements"], 4)

        filepath = os.path.join(test_dir, 'vasprun.xml.unconverged')
        with warnings.catch_warnings(record=True) as w:
            # Cause all warnings to always be triggered.
            warnings.simplefilter("always")
            # Trigger a warning.
            vasprun_unconverged = Vasprun(filepath, parse_potcar_file=False)
            # Verify some things
            self.assertEqual(len(w), 1)
            self.assertTrue(issubclass(w[-1].category,
                                       UnconvergedVASPWarning))

            self.assertTrue(vasprun_unconverged.converged_ionic)
            self.assertFalse(vasprun_unconverged.converged_electronic)
            self.assertFalse(vasprun_unconverged.converged)

        filepath = os.path.join(test_dir, 'vasprun.xml.dfpt')
        vasprun_dfpt = Vasprun(filepath, parse_potcar_file=False)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][0], 3.26105533)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][1], -0.00459066)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static[2][2], 3.24330517)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][0], 3.33402531)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][1], -0.00559998)
        self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[2][2], 3.31237357)
        self.assertTrue(vasprun_dfpt.converged)

        entry = vasprun_dfpt.get_computed_entry()
        entry = MaterialsProjectCompatibility(check_potcar_hash=False).process_entry(entry)
        self.assertAlmostEqual(entry.uncorrected_energy + entry.correction,
                               entry.energy)


        filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.ionic')
        vasprun_dfpt_ionic = Vasprun(filepath, parse_potcar_file=False)
        self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][0], 515.73485838)
        self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][1], -0.00263523)
        self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[2][2], 19.02110169)


        filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.unconverged')
        vasprun_dfpt_unconv = Vasprun(filepath, parse_potcar_file=False)
        self.assertFalse(vasprun_dfpt_unconv.converged_electronic)
        self.assertTrue(vasprun_dfpt_unconv.converged_ionic)
        self.assertFalse(vasprun_dfpt_unconv.converged)

        vasprun_uniform = Vasprun(os.path.join(test_dir, "vasprun.xml.uniform"),
                                  parse_potcar_file=False)
        self.assertEqual(vasprun_uniform.kpoints.style,
                         Kpoints.supported_modes.Reciprocal)


        vasprun_no_pdos = Vasprun(os.path.join(test_dir, "Li_no_projected.xml"),
                                  parse_potcar_file=False)
        self.assertIsNotNone(vasprun_no_pdos.complete_dos)
        self.assertFalse(vasprun_no_pdos.dos_has_errors)

        vasprun_diel = Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric"),
                               parse_potcar_file=False)
        self.assertAlmostEqual(0.4294,vasprun_diel.dielectric[0][10])
        self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][0])
        self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][1])
        self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][2])
        self.assertAlmostEqual(0.0,vasprun_diel.dielectric[1][51][3])
        self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][0])
        self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][1])
        self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][2])
        self.assertAlmostEqual(0.0,vasprun_diel.dielectric[2][85][3])

        v = Vasprun(os.path.join(test_dir, "vasprun.xml.indirect.gz"))
        (gap, cbm, vbm, direct) = v.eigenvalue_band_properties
        self.assertFalse(direct)
def get_dos(vasprun_dos):
    ## get CompleteDos object and "save" in hidden div in json format
    dos = Vasprun(vasprun_dos).complete_dos
    return json.dumps(dos.as_dict())