Exemplo n.º 1
0
    def eos_fit(self, eos_name="murnaghan"):
        """
        Fit E(V)
        For the list of available models, see EOS.MODELS

        TODO: which default? all should return a list of fits
        """
        # Read volumes and energies from the GSR files.
        energies, volumes = [], []
        for label, gsr in self:
            energies.append(gsr.energy)
            volumes.append(gsr.structure.volume)

        # Note that eos.fit expects lengths in Angstrom, and energies in eV.
        if eos_name != "all":
            return EOS(eos_name=eos_name).fit(volumes, energies)
        else:
            # Use all the available models.
            fits, rows = [], []
            for eos_name in EOS.MODELS:
                fit = EOS(eos_name=eos_name).fit(volumes, energies)
                fits.append(fit)
                rows.append(fit.results)

            import pandas as pd
            frame = pd.DataFrame(rows, index=EOS.MODELS, columns=list(rows[0].keys()))
            return fits, frame
Exemplo n.º 2
0
    def getnwrite_eosdata(self, write_json=True):
        """
        This method is called when all tasks reach S_OK. It reads the energies
        and the volumes from the GSR file, computes the EOS and produce a
        JSON file `eos_data.json` in outdata.
        """
        energies_ev, volumes = [], []
        for task in self:
            with task.open_gsr() as gsr:
                volumes.append(float(gsr.structure.volume))
                energies_ev.append(float(gsr.energy))

        from pymatgen.analysis.eos import EOS
        eos_data = {
            "input_volumes_ang3": self.input_volumes,
            "volumes_ang3": volumes,
            "energies_ev": energies_ev
        }

        for model in EOS.MODELS:
            if model in ("deltafactor", "numerical_eos"): continue
            try:
                fit = EOS(model).fit(volumes, energies_ev)
                eos_data[model] = {k: float(v) for k, v in fit.results.items()}
            except Exception as exc:
                eos_data[model] = {"exception": str(exc)}

        if write_json:
            with open(self.outdir.path_in("eos_data.json"), "wt") as fh:
                json.dump(eos_data, fh, indent=4, sort_keys=True)

        return eos_data
Exemplo n.º 3
0
    def __init__(self, energies, volumes, structure, t_min=5, t_step=5,
                 t_max=2000.0, eos="vinet", poisson=0.363615,
                 gruneisen=True, bp2gru=1., mass_average_mode='arithmetic'):
        self.energies = energies
        self.volumes = volumes
        self.structure = structure
        self.temperatures = np.arange(t_min, t_max+t_step, t_step)
        self.eos_name = eos
        self.poisson = poisson
        self.bp2gru = bp2gru
        self.gruneisen = gruneisen
        self.natoms = self.structure.composition.num_atoms
        self.kb = physical_constants["Boltzmann constant in eV/K"][0]
        # calculate the average masses
        masses = np.array([e.atomic_mass for e in self.structure.species]) * physical_constants["atomic mass constant"][0]
        if mass_average_mode == 'arithmetic':
            self.avg_mass = np.mean(masses)
        elif mass_average_mode == 'geometric':
            self.avg_mass = gmean(masses)
        else:
            raise ValueError("DebyeModel mass_average_mode must be either 'arithmetic' or 'geometric'")
        # fit E and V and get the bulk modulus(used to compute the Debye temperature)
        self.eos = EOS(eos)
        self.ev_eos_fit = self.eos.fit(volumes, energies)
        self.bulk_modulus = self.ev_eos_fit.b0_GPa  # in GPa

        self.calculate_F_el()
Exemplo n.º 4
0
    def birch_murnaghan(self, title=None):
        """
        Fit E,V data with Birch-Murnaghan EOS

        Parameters
        ----------
        title : (str)
            Plot title

        Returns
        -------
        plt :
            Matplotlib object.
        eos_fit : 
            Pymatgen EosBase object.
        """
        V, E = [], []
        for j in self.jobs:
            V.append(j.initial_structure.lattice.volume)
            E.append(j.final_energy)
        eos = EOS(eos_name='birch_murnaghan')
        eos_fit = eos.fit(V, E)
        eos_fit.plot(width=10,
                     height=10,
                     text='',
                     markersize=15,
                     label='Birch-Murnaghan fit')
        plt.legend(loc=2, prop={'size': 20})
        if title:
            plt.title(title, size=25)
        plt.tight_layout()

        return plt, eos_fit
Exemplo n.º 5
0
    def set_eos(self, eos_name):
        """
        Updates the EOS used for the fit.

        Args:
            eos_name: string indicating the expression used to fit the energies. See pymatgen.analysis.eos.EOS.
        """
        self.eos = EOS(eos_name)
Exemplo n.º 6
0
    def test_run_all_models(self):

        # these have been checked for plausibility,
        # but are not benchmarked against independently known values
        test_output = {
            "birch": {
                "b0": 0.5369258244952931,
                "b1": 4.178644231838501,
                "e0": -10.8428039082307,
                "v0": 40.98926572870838,
            },
            "birch_murnaghan": {
                "b0": 0.5369258245417454,
                "b1": 4.178644235500821,
                "e0": -10.842803908240892,
                "v0": 40.98926572528106,
            },
            "deltafactor": {
                "b0": 0.5369258245611414,
                "b1": 4.178644231924639,
                "e0": -10.842803908299294,
                "v0": 40.989265727927936,
            },
            "murnaghan": {
                "b0": 0.5144967693786603,
                "b1": 3.9123862262572264,
                "e0": -10.836794514626673,
                "v0": 41.13757930387086,
            },
            "numerical_eos": {
                "b0": 0.5557257614101998,
                "b1": 4.344039148405489,
                "e0": -10.847490826530702,
                "v0": 40.857200064982536,
            },
            "pourier_tarantola": {
                "b0": 0.5667729960804602,
                "b1": 4.331688936974368,
                "e0": -10.851486685041658,
                "v0": 40.86770643373908,
            },
            "vinet": {
                "b0": 0.5493839425156859,
                "b1": 4.3051929654936885,
                "e0": -10.846160810560756,
                "v0": 40.916875663779784,
            },
        }

        for eos_name in EOS.MODELS:
            eos = EOS(eos_name=eos_name)
            _ = eos.fit(self.volumes, self.energies)
            for param in ("b0", "b1", "e0", "b0"):
                # TODO: solutions only stable to 2 decimal places
                # between different machines, this seems far too low?
                self.assertArrayAlmostEqual(_.results[param],
                                            test_output[eos_name][param],
                                            decimal=1)
Exemplo n.º 7
0
    def get_eos_fits_dataframe(self, eos_names="murnaghan"):
        """
        Fit energy as function of volume to get the equation of state,
        equilibrium volume, bulk modulus and its derivative wrt to pressure.

        Args:
            eos_names: String or list of strings with EOS names.
                For the list of available models, see pymatgen.analysis.eos.

        Return:
            (fits, dataframe) namedtuple.
                fits is a list of ``EOSFit object``
                dataframe is a |pandas-DataFrame| with the final results.
        """
        # Read volumes and energies from the GSR files.
        energies, volumes = [], []
        for label, gsr in self.items():
            energies.append(float(gsr.energy))
            volumes.append(float(gsr.structure.volume))

        # Order data by volumes if needed.
        if np.any(np.diff(volumes) < 0):
            ves = sorted(zip(volumes, energies), key=lambda t: t[0])
            volumes = [t[0] for t in ves]
            energies = [t[1] for t in ves]

        # Note that eos.fit expects lengths in Angstrom, and energies in eV.
        # I'm also monkey-patching the plot method.
        from pymatgen.analysis.eos import EOS
        if eos_names == "all":
            # Use all the available models.
            eos_names = [
                n for n in EOS.MODELS
                if n not in ("deltafactor", "numerical_eos")
            ]
        else:
            eos_names = list_strings(eos_names)

        fits, index, rows = [], [], []
        for eos_name in eos_names:
            try:
                fit = EOS(eos_name=eos_name).fit(volumes, energies)
            except Exception as exc:
                cprint("EOS %s raised exception:\n%s" % (eos_name, str(exc)))
                continue

            # Replace plot with plot_ax method
            fit.plot = fit.plot_ax
            fits.append(fit)
            index.append(eos_name)
            rows.append(
                OrderedDict([(aname, getattr(fit, aname))
                             for aname in ("v0", "e0", "b0_GPa", "b1")]))

        dataframe = pd.DataFrame(
            rows, index=index, columns=list(rows[0].keys()) if rows else None)
        return dict2namedtuple(fits=fits, dataframe=dataframe)
Exemplo n.º 8
0
def gibbs_minimizer(energies,
                    volumes,
                    mass,
                    natoms,
                    temperature=298.0,
                    pressure=0,
                    poisson=0.25,
                    eos="murnaghan"):
    """
    Fit the input energies and volumes to the equation of state to obtain the bulk modulus which is
    subsequently used to obtain the debye temperature. The debye temperature is then used to compute
    the  vibrational free energy and the gibbs free energy as a function of volume, temperature and
    pressure. A second fit is preformed to get the functional form of gibbs free energy:(G, V, T, P).
    Finally G(V, P, T) is minimized with respect to V and the optimum value of G evaluated at V_opt,
    G_opt(V_opt, T, P), is returned.

    Args:
        energies (list): list of energies
        volumes (list): list of volumes
        mass (float): total mass
        natoms (int): number of atoms
        temperature (float): temperature in K
        pressure (float): pressure in GPa
        poisson (float): poisson ratio
        eos (str): name of the equation of state supported by pymatgen. See pymatgen.analysis.eos.py

    Returns:
        float: gibbs free energy at the given temperature and pressure minimized wrt volume.
    """
    try:
        from scipy.optimize import minimize
        from scipy.integrate import quadrature
    except ImportError:
        import sys
        print("Install scipy. Exiting.")
        sys.exit()

    integrator = quadrature

    eos = EOS(eos)
    eos_fit_1 = eos.fit(volumes, energies)
    G_V = []
    for i, v in enumerate(volumes):
        debye = debye_temperature_gibbs(v,
                                        mass,
                                        natoms,
                                        eos_fit_1.b0_GPa,
                                        poisson=poisson)
        G_V.append(energies[i] + pressure * v +
                   A_vib(temperature, debye, natoms, integrator))

    # G(V, T, P)
    eos_fit_2 = eos.fit(volumes, G_V)
    params = eos_fit_2.eos_params.tolist()
    # G_opt(V_opt, T, P)
    return params[0]
Exemplo n.º 9
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.")
Exemplo n.º 10
0
 def __init__(self, energies, volumes, structure, t_min=300.0, t_step=100,
              t_max=300.0, eos="vinet", pressure=0.0, poisson=0.25,
              use_mie_gruneisen=False, anharmonic_contribution=False):
     """
     Args:
         energies (list): list of DFT energies in eV
         volumes (list): list of volumes in Ang^3
         structure (Structure):
         t_min (float): min temperature
         t_step (float): temperature step
         t_max (float): max temperature
         eos (str): equation of state used for fitting the energies and the
             volumes.
             options supported by pymatgen: "quadratic", "murnaghan", "birch",
                 "birch_murnaghan", "pourier_tarantola", "vinet",
                 "deltafactor", "numerical_eos"
         pressure (float): in GPa, optional.
         poisson (float): poisson ratio.
         use_mie_gruneisen (bool): whether or not to use the mie-gruneisen
             formulation to compute the gruneisen parameter.
             The default is the slater-gamma formulation.
         anharmonic_contribution (bool): whether or not to consider the anharmonic
             contribution to the Debye temperature. Cannot be used with
             use_mie_gruneisen. Defaults to False.
     """
     self.energies = energies
     self.volumes = volumes
     self.structure = structure
     self.temperature_min = t_min
     self.temperature_max = t_max
     self.temperature_step = t_step
     self.eos_name = eos
     self.pressure = pressure
     self.poisson = poisson
     self.use_mie_gruneisen = use_mie_gruneisen
     self.anharmonic_contribution = anharmonic_contribution
     if self.use_mie_gruneisen and self.anharmonic_contribution:
         raise ValueError('The Mie-Gruneisen formulation and anharmonic contribution are circular referenced and '
                          'cannot be used together.')
     self.mass = sum([e.atomic_mass for e in self.structure.species])
     self.natoms = self.structure.composition.num_atoms
     self.avg_mass = physical_constants["atomic mass constant"][0] * self.mass / self.natoms  # kg
     self.kb = physical_constants["Boltzmann constant in eV/K"][0]
     self.hbar = physical_constants["Planck constant over 2 pi in eV s"][0]
     self.gpa_to_ev_ang = 1./160.21766208  # 1 GPa in ev/Ang^3
     self.gibbs_free_energy = []  # optimized values, eV
     # list of temperatures for which the optimized values are available, K
     self.temperatures = []
     self.optimum_volumes = []  # in Ang^3
     # fit E and V and get the bulk modulus(used to compute the Debye
     # temperature)
     logger.info("Fitting E and V")
     self.eos = EOS(eos)
     self.ev_eos_fit = self.eos.fit(volumes, energies)
     self.bulk_modulus = self.ev_eos_fit.b0_GPa  # in GPa
     self.optimize_gibbs_free_energy()
Exemplo n.º 11
0
Arquivo: eos.py Projeto: zbwang/abipy
    def OnFitButton(self, event):
        model = self.model_choice.GetStringSelection()

        try:
            eos = EOS(eos_name=model)
            fit = eos.fit(self.volumes, self.energies, vol_unit=self.vol_unit, ene_unit=self.ene_unit)
            print(fit)
            fit.plot()

        except:
            awx.showErrorMessage(self)
Exemplo n.º 12
0
    def __init__(self, structures, energies, eos_name='vinet', pressure=0):
        """
        Args:
            structures: list of structures at different volumes.
            energies: list of SCF energies for the structures in eV.
            eos_name: string indicating the expression used to fit the energies. See pymatgen.analysis.eos.EOS.
            pressure: value of the pressure in GPa that will be considered in the p*V contribution to the energy.
        """
        self.structures = structures
        self.energies = np.array(energies)
        self.eos = EOS(eos_name)
        self.pressure = pressure

        self.volumes = np.array([s.volume for s in structures])
        self.iv0 = np.argmin(energies)
Exemplo n.º 13
0
def test_eosfit_stderr():
    volume = [
        64.26025658624827, 66.6402902061661, 69.02026278463558,
        71.40028395651238, 73.7802955243384, 76.16031916837127,
        78.5402791170494, 80.94268976633485
    ]
    energy = [
        -34.69037673, -34.88126365, -34.98844492, -35.02444959, -34.99974727,
        -34.92873799, -34.8383195, -34.69550342
    ]
    eos = EOS('vinet')
    eos_fit = eos.fit(volume, energy)
    fit_value = eos_fit.func(volume)
    print(fit_value)
    stderr = eosfit_stderr(eos_fit, volume, energy)
    assert (stderr == pytest.approx(1.18844e-5, abs=1e-7))
Exemplo n.º 14
0
 def __init__(self,
              energies,
              volumes,
              structure,
              t_min=300.0,
              t_step=100,
              t_max=300.0,
              eos="vinet",
              pressure=0.0,
              poisson=0.25,
              use_mie_gruneisen=False,
              anharmonic_contribution=False):
     self.energies = energies
     self.volumes = volumes
     self.structure = structure
     self.temperature_min = t_min
     self.temperature_max = t_max
     self.temperature_step = t_step
     self.eos_name = eos
     self.pressure = pressure
     self.poisson = poisson
     self.use_mie_gruneisen = use_mie_gruneisen
     self.anharmonic_contribution = anharmonic_contribution
     if self.use_mie_gruneisen and self.anharmonic_contribution:
         raise ValueError(
             'The Mie-Gruneisen formulation and anharmonic contribution are circular referenced and cannot be used together.'
         )
     self.mass = sum([e.atomic_mass for e in self.structure.species])
     self.natoms = self.structure.composition.num_atoms
     self.avg_mass = physical_constants["atomic mass constant"][0] \
                     * self.mass / self.natoms  # kg
     self.kb = physical_constants["Boltzmann constant in eV/K"][0]
     self.hbar = physical_constants["Planck constant over 2 pi in eV s"][0]
     self.gpa_to_ev_ang = 1. / 160.21766208  # 1 GPa in ev/Ang^3
     self.gibbs_free_energy = []  # optimized values, eV
     # list of temperatures for which the optimized values are available, K
     self.temperatures = []
     self.optimum_volumes = []  # in Ang^3
     # fit E and V and get the bulk modulus(used to compute the Debye
     # temperature)
     print("Fitting E and V")
     self.eos = EOS(eos)
     self.ev_eos_fit = self.eos.fit(volumes, energies)
     self.bulk_modulus = self.ev_eos_fit.b0_GPa  # in GPa
     self.optimize_gibbs_free_energy()
    def __init__(self, energies, volumes, structure, dos_objects=None, F_vib=None, S_vib=None, C_vib=None,
                 t_min=5, t_step=5,
                 t_max=2000.0, eos="vinet", pressure=0.0, poisson=0.25,
                 bp2gru=1., vib_kwargs=None):
        self.energies = np.array(energies)
        self.volumes = np.array(volumes)
        self.natoms = len(structure)
        self.temperatures = np.arange(t_min, t_max+t_step, t_step)
        self.eos_name = eos
        self.pressure = pressure
        self.gpa_to_ev_ang = 1./160.21766208  # 1 GPa in ev/Ang^3
        self.eos = EOS(eos)

        # get the vibrational properties as a function of V and T
        if F_vib is None:  # use the Debye model
            vib_kwargs = vib_kwargs or {}
            debye_model = DebyeModel(energies, volumes, structure, t_min=t_min, t_step=t_step,
                                     t_max=t_max, eos=eos, poisson=poisson, bp2gru=bp2gru, **vib_kwargs)
            self.F_vib = debye_model.F_vib  # vibrational free energy as a function of volume and temperature
            self.S_vib = debye_model.S_vib  # vibrational entropy as a function of volume and temperature
            self.C_vib = debye_model.C_vib  # vibrational heat capacity as a function of volume and temperature
            self.D_vib = debye_model.D_vib  # Debye temperature
        else:
            self.F_vib = F_vib
            self.S_vib = S_vib
            self.C_vib = C_vib


        # get the electronic properties as a function of V and T
        if dos_objects:
            # we set natom to 1 always because we want the property per formula unit here.
            thermal_electronic_props = [calculate_thermal_electronic_contribution(dos, t0=t_min, t1=t_max, td=t_step, natom=1) for dos in dos_objects]
            self.F_el = [p['free_energy'] for p in thermal_electronic_props]
        else:
            self.F_el = np.zeros((self.volumes.size, self.temperatures.size))

        # Set up the array of Gibbs energies
        # G = E_0(V) + F_vib(V,T) + F_el(V,T) + PV
        self.G = self.energies[:, np.newaxis] + self.F_vib + self.F_el + self.pressure * self.volumes[:, np.newaxis] * self.gpa_to_ev_ang

        # set up the final variables of the optimized Gibbs energies
        self.gibbs_free_energy = []  # optimized values, eV
        self.optimum_volumes = []  # in Ang^3
        self.optimize_gibbs_free_energy()
Exemplo n.º 16
0
    def run_task(self, fw_spec):

        from pymatgen.analysis.eos import EOS

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

        mmdb = MMVaspDb.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()

        # 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)
        summary_dict["energies"] = energies
        summary_dict["volumes"] = volumes

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

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

        logger.info("BULK MODULUS CALCULATION COMPLETE")
Exemplo n.º 17
0
 def test_eos_func(self):
     # list vs np.array arguments
     np.testing.assert_almost_equal(self.num_eos_fit.func([0, 1, 2]),
                                    self.num_eos_fit.func(np.array([0, 1, 2])),
                                    decimal=10)
     # func vs _func
     np.testing.assert_almost_equal(self.num_eos_fit.func(0.),
                                    self.num_eos_fit._func(
                                        0., self.num_eos_fit.eos_params),
                                    decimal=10)
     # test the eos function: energy = f(volume)
     # numerical eos evaluated at volume=0 == a0 of the fit polynomial
     np.testing.assert_almost_equal(self.num_eos_fit.func(0.),
                                    self.num_eos_fit.eos_params[-1], decimal=6)
     birch_eos = EOS(eos_name="birch")
     birch_eos_fit = birch_eos.fit(self.volumes, self.energies)
     # birch eos evaluated at v0 == e0
     np.testing.assert_almost_equal(birch_eos_fit.func(birch_eos_fit.v0),
                                    birch_eos_fit.e0, decimal=6)
Exemplo n.º 18
0
 def setUp(self):
     # Si data from Cormac
     self.volumes = [
         25.987454833, 26.9045702104, 27.8430241908, 28.8029649591,
         29.7848370694, 30.7887887064, 31.814968055, 32.8638196693,
         33.9353435494, 35.0299842495, 36.1477417695, 37.2892088485,
         38.4543854865, 39.6437162376, 40.857201102, 42.095136449,
         43.3579668329, 44.6456922537, 45.9587572656, 47.2973100535,
         48.6614988019, 50.0517680652, 51.4682660281, 52.9112890601,
         54.3808371612, 55.8775030703, 57.4014349722, 58.9526328669
     ]
     self.energies = [
         -7.63622156576, -8.16831294894, -8.63871612686, -9.05181213218,
         -9.41170988374, -9.72238224345, -9.98744832526, -10.210309552,
         -10.3943401353, -10.5427238068, -10.6584266073, -10.7442240979,
         -10.8027285713, -10.8363890521, -10.8474912964, -10.838157792,
         -10.8103477586, -10.7659387815, -10.7066179666, -10.6339907853,
         -10.5495538639, -10.4546677714, -10.3506386542, -10.2386366017,
         -10.1197772808, -9.99504030111, -9.86535084973, -9.73155247952
     ]
     num_eos = EOS(eos_name="numerical_eos")
     self.num_eos_fit = num_eos.fit(self.volumes, self.energies)
Exemplo n.º 19
0
    def run_task(self, fw_spec):
        db_file = env_chk(self.get("db_file"), fw_spec)
        tag = self["tag"]
        vasp_db = VaspCalcDb.from_db_file(db_file, admin=True)
        static_calculations = vasp_db.collection.find({"metadata.tag": tag})

        energies = []
        volumes = []
        structure = None  # single Structure for QHA calculation
        for calc in static_calculations:
            energies.append(calc['output']['energy'])
            volumes.append(calc['output']['structure']['lattice']['volume'])
            if structure is None:
                structure = Structure.from_dict(calc['output']['structure'])

        eos = EOS(self.get('eos'))
        ev_eos_fit = eos.fit(volumes, energies)
        equil_volume = ev_eos_fit.v0

        structure.scale_lattice(equil_volume)

        analysis_result = ev_eos_fit.results
        analysis_result['b0_GPa'] = float(ev_eos_fit.b0_GPa)
        analysis_result['structure'] = structure.as_dict()
        analysis_result[
            'formula_pretty'] = structure.composition.reduced_formula
        analysis_result['metadata'] = self.get('metadata', {})
        analysis_result['energies'] = energies
        analysis_result['volumes'] = volumes

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

        vasp_db.db['eos'].insert_one(analysis_result)
Exemplo n.º 20
0
 def test_run_all_models(self):
     for eos_name in EOS.MODELS:
         eos = EOS(eos_name=eos_name)
         _ = eos.fit(self.volumes, self.energies)
Exemplo n.º 21
0
 def analyze_eos_flow(flow, **kwargs):
     work = flow[0]
     etotals = work.read_etotals(unit="eV")
     eos_fit = EOS(eos_name="birch_murnaghan").fit(flow.volumes, etotals)
     return eos_fit.plot(**kwargs)
Exemplo n.º 22
0
    def test_fitting(self):

        # courtesy of @katherinelatimer2013
        # known correct values for Vinet

        # Mg

        mp153_volumes = [
            16.69182365,
            17.25441763,
            17.82951915,
            30.47573817,
            18.41725977,
            29.65211363,
            28.84346369,
            19.01777055,
            28.04965916,
            19.63120886,
            27.27053682,
            26.5059864,
            20.25769112,
            25.75586879,
            20.89736201,
            25.02003097,
            21.55035204,
            24.29834347,
            22.21681221,
            23.59066888,
            22.89687316,
        ]

        mp153_energies = [
            -1.269884575,
            -1.339411225,
            -1.39879471,
            -1.424480995,
            -1.44884184,
            -1.45297499,
            -1.4796246,
            -1.49033594,
            -1.504198485,
            -1.52397006,
            -1.5264432,
            -1.54609291,
            -1.550269435,
            -1.56284009,
            -1.569937375,
            -1.576420935,
            -1.583470925,
            -1.58647189,
            -1.591436505,
            -1.592563495,
            -1.594347355,
        ]

        mp153_known_energies_vinet = [
            -1.270038831,
            -1.339366487,
            -1.398683238,
            -1.424556061,
            -1.448746649,
            -1.453000456,
            -1.479614511,
            -1.490266797,
            -1.504163502,
            -1.523910268,
            -1.526395734,
            -1.546038792,
            -1.550298657,
            -1.562800797,
            -1.570015274,
            -1.576368392,
            -1.583605186,
            -1.586404575,
            -1.591578378,
            -1.592547954,
            -1.594410995,
        ]

        # C: 4.590843262
        # B: 2.031381599
        mp153_known_e0_vinet = -1.594429229
        mp153_known_v0_vinet = 22.95764159

        eos = EOS(eos_name="vinet")

        fit = eos.fit(mp153_volumes, mp153_energies)

        np.testing.assert_array_almost_equal(fit.func(mp153_volumes),
                                             mp153_known_energies_vinet,
                                             decimal=5)

        self.assertAlmostEqual(mp153_known_e0_vinet, fit.e0, places=4)
        self.assertAlmostEqual(mp153_known_v0_vinet, fit.v0, places=4)

        # expt. value 35.5, known fit 36.16
        self.assertAlmostEqual(fit.b0_GPa, 36.16258687442761, 4)

        # Si

        mp149_volumes = [
            15.40611854,
            14.90378698,
            16.44439516,
            21.0636307,
            17.52829835,
            16.98058208,
            18.08767363,
            18.65882487,
            19.83693435,
            15.91961152,
            22.33987173,
            21.69548924,
            22.99688883,
            23.66666322,
            20.44414922,
            25.75374305,
            19.24187473,
            24.34931029,
            25.04496106,
            27.21116571,
            26.4757653,
        ]

        mp149_energies = [
            -4.866909695,
            -4.7120965,
            -5.10921253,
            -5.42036228,
            -5.27448405,
            -5.200810795,
            -5.331915665,
            -5.3744186,
            -5.420058145,
            -4.99862686,
            -5.3836163,
            -5.40610838,
            -5.353700425,
            -5.31714654,
            -5.425263555,
            -5.174988295,
            -5.403353105,
            -5.27481447,
            -5.227210275,
            -5.058992615,
            -5.118805775,
        ]

        mp149_known_energies_vinet = [
            -4.866834585,
            -4.711786499,
            -5.109642598,
            -5.420093739,
            -5.274605844,
            -5.201025714,
            -5.331899365,
            -5.374315789,
            -5.419671568,
            -4.998827503,
            -5.383703409,
            -5.406038887,
            -5.353926272,
            -5.317484252,
            -5.424963418,
            -5.175090887,
            -5.403166824,
            -5.275096644,
            -5.227427635,
            -5.058639193,
            -5.118654229,
        ]

        # C: 4.986513158
        # B: 4.964976215
        mp149_known_e0_vinet = -5.424963506
        mp149_known_v0_vinet = 20.44670279

        eos = EOS(eos_name="vinet")

        fit = eos.fit(mp149_volumes, mp149_energies)

        np.testing.assert_array_almost_equal(fit.func(mp149_volumes),
                                             mp149_known_energies_vinet,
                                             decimal=5)

        self.assertAlmostEqual(mp149_known_e0_vinet, fit.e0, places=4)
        self.assertAlmostEqual(mp149_known_v0_vinet, fit.v0, places=4)

        # expt. value 97.9, known fit 88.39
        self.assertAlmostEqual(fit.b0_GPa, 88.38629337404822, 4)

        # Ti

        mp72_volumes = [
            12.49233296,
            12.91339188,
            13.34380224,
            22.80836212,
            22.19195533,
            13.78367177,
            21.58675559,
            14.23310328,
            20.99266009,
            20.4095592,
            14.69220297,
            19.83736385,
            15.16106697,
            19.2759643,
            15.63980711,
            18.72525771,
            16.12851491,
            18.18514127,
            16.62729878,
            17.65550599,
            17.13626153,
        ]

        mp72_energies = [
            -7.189983803,
            -7.33985647,
            -7.468745423,
            -7.47892835,
            -7.54945107,
            -7.578012237,
            -7.61513166,
            -7.66891898,
            -7.67549721,
            -7.73000681,
            -7.74290386,
            -7.77803379,
            -7.801246383,
            -7.818964483,
            -7.84488189,
            -7.85211192,
            -7.87486651,
            -7.876767777,
            -7.892161533,
            -7.892199957,
            -7.897605303,
        ]

        mp72_known_energies_vinet = [
            -7.189911138,
            -7.339810181,
            -7.468716095,
            -7.478678021,
            -7.549402394,
            -7.578034391,
            -7.615240977,
            -7.669091347,
            -7.675683891,
            -7.730188653,
            -7.74314028,
            -7.778175824,
            -7.801363213,
            -7.819030923,
            -7.844878053,
            -7.852099741,
            -7.874737806,
            -7.876686864,
            -7.891937429,
            -7.892053535,
            -7.897414664,
        ]

        # C: 3.958192998
        # B: 6.326790098
        mp72_known_e0_vinet = -7.897414997
        mp72_known_v0_vinet = 17.13223229

        eos = EOS(eos_name="vinet")

        fit = eos.fit(mp72_volumes, mp72_energies)

        np.testing.assert_array_almost_equal(fit.func(mp72_volumes),
                                             mp72_known_energies_vinet,
                                             decimal=5)

        self.assertAlmostEqual(mp72_known_e0_vinet, fit.e0, places=4)
        self.assertAlmostEqual(mp72_known_v0_vinet, fit.v0, places=4)

        # expt. value 107.3, known fit 112.63
        self.assertAlmostEqual(fit.b0_GPa, 112.62927187296167, 4)
Exemplo n.º 23
0
 def test_fit(self):
     """Test EOS fit"""
     for eos_name in EOS.MODELS:
         eos = EOS(eos_name=eos_name)
         fit = eos.fit(self.volumes, self.energies)
         print(fit)
Exemplo n.º 24
0
 def check_fit(self, volumes, energies):
     eos = EOS('vinet')
     self.eos_fit = eos.fit(volumes, energies)
Exemplo n.º 25
0
def volume_workflow_is_converged(pwd, max_num_sub, min_num_vols,
                                 volume_tolerance):
    workflow_converged_list = []
    E, V = [], []
    minE = 100
    for root, dirs, files in os.walk(pwd):
        for file in files:
            if file == 'POTCAR' and check_vasp_input(root) == True:
                if os.path.exists(os.path.join(root, 'vasprun.xml')):
                    try:
                        Vr = Vasprun(os.path.join(root, 'vasprun.xml'))
                        fizzled = False
                    except:
                        fizzled = True
                        workflow_converged_list.append(False)

                    if fizzled == False:
                        job = is_converged(root)
                        if job == 'converged':
                            workflow_converged_list.append(True)
                            vol = Poscar.from_file(os.path.join(
                                root, 'POSCAR')).structure.volume
                            if Vr.final_energy < minE:
                                minE = Vr.final_energy
                                minV = vol
                                minE_path = root
                                minE_formula = str(
                                    Poscar.from_file(
                                        os.path.join(path, 'POSCAR')).
                                    structure.composition.reduced_formula)
                            E.append(Vr.final_energy)
                            V.append(vol)

                    elif fizzled == True and get_incar_value(
                            path, 'STAGE_NUMBER'
                    ) == 0:  #job is failing on initial relaxation
                        num_sub = get_number_of_subs(root)
                        if num_sub == max_num_sub:
                            os.remove(os.path.join(root, 'POTCAR'))
                            #job failed too many times.... just ignore this job for the remainder of the workflow
                else:
                    workflow_converged_list.append(False)

    num_jobs = check_num_jobs_in_workflow(pwd)
    if num_jobs < min_num_vols and len(E) > 0:
        scale_around_min = [0.98, 1.02]
        for s in scale_around_min:
            write_path = os.path.join(pwd, minE_formula + str(s * minV))
            os.mkdir(write_path)
            structure = Poscar.from_file(os.path.join(minE_path,
                                                      'POSCAR')).structure
            structure.scale_lattice(s * minV)
            Poscar.write_file(structure, os.path.join(write_path, 'POSCAR'))
            files_copy = [
                'backup/Init/INCAR', 'CONVERGENCE', 'KPOINTS', 'POTCAR'
            ]
            for fc in files_copy:
                copy_from_path = os.path.join(minE_path, fc)
                if os.path.exists(copy_from_path):
                    copy(copy_from_path, write_path)
            remove_sys_incar(write_path)

        #create new jobs
    if False not in workflow_converged_list:
        if len(E) > min_num_vols - 1:
            volumes = V
            energies = E
            eos = EOS(eos_name='murnaghan')
            eos_fit = eos.fit(volumes, energies)
            eos_minV = eos_fit.v0
            if abs(eos_minV - minV) < volume_tolerance:  # ang^3 cutoff
                return True
                #eos_fit.plot()

            else:
                scale_around_min = [0.99, 1, 1.01]
                for s in scale_around_min:
                    write_path = os.path.join(pwd,
                                              minE_formula + str(s * eos_minV))
                    os.mkdir(write_path)
                    structure = Poscar.from_file(
                        os.path.join(minE_path, 'POSCAR')).structure
                    structure.scale_lattice(s * eos_minV)
                    Poscar.write_file(structure,
                                      os.path.join(write_path, 'POSCAR'))
                    files_copy = [
                        'backup/Init/INCAR', 'CONVERGENCE', 'KPOINTS', 'POTCAR'
                    ]
                    for fc in files_copy:
                        copy_from_path = os.path.join(minE_path, fc)
                        if os.path.exists(copy_from_path):
                            copy(copy_from_path, write_path)
                    remove_sys_incar(write_path)

                return False

    else:
        return False
 def test_bulk_modulus(self):
     eos = EOS(self.eos)
     eos_fit = eos.fit(self.volumes, self.energies)
     bulk_modulus = float(str(eos_fit.b0_GPa).split()[0])
     bulk_modulus_ans = float(str(self.qhda.bulk_modulus).split()[0])
     np.testing.assert_almost_equal(bulk_modulus, bulk_modulus_ans, 3)
Exemplo n.º 27
0
print(f'Data printed in "{system_name}_eos.dat"')

import matplotlib.pyplot as plt
import numpy as np

import matplotlib

matplotlib.rcParams.update({'font.size': 22})

data = np.loadtxt(f"{system_name}_eos.dat", 'f')

V = data[:, 0]
E = data[:, 1]

# making b-m fit and plot with pymatgen
eos = EOS(eos_name='birch_murnaghan')
eos_fit = eos.fit(V, E)
eos_fit.plot(width=10,
             height=10,
             text='',
             markersize=15,
             label='Birch-Murnaghan fit')
plt.legend(loc=2, prop={'size': 20})
plt.title(f'{system_name}')
plt.tight_layout()
#plt.show()
plt.savefig(f'{system_name}_fit_eos.png')
print('')
print(f'Plot saved as "{system_name}_fit_eos.png"')

# getting fitted parameters