예제 #1
0
    def __init__(self, symbol):
        self.symbol = "%s" % symbol
        d = _pt_data[symbol]

        # Store key variables for quick access
        self.Z = d["Atomic no"]
        self.X = d.get("X", 0)
        for a in [
                "mendeleev_no", "electrical_resistivity", "velocity_of_sound",
                "reflectivity", "refractive_index", "poissons_ratio",
                "molar_volume", "electronic_structure", "thermal_conductivity",
                "boiling_point", "melting_point", "critical_temperature",
                "superconduction_temperature", "liquid_range", "bulk_modulus",
                "youngs_modulus", "brinell_hardness", "rigidity_modulus",
                "mineral_hardness", "vickers_hardness", "density_of_solid",
                "atomic_radius_calculated", "van_der_waals_radius",
                "coefficient_of_linear_thermal_expansion"
        ]:
            kstr = a.capitalize().replace("_", " ")
            val = d.get(kstr, None)
            if str(val).startswith("no data"):
                val = None
            else:
                try:
                    val = float(val)
                except ValueError:
                    toks_nobracket = re.sub(r'\(.*\)', "", val)
                    toks = toks_nobracket.replace("about",
                                                  "").strip().split(" ", 1)
                    if len(toks) == 2:
                        try:
                            if "10<sup>" in toks[1]:
                                base_power = re.findall(r'([+-]?\d+)', toks[1])
                                factor = "e" + base_power[1]
                                toks[0] += factor
                                if a == "electrical_resistivity":
                                    unit = "ohm m"
                                elif a == "coefficient_of_linear_thermal_expansion":
                                    unit = "K^-1"
                                else:
                                    unit = toks[1]
                                val = FloatWithUnit(toks[0], unit)
                            else:
                                unit = toks[1].replace("<sup>", "^").replace(
                                    "</sup>", "").replace("&Omega;", "ohm")
                                units = Unit(unit)
                                if set(units.keys()).issubset(
                                        SUPPORTED_UNIT_NAMES):
                                    val = FloatWithUnit(toks[0], unit)
                        except ValueError as ex:
                            # Ignore error. val will just remain a string.
                            pass
            setattr(self, a, val)
        if str(d.get("Atomic radius", "no data")).startswith("no data"):
            self.atomic_radius = None
        else:
            self.atomic_radius = Length(d["Atomic radius"], "ang")
        self.atomic_mass = Mass(d["Atomic mass"], "amu")
        self._data = d
예제 #2
0
 def __getattr__(self, item):
     if item in ["mendeleev_no", "electrical_resistivity",
                 "velocity_of_sound", "reflectivity",
                 "refractive_index", "poissons_ratio", "molar_volume",
                 "electronic_structure", "thermal_conductivity",
                 "boiling_point", "melting_point",
                 "critical_temperature", "superconduction_temperature",
                 "liquid_range", "bulk_modulus", "youngs_modulus",
                 "brinell_hardness", "rigidity_modulus",
                 "mineral_hardness", "vickers_hardness",
                 "density_of_solid", "atomic_radius_calculated",
                 "van_der_waals_radius", "atomic_orbitals",
                 "coefficient_of_linear_thermal_expansion"]:
         kstr = item.capitalize().replace("_", " ")
         val = self._data.get(kstr, None)
         if str(val).startswith("no data"):
             val = None
         elif type(val) == dict:
             pass
         else:
             try:
                 val = float(val)
             except ValueError:
                 nobracket = re.sub(r'\(.*\)', "", val)
                 toks = nobracket.replace("about", "").strip().split(" ", 1)
                 if len(toks) == 2:
                     try:
                         if "10<sup>" in toks[1]:
                             base_power = re.findall(r'([+-]?\d+)', toks[1])
                             factor = "e" + base_power[1]
                             if toks[0] in ["&gt;", "high"]:
                                 toks[0] = "1"  # return the border value
                             toks[0] += factor
                             if item == "electrical_resistivity":
                                 unit = "ohm m"
                             elif (
                                 item ==
                                 "coefficient_of_linear_thermal_expansion"
                             ):
                                 unit = "K^-1"
                             else:
                                 unit = toks[1]
                             val = FloatWithUnit(toks[0], unit)
                         else:
                             unit = toks[1].replace("<sup>", "^").replace(
                                 "</sup>", "").replace("&Omega;",
                                                       "ohm")
                             units = Unit(unit)
                             if set(units.keys()).issubset(
                                     SUPPORTED_UNIT_NAMES):
                                 val = FloatWithUnit(toks[0], unit)
                     except ValueError as ex:
                         # Ignore error. val will just remain a string.
                         pass
         return val
     raise AttributeError
 def average_anionic_radius(self) -> float:
     """
     Average anionic radius for element (with units). The average is
     taken over all negative oxidation states of the element for which
     data is present.
     """
     if "Ionic radii" in self._data:
         radii = [v for k, v in self._data["Ionic radii"].items() if int(k) < 0]
         if radii:
             return FloatWithUnit(sum(radii) / len(radii), "ang")
     return FloatWithUnit(0.0, "ang")
예제 #4
0
    def __new__(cls, *args):
        """Extends the base class adding type conversion of arguments."""
        new_args = len(args) * [None]

        for i, arg in enumerate(args[:-1]):
            converter = float
            if i == 0: converter = str
            new_args[i] = converter(arg)

        v0 = FloatWithUnit(new_args[1], "ang^3")
        b0 = FloatWithUnit(new_args[2], "eV ang^-3")

        return super(cls, DeltaFactorEntry).__new__(cls,
                     symbol=new_args[0], v0=v0, b0=b0, b1=new_args[3], xc=args[-1])
예제 #5
0
 def test_compound_operations(self):
     g = 10 * Length(1, "m") / (Time(1, "s") ** 2)
     e = Mass(1, "kg") * g * Length(1, "m")
     self.assertEqual(str(e), "10.0 N m")
     form_e = FloatWithUnit(10, unit="kJ mol^-1")
     self.assertEqual(str(form_e.to("eV atom^-1")), "0.103642691905 eV atom^-1")
     self.assertRaises(UnitError, form_e.to, "m s^-1")
     a = FloatWithUnit(1.0, "Ha^3")
     self.assertEqual(str(a.to("J^3")), "8.28672661615e-53 J^3")
     a = FloatWithUnit(1.0, "Ha bohr^-2")
     self.assertEqual(str(a.to("J m^-2")), "1556.89291457 J m^-2")
예제 #6
0
 def nmr_quadrupole_moment(self):
     """
     Get a dictionary the nuclear electric quadrupole moment in units of
     e*millibarns for various isotopes
     """
     return {k: FloatWithUnit(v, "mbarn")
             for k, v in self.data.get("NMR Quadrupole Moment", {}).items()}
예제 #7
0
 def test_compound_operations(self):
     g = 10 * Length(1, "m") / (Time(1, "s") ** 2)
     e = Mass(1, "kg") * g * Length(1, "m")
     self.assertEqual(str(e), "10.0 N m")
     form_e = FloatWithUnit(10, unit="kJ mol^-1").to("eV atom^-1")
     self.assertAlmostEqual(float(form_e), 0.103642691905)
     self.assertEqual(str(form_e.unit), "eV atom^-1")
     self.assertRaises(UnitError, form_e.to, "m s^-1")
     a = FloatWithUnit(1.0, "Ha^3")
     b = a.to("J^3")
     self.assertAlmostEqual(b, 8.28672661615e-53)
     self.assertEqual(str(b.unit), "J^3")
     a = FloatWithUnit(1.0, "Ha bohr^-2")
     b = a.to("J m^-2")
     self.assertAlmostEqual(b, 1556.893078472351)
     self.assertEqual(str(b.unit), "J m^-2")
예제 #8
0
 def b0_GPa(self):
     """
     Returns the bulk modulus in GPa.
     Note: This assumes that the energy and volumes are in eV and Ang^3
         respectively
     """
     return FloatWithUnit(self.b0, "eV ang^-3").to("GPa")
예제 #9
0
    def coupling_constant(self, specie):
        """
        Computes the couplling constant C_q as defined in:
            Wasylishen R E, Ashbrook S E, Wimperis S. NMR of quadrupolar nuclei
            in solid materials[M]. John Wiley & Sons, 2012. (Chapter 3.2)

        C_q for a specific atom type for this electric field tensor:
                C_q=e*Q*V_zz/h
            h: planck's constant
            Q: nuclear electric quadrupole moment in mb (millibarn
            e: elementary proton charge

        Args:
            specie: flexible input to specify the species at this site.
                    Can take a isotope or element string, Specie object,
                    or Site object

        Return:

            the coupling constant as a FloatWithUnit in MHz
        """
        planks_constant = FloatWithUnit(6.62607004E-34, "m^2 kg s^-1")
        Vzz = FloatWithUnit(self.V_zz, "V ang^-2")
        e = FloatWithUnit(-1.60217662E-19, "C")

        # Convert from string to Specie object
        if isinstance(specie, str):
            # isotope was provided in string format
            if len(specie.split("-")) > 1:
                isotope = str(specie)
                specie = Specie(specie.split("-")[0])
                Q = specie.get_nmr_quadrupole_moment(isotope)
            else:
                specie = Specie(specie)
                Q = specie.get_nmr_quadrupole_moment()
        elif isinstance(specie, Site):
            specie = specie.specie
            Q = specie.get_nmr_quadrupole_moment()
        elif isinstance(specie, Specie):
            Q = specie.get_nmr_quadrupole_moment()
        else:
            raise ValueError(
                "Invalid speciie provided for quadrupolar coupling constant calcuations"
            )

        return (e * Q * Vzz / planks_constant).to("MHz")
 def ionic_radii(self) -> Dict[int, float]:
     """
     All ionic radii of the element as a dict of
     {oxidation state: ionic radii}. Radii are given in ang.
     """
     if "Ionic radii" in self._data:
         return {int(k): FloatWithUnit(v, "ang") for k, v in self._data["Ionic radii"].items()}
     return {}
예제 #11
0
 def average_ionic_radius(self):
     """
     Average ionic radius for element (with units). The average is taken
     over all oxidation states of the element for which data is present.
     """
     if "Ionic radii" in self._data:
         radii = self._data["Ionic radii"]
         radius = sum(radii.values()) / len(radii)
     else:
         radius = 0.0
     return FloatWithUnit(radius, "ang")
예제 #12
0
    def gruneisen_parameter(self, temperature, volume):
        """
        Slater-gamma formulation(the default):
            gruneisen paramter = - d log(theta)/ d log(V)
                               = - ( 1/6 + 0.5 d log(B)/ d log(V) )
                               = - (1/6 + 0.5 V/B dB/dV),
                                    where dB/dV = d^2E/dV^2 + V * d^3E/dV^3

        Mie-gruneisen formulation:
            Eq(31) in doi.org/10.1016/j.comphy.2003.12.001
            Eq(7) in Blanco et. al. Joumal of Molecular Structure (Theochem)
                368 (1996) 245-255
            Also se J.P. Poirier, Introduction to the Physics of the Earth’s
                Interior, 2nd ed. (Cambridge University Press, Cambridge,
                2000) Eq(3.53)

        Args:
            temperature (float): temperature in K
            volume (float): in Ang^3

        Returns:
            float: unitless
        """
        if isinstance(self.eos, PolynomialEOS):
            p = np.poly1d(self.eos.eos_params)  # pylint: disable=E1101
            # first derivative of energy at 0K wrt volume evaluated at the
            # given volume, in eV/Ang^3
            dEdV = np.polyder(p, 1)(volume)
            # second derivative of energy at 0K wrt volume evaluated at the
            # given volume, in eV/Ang^6
            d2EdV2 = np.polyder(p, 2)(volume)
            # third derivative of energy at 0K wrt volume evaluated at the
            # given volume, in eV/Ang^9
            d3EdV3 = np.polyder(p, 3)(volume)
        else:
            func = self.ev_eos_fit.func
            dEdV = derivative(func, volume, dx=1e-3)
            d2EdV2 = derivative(func, volume, dx=1e-3, n=2, order=5)
            d3EdV3 = derivative(func, volume, dx=1e-3, n=3, order=7)

        # Mie-gruneisen formulation
        if self.use_mie_gruneisen:
            p0 = dEdV
            return (
                self.gpa_to_ev_ang
                * volume
                * (self.pressure + p0 / self.gpa_to_ev_ang)
                / self.vibrational_internal_energy(temperature, volume)
            )

        # Slater-gamma formulation
        # first derivative of bulk modulus wrt volume, eV/Ang^6
        dBdV = d2EdV2 + d3EdV3 * volume
        return -(1.0 / 6.0 + 0.5 * volume * dBdV / FloatWithUnit(self.ev_eos_fit.b0_GPa, "GPa").to("eV ang^-3"))
예제 #13
0
    def __new__(cls, **kwargs):
        """Extends the base class adding type conversion of arguments."""
        for k, v in kwargs.items():
            if k in ["symbol", "struct_type"]: continue
            if v == "-":
                # Set missing entries to None
                v = None
            else:
                # Values in GBRV tables are in Angstrom.
                v = FloatWithUnit(v, "ang")

            kwargs[k] = v

        return super(cls, GbrvEntry).__new__(cls, **kwargs)
예제 #14
0
 def test_compound_operations(self):
     g = 10 * Length(1, "m") / (Time(1, "s")**2)
     e = Mass(1, "kg") * g * Length(1, "m")
     self.assertEqual(str(e), "10.0 N m")
     form_e = FloatWithUnit(10, unit="kJ mol^-1").to("eV atom^-1")
     self.assertAlmostEqual(float(form_e), 0.103642691905)
     self.assertEqual(str(form_e.unit), "eV atom^-1")
     self.assertRaises(UnitError, form_e.to, "m s^-1")
     a = FloatWithUnit(1.0, "Ha^3")
     b = a.to("J^3")
     self.assertAlmostEqual(b, 8.28672661615e-53)
     self.assertEqual(str(b.unit), "J^3")
     a = FloatWithUnit(1.0, "Ha bohr^-2")
     b = a.to("J m^-2")
     self.assertAlmostEqual(b, 1556.893078472351)
     self.assertEqual(str(b.unit), "J m^-2")
예제 #15
0
def read_data_from_filepath(filepath, xc):
    """
    Reads (v0, b0, b1) from file filename. b0 is in GPa.
    xc is the XcFunc associated to these data.
    Returns a dict of `DeltaFactorEntry` objects indexed by element symbol.
    """
    data = collections.OrderedDict()

    with open(filepath, "r") as fh:
        for line in fh:
            line = line.strip()
            if line.startswith("#") or not line:
                continue
            tokens = line.split()
            symbol = tokens[0]
            # Conversion GPa --> eV / A**3 and pass xc info to the Entry.
            tokens[2] = FloatWithUnit(tokens[2], "GPa").to("eV ang^-3")
            tokens.append(xc)
            data[symbol] = DeltaFactorEntry(*tokens)

    return data
예제 #16
0
    def test_unitized(self):

        @unitized("eV")
        def f():
            return [1, 2, 3]

        self.assertEqual(str(f()[0]), "1.0 eV")
        self.assertIsInstance(f(), list)

        @unitized("eV")
        def g():
            return 2, 3, 4

        self.assertEqual(str(g()[0]), "2.0 eV")
        self.assertIsInstance(g(), tuple)

        @unitized("pm")
        def h():
            d = collections.OrderedDict()
            for i in range(3):
                d[i] = i * 20
            return d

        self.assertEqual(str(h()[1]), "20.0 pm")
        self.assertIsInstance(h(), collections.OrderedDict)

        @unitized("kg")
        def i():
            return FloatWithUnit(5, "g")

        self.assertEqual(i(), FloatWithUnit(0.005, "kg"))

        @unitized("kg")
        def j():
            return ArrayWithUnit([5, 10], "g")

        j_out = j()
        self.assertEqual(j_out.unit, Unit("kg"))
        self.assertEqual(j_out[0], 0.005)
        self.assertEqual(j_out[1], 0.01)
예제 #17
0
 def b0_GPa(self):
     return FloatWithUnit(self.b0, "eV ang^-3").to("GPa")
예제 #18
0
def df_compute(v0w, b0w, b1w, v0f, b0f, b1f, b0_GPa=False, v=3, useasymm=False):
    """
    Compute the deltafactor. Based on the code of the offical calcDelta.py script.

    Args:
        v0w, b0w, b1w:  Volume, bulk-modulus and pressure derivative of b0w (reference values).
        v0f, b0f, b1f: Volume, bulk-modulus and pressure derivative of b0f (computed values).
        v: version of delta factor, current version is 3, 1 for symmetrical old version

    .. note::

        v0 is A**3/natom, by default b0 is in eV/A**3, GPa units are used if b0_GPa is True.
    """
    #print(v0w, b0w, b1w, v0f, b0f, b1f)

    if v == 1:
        # delta factor form version 1
        if b0_GPa:
            # Conversion GPa --> eV/A**3
            b0w = FloatWithUnit(b0w, "GPa").to("eV ang^-3")
            b0f = FloatWithUnit(b0f, "GPa").to("eV ang^-3")

        Vi = 0.94 * v0w
        Vf = 1.06 * v0w

        a3f = 9. * v0f**3. * b0f / 16. * (b1f - 4.)
        a2f = 9. * v0f**(7./3.) * b0f / 16. * (14. - 3. * b1f)
        a1f = 9. * v0f**(5./3.) * b0f / 16. * (3. * b1f - 16.)
        a0f = 9. * v0f * b0f / 16. * (6. - b1f)

        a3w = 9. * v0w**3. * b0w / 16. * (b1w - 4.)
        a2w = 9. * v0w**(7./3.) * b0w / 16. * (14. - 3. * b1w)
        a1w = 9. * v0w**(5./3.) * b0w / 16. * (3. * b1w - 16.)
        a0w = 9. * v0w * b0w / 16. * (6. - b1w)

        x = [0, 0, 0, 0, 0, 0, 0]

        x[0] = (a0f - a0w)**2
        x[1] = 6. * (a1f - a1w) * (a0f - a0w)
        x[2] = -3. * (2. * (a2f - a2w) * (a0f - a0w) + (a1f - a1w)**2.)
        x[3] = -2. * (a3f - a3w) * (a0f - a0w) - 2. * (a2f - a2w) * (a1f - a1w)
        x[4] = -3./5. * (2. * (a3f - a3w) * (a1f - a1w) + (a2f - a2w)**2.)
        x[5] = -6./7. * (a3f - a3w) * (a2f - a2w)
        x[6] = -1./3. * (a3f - a3w)**2.

        Fi = np.zeros_like(Vi)
        Ff = np.zeros_like(Vf)

        for n in range(7):
            Fi = Fi + x[n] * Vi**(-(2.*n-3.)/3.)
            Ff = Ff + x[n] * Vf**(-(2.*n-3.)/3.)

        return 1000. * np.sqrt((Ff - Fi) / (0.12 * v0w))

    elif v == 3:
        # version 3

        if b0_GPa:
            # Conversion GPa --> eV/A**3
            b0w = FloatWithUnit(b0w, "GPa").to("eV ang^-3")
            b0f = FloatWithUnit(b0f, "GPa").to("eV ang^-3")

        if useasymm:
            Vi = 0.94 * v0w
            Vf = 1.06 * v0w
        else:
            Vi = 0.94 * (v0w + v0f) / 2.
            Vf = 1.06 * (v0w + v0f) / 2.

        a3f = 9. * v0f**3. * b0f / 16. * (b1f - 4.)
        a2f = 9. * v0f**(7./3.) * b0f / 16. * (14. - 3. * b1f)
        a1f = 9. * v0f**(5./3.) * b0f / 16. * (3. * b1f - 16.)
        a0f = 9. * v0f * b0f / 16. * (6. - b1f)

        a3w = 9. * v0w**3. * b0w / 16. * (b1w - 4.)
        a2w = 9. * v0w**(7./3.) * b0w / 16. * (14. - 3. * b1w)
        a1w = 9. * v0w**(5./3.) * b0w / 16. * (3. * b1w - 16.)
        a0w = 9. * v0w * b0w / 16. * (6. - b1w)

        x = [0, 0, 0, 0, 0, 0, 0]

        x[0] = (a0f - a0w)**2
        x[1] = 6. * (a1f - a1w) * (a0f - a0w)
        x[2] = -3. * (2. * (a2f - a2w) * (a0f - a0w) + (a1f - a1w)**2.)
        x[3] = -2. * (a3f - a3w) * (a0f - a0w) - 2. * (a2f - a2w) * (a1f - a1w)
        x[4] = -3./5. * (2. * (a3f - a3w) * (a1f - a1w) + (a2f - a2w)**2.)
        x[5] = -6./7. * (a3f - a3w) * (a2f - a2w)
        x[6] = -1./3. * (a3f - a3w)**2.

        y = [0, 0, 0, 0, 0, 0, 0]

        y[0] = (a0f + a0w)**2 / 4.
        y[1] = 3. * (a1f + a1w) * (a0f + a0w) / 2.
        y[2] = -3. * (2. * (a2f + a2w) * (a0f + a0w) + (a1f + a1w)**2.) / 4.
        y[3] = -(a3f + a3w) * (a0f + a0w) / 2. - (a2f + a2w) * (a1f + a1w) / 2.
        y[4] = -3./20. * (2. * (a3f + a3w) * (a1f + a1w) + (a2f + a2w)**2.)
        y[5] = -3./14. * (a3f + a3w) * (a2f + a2w)
        y[6] = -1./12. * (a3f + a3w)**2.

        Fi = np.zeros_like(Vi)
        Ff = np.zeros_like(Vf)

        Gi = np.zeros_like(Vi)
        Gf = np.zeros_like(Vf)

        for n in range(7):
            Fi += x[n] * Vi**(-(2.*n-3.)/3.)
            Ff += x[n] * Vf**(-(2.*n-3.)/3.)

            Gi += y[n] * Vi**(-(2.*n-3.)/3.)
            Gf += y[n] * Vf**(-(2.*n-3.)/3.)

        Delta = 1000. * np.sqrt((Ff - Fi) / (Vf - Vi))

        #Deltarel = 100. * np.sqrt((Ff - Fi) / (Gf - Gi))
        #if useasymm:
        #    Delta1 = 1000. * np.sqrt((Ff - Fi) / (Vf - Vi)) \
        #             / v0w / b0w * vref * bref
        #else:
        #    Delta1 = 1000. * np.sqrt((Ff - Fi) / (Vf - Vi)) \
        #             / (v0w + v0f) / (b0w + b0f) * 4. * vref * bref

        return Delta

    else:
        raise ValueError("Wrong version %s" % v)
예제 #19
0
    def _parse_job(self, output):
        energy_patt = re.compile(r'Total \w+ energy\s+=\s+([.\-\d]+)')
        energy_gas_patt = re.compile(r'gas phase energy\s+=\s+([.\-\d]+)')
        energy_sol_patt = re.compile(r'sol phase energy\s+=\s+([.\-\d]+)')
        coord_patt = re.compile(r'\d+\s+(\w+)\s+[.\-\d]+\s+([.\-\d]+)\s+'
                                r'([.\-\d]+)\s+([.\-\d]+)')
        lat_vector_patt = re.compile(r'a[123]=<\s+([.\-\d]+)\s+'
                                     r'([.\-\d]+)\s+([.\-\d]+)\s+>')
        corrections_patt = re.compile(r'([\w\-]+ correction to \w+)\s+='
                                      r'\s+([.\-\d]+)')
        preamble_patt = re.compile(r'(No. of atoms|No. of electrons'
                                   r'|SCF calculation type|Charge|Spin '
                                   r'multiplicity)\s*:\s*(\S+)')
        force_patt = re.compile(r'\s+(\d+)\s+(\w+)' + 6 * r'\s+([0-9\.\-]+)')

        time_patt = re.compile(
            r'\s+ Task \s+ times \s+ cpu: \s+   ([.\d]+)s .+ ', re.VERBOSE)

        error_defs = {
            "calculations not reaching convergence": "Bad convergence",
            "Calculation failed to converge": "Bad convergence",
            "geom_binvr: #indep variables incorrect": "autoz error",
            "dft optimize failed": "Geometry optimization failed"}

        fort2py = lambda x: x.replace("D", "e")
        isfloatstring = lambda s: s.find(".") == -1

        parse_hess = False
        parse_proj_hess = False
        hessian = None
        projected_hessian = None
        parse_force = False
        all_forces = []
        forces = []

        data = {}
        energies = []
        frequencies = None
        normal_frequencies = None
        corrections = {}
        molecules = []
        structures = []
        species = []
        coords = []
        lattice = []
        errors = []
        basis_set = {}
        bset_header = []
        parse_geom = False
        parse_freq = False
        parse_bset = False
        parse_projected_freq = False
        job_type = ""
        parse_time = False
        time = 0
        for l in output.split("\n"):
            for e, v in error_defs.items():
                if l.find(e) != -1:
                    errors.append(v)
            if parse_time:
                m = time_patt.search(l)
                if m:
                    time = m.group(1)
                    parse_time = False
            if parse_geom:
                if l.strip() == "Atomic Mass":
                    if lattice:
                        structures.append(Structure(lattice, species, coords,
                                                    coords_are_cartesian=True))
                    else:
                        molecules.append(Molecule(species, coords))
                    species = []
                    coords = []
                    lattice = []
                    parse_geom = False
                else:
                    m = coord_patt.search(l)
                    if m:
                        species.append(m.group(1).capitalize())
                        coords.append([float(m.group(2)), float(m.group(3)),
                                       float(m.group(4))])
                    m = lat_vector_patt.search(l)
                    if m:
                        lattice.append([float(m.group(1)), float(m.group(2)),
                                        float(m.group(3))])

            if parse_force:
                m = force_patt.search(l)
                if m:
                    forces.extend(map(float, m.groups()[5:]))
                elif len(forces) > 0:
                    all_forces.append(forces)
                    forces = []
                    parse_force = False

            elif parse_freq:
                if len(l.strip()) == 0:
                    if len(normal_frequencies[-1][1]) == 0:
                        continue
                    else:
                        parse_freq = False
                else:
                    vibs = [float(vib) for vib in l.strip().split()[1:]]
                    num_vibs = len(vibs)
                    for mode, dis in zip(normal_frequencies[-num_vibs:], vibs):
                        mode[1].append(dis)

            elif parse_projected_freq:
                if len(l.strip()) == 0:
                    if len(frequencies[-1][1]) == 0:
                        continue
                    else:
                        parse_projected_freq = False
                else:
                    vibs = [float(vib) for vib in l.strip().split()[1:]]
                    num_vibs = len(vibs)
                    for mode, dis in zip(
                            frequencies[-num_vibs:], vibs):
                        mode[1].append(dis)

            elif parse_bset:
                if l.strip() == "":
                    parse_bset = False
                else:
                    toks = l.split()
                    if toks[0] != "Tag" and not re.match(r"-+", toks[0]):
                        basis_set[toks[0]] = dict(zip(bset_header[1:],
                                                      toks[1:]))
                    elif toks[0] == "Tag":
                        bset_header = toks
                        bset_header.pop(4)
                        bset_header = [h.lower() for h in bset_header]

            elif parse_hess:
                if l.strip() == "":
                    continue
                if len(hessian) > 0 and l.find("----------") != -1:
                    parse_hess = False
                    continue
                toks = l.strip().split()
                if len(toks) > 1:
                    try:
                        row = int(toks[0])
                    except Exception:
                        continue
                    if isfloatstring(toks[1]):
                        continue
                    vals = [float(fort2py(x)) for x in toks[1:]]
                    if len(hessian) < row:
                        hessian.append(vals)
                    else:
                        hessian[row - 1].extend(vals)

            elif parse_proj_hess:
                if l.strip() == "":
                    continue
                nat3 = len(hessian)
                toks = l.strip().split()
                if len(toks) > 1:
                    try:
                        row = int(toks[0])
                    except Exception:
                        continue
                    if isfloatstring(toks[1]):
                        continue
                    vals = [float(fort2py(x)) for x in toks[1:]]
                    if len(projected_hessian) < row:
                        projected_hessian.append(vals)
                    else:
                        projected_hessian[row - 1].extend(vals)
                    if len(projected_hessian[-1]) == nat3:
                        parse_proj_hess = False

            else:
                m = energy_patt.search(l)
                if m:
                    energies.append(Energy(m.group(1), "Ha").to("eV"))
                    parse_time = True
                    continue

                m = energy_gas_patt.search(l)
                if m:
                    cosmo_scf_energy = energies[-1]
                    energies[-1] = dict()
                    energies[-1].update({"cosmo scf": cosmo_scf_energy})
                    energies[-1].update({"gas phase":
                                         Energy(m.group(1), "Ha").to("eV")})

                m = energy_sol_patt.search(l)
                if m:
                    energies[-1].update(
                        {"sol phase": Energy(m.group(1), "Ha").to("eV")})

                m = preamble_patt.search(l)
                if m:
                    try:
                        val = int(m.group(2))
                    except ValueError:
                        val = m.group(2)
                    k = m.group(1).replace("No. of ", "n").replace(" ", "_")
                    data[k.lower()] = val
                elif l.find("Geometry \"geometry\"") != -1:
                    parse_geom = True
                elif l.find("Summary of \"ao basis\"") != -1:
                    parse_bset = True
                elif l.find("P.Frequency") != -1:
                    parse_projected_freq = True
                    if frequencies is None:
                        frequencies = []
                    toks = l.strip().split()[1:]
                    frequencies.extend([(float(freq), []) for freq in toks])

                elif l.find("Frequency") != -1:
                    toks = l.strip().split()
                    if len(toks) > 1 and toks[0] == "Frequency":
                        parse_freq = True
                        if normal_frequencies is None:
                            normal_frequencies = []
                        normal_frequencies.extend([(float(freq), []) for freq
                                                   in l.strip().split()[1:]])

                elif l.find("MASS-WEIGHTED NUCLEAR HESSIAN") != -1:
                    parse_hess = True
                    if not hessian:
                        hessian = []
                elif l.find("MASS-WEIGHTED PROJECTED HESSIAN") != -1:
                    parse_proj_hess = True
                    if not projected_hessian:
                        projected_hessian = []

                elif l.find("atom               coordinates                        gradient") != -1:
                    parse_force = True

                elif job_type == "" and l.strip().startswith("NWChem"):
                    job_type = l.strip()
                    if job_type == "NWChem DFT Module" and \
                            "COSMO solvation results" in output:
                        job_type += " COSMO"
                else:
                    m = corrections_patt.search(l)
                    if m:
                        corrections[m.group(1)] = FloatWithUnit(
                            m.group(2), "kJ mol^-1").to("eV atom^-1")

        if frequencies:
            for freq, mode in frequencies:
                mode[:] = zip(*[iter(mode)]*3)
        if normal_frequencies:
            for freq, mode in normal_frequencies:
                mode[:] = zip(*[iter(mode)]*3)
        if hessian:
            n = len(hessian)
            for i in range(n):
                for j in range(i + 1, n):
                    hessian[i].append(hessian[j][i])
        if projected_hessian:
            n = len(projected_hessian)
            for i in range(n):
                for j in range(i + 1, n):
                    projected_hessian[i].append(projected_hessian[j][i])

        data.update({"job_type": job_type, "energies": energies,
                     "corrections": corrections,
                     "molecules": molecules,
                     "structures": structures,
                     "basis_set": basis_set,
                     "errors": errors,
                     "has_error": len(errors) > 0,
                     "frequencies": frequencies,
                     "normal_frequencies": normal_frequencies,
                     "hessian": hessian,
                     "projected_hessian": projected_hessian,
                     "forces": all_forces,
                     "task_time": time})

        return data
예제 #20
0
 def test_as_base_units(self):
     x = FloatWithUnit(5, "MPa")
     self.assertEqual(FloatWithUnit(5000000, "Pa"), x.as_base_units)
예제 #21
0
def find_theo_redenth(compstr):
    """
    Finds theoretical redox enthalpies from the Materials Project from perovskite to brownmillerite
    based partially on https://github.com/materialsproject/pymatgen/blob/b3e972e293885c5b3c69fb3e9aa55287869d4d84/
    examples/Calculating%20Reaction%20Energies%20with%20the%20Materials%20API.ipynb

    :param compstr: composition as a string

    :return:
    red_enth:  redox enthalpy in kJ/mol O
    """
    compstr_perovskite = compstr.split("O")[0] + "O3"

    comp_spl = split_comp(compstr)
    chem_sys = ""
    for i in range(len(comp_spl)):
        if comp_spl[i] is not None:
            chem_sys = chem_sys + comp_spl[i][0] + "-"
    chem_sys = chem_sys + "O"
    chem_sys = chem_sys.split("-")

    all_entries = mpr.get_entries_in_chemsys(chem_sys)

    # This method simply gets the lowest energy entry for all entries with the same composition.
    def get_most_stable_entry(formula):
        relevant_entries = [entry for entry in all_entries if
        entry.composition.reduced_formula == Composition(formula).reduced_formula]
        relevant_entries = sorted(relevant_entries, key=lambda e: e.energy_per_atom)
        return relevant_entries[0]

    formula_spl = [''.join(g) for _, g in groupby(str(compstr), str.isalpha)]
    perov_formula = []
    for k in range(len(formula_spl)):
        try:
            perov_formula += str(int(float(formula_spl[k]) * 8))
        except ValueError:
            perov_formula += str(formula_spl[k])
    perov_formula = "".join(perov_formula)
    perov_formula = str(perov_formula).split("O")[0] + "O24"
    perovskite = get_most_stable_entry(perov_formula)

    brownm_formula = []
    for k in range(len(formula_spl)):
        try:
            brownm_formula += str(int(float(formula_spl[k]) * 32))
        except ValueError:
            brownm_formula += str(formula_spl[k])
    brownm_formula = "".join(brownm_formula)
    brownm_formula = str(brownm_formula).split("O")[0] + "O80"
    brownmillerite = get_most_stable_entry(brownm_formula)

    # for oxygen: do not use the most stable phase O8 but the most stable O2 phase
    def get_oxygen():
        relevant_entries = [entry for entry in all_entries if
        entry.composition == Composition("O2")]
        relevant_entries = sorted(relevant_entries, key=lambda e: e.energy_per_atom)
        return relevant_entries[0]

    oxygen = get_oxygen()

    reaction = ComputedReaction([perovskite], [brownmillerite, oxygen])
    energy = FloatWithUnit(reaction.calculated_reaction_energy, "eV atom^-1")

    # figure out the stoichiometry of O2 in the reaction equation in order to normalize the energies per mol of O
    try:
        o_stoich = float(str(str(reaction.as_dict).split(" O2")[0]).split()[-1])
    except ValueError:
        o_stoich = 1
    # energy in J/mol per mol of O2
    ener = (float(energy.to("kJ mol^-1")) * 1000) / o_stoich
    # per mol of O
    ener = ener / 2

    return ener
예제 #22
0
 def i():
     return FloatWithUnit(5, "g")
예제 #23
0
 def metallic_radius(self):
     """
     Metallic radius of the element. Radius is given in ang.
     """
     return FloatWithUnit(self._data["Metallic radius"], "ang")
예제 #24
0
    def _parse_job(self, output):
        energy_patt = re.compile("Total \w+ energy\s+=\s+([\.\-\d]+)")

        #In cosmo solvation results; gas phase energy = -152.5044774212

        energy_gas_patt = re.compile("gas phase energy\s+=\s+([\.\-\d]+)")

        #In cosmo solvation results; sol phase energy = -152.5044774212

        energy_sol_patt = re.compile("sol phase energy\s+=\s+([\.\-\d]+)")

        coord_patt = re.compile("\d+\s+(\w+)\s+[\.\-\d]+\s+([\.\-\d]+)\s+"
                                "([\.\-\d]+)\s+([\.\-\d]+)")
        corrections_patt = re.compile("([\w\-]+ correction to \w+)\s+="
                                      "\s+([\.\-\d]+)")
        preamble_patt = re.compile("(No. of atoms|No. of electrons"
                                   "|SCF calculation type|Charge|Spin "
                                   "multiplicity)\s*:\s*(\S+)")
        error_defs = {
            "calculations not reaching convergence": "Bad convergence",
            "Calculation failed to converge": "Bad convergence",
            "geom_binvr: #indep variables incorrect": "autoz error",
            "dft optimize failed": "Geometry optimization failed"
        }

        data = {}
        energies = []
        frequencies = None
        corrections = {}
        molecules = []
        species = []
        coords = []
        errors = []
        basis_set = {}
        parse_geom = False
        parse_freq = False
        parse_bset = False
        job_type = ""
        for l in output.split("\n"):
            for e, v in error_defs.items():
                if l.find(e) != -1:
                    errors.append(v)
            if parse_geom:
                if l.strip() == "Atomic Mass":
                    molecules.append(Molecule(species, coords))
                    species = []
                    coords = []
                    parse_geom = False
                else:
                    m = coord_patt.search(l)
                    if m:
                        species.append(m.group(1).capitalize())
                        coords.append([
                            float(m.group(2)),
                            float(m.group(3)),
                            float(m.group(4))
                        ])
            if parse_freq:
                if len(l.strip()) == 0:
                    if len(frequencies[-1][1]) == 0:
                        continue
                    else:
                        parse_freq = False
                else:
                    vibs = [float(vib) for vib in l.strip().split()[1:]]
                    num_vibs = len(vibs)
                    for mode, dis in zip(frequencies[-num_vibs:], vibs):
                        mode[1].append(dis)

            elif parse_bset:
                if l.strip() == "":
                    parse_bset = False
                else:
                    toks = l.split()
                    if toks[0] != "Tag" and not re.match("\-+", toks[0]):
                        basis_set[toks[0]] = dict(
                            zip(bset_header[1:], toks[1:]))
                    elif toks[0] == "Tag":
                        bset_header = toks
                        bset_header.pop(4)
                        bset_header = [h.lower() for h in bset_header]
            else:
                m = energy_patt.search(l)
                if m:
                    energies.append(Energy(m.group(1), "Ha").to("eV"))
                    continue

                m = energy_gas_patt.search(l)
                if m:
                    cosmo_scf_energy = energies[-1]
                    energies[-1] = dict()
                    energies[-1].update({"cosmo scf": cosmo_scf_energy})
                    energies[-1].update(
                        {"gas phase": Energy(m.group(1), "Ha").to("eV")})

                m = energy_sol_patt.search(l)
                if m:
                    energies[-1].update(
                        {"sol phase": Energy(m.group(1), "Ha").to("eV")})

                m = preamble_patt.search(l)
                if m:
                    try:
                        val = int(m.group(2))
                    except ValueError:
                        val = m.group(2)
                    k = m.group(1).replace("No. of ", "n").replace(" ", "_")
                    data[k.lower()] = val
                elif l.find("Geometry \"geometry\"") != -1:
                    parse_geom = True
                elif l.find("Summary of \"ao basis\"") != -1:
                    parse_bset = True
                elif l.find("P.Frequency") != -1:
                    parse_freq = True
                    if not frequencies:
                        frequencies = []
                    frequencies.extend([(float(freq), [])
                                        for freq in l.strip().split()[1:]])
                elif job_type == "" and l.strip().startswith("NWChem"):
                    job_type = l.strip()
                    if job_type == "NWChem DFT Module" and \
                            "COSMO solvation results" in output:
                        job_type += " COSMO"
                else:
                    m = corrections_patt.search(l)
                    if m:
                        corrections[m.group(1)] = FloatWithUnit(
                            m.group(2), "kJ mol^-1").to("eV atom^-1")
        if frequencies:
            for freq, mode in frequencies:
                mode[:] = zip(*[iter(mode)] * 3)
        data.update({
            "job_type": job_type,
            "energies": energies,
            "corrections": corrections,
            "molecules": molecules,
            "basis_set": basis_set,
            "errors": errors,
            "has_error": len(errors) > 0,
            "frequencies": frequencies
        })

        return data
def get_most_stable_entry(formula):
    relevant_entries = [
        entry for entry in all_entries if entry.composition.reduced_formula ==
        Composition(formula).reduced_formula
    ]
    relevant_entries = sorted(relevant_entries,
                              key=lambda e: e.energy_per_atom)
    return relevant_entries[0]


CaO = get_most_stable_entry("CaO")
CO2 = get_most_stable_entry("CO2")
CaCO3 = get_most_stable_entry("CaCO3")

reaction = ComputedReaction([CaO, CO2], [CaCO3])  #得到化学反应
energy = FloatWithUnit(reaction.calculated_reaction_energy,
                       "eV atom^-1")  #计算化学反应的能量,并且转换单位

print("Caculated")
print(reaction)
print("Reaction energy = {}".format(energy.to("kJ mol^-1")))

# The following portions demonstrate how to get the experimental values as well.
exp_CaO = a.get_exp_entry("CaO")  #获得ExpEntry对象,可用于实验数据分析
exp_CaCO3 = a.get_exp_entry("CaCO3")

#Unfortunately, the Materials Project database does not have gas phase experimental entries. This is the value from NIST. We manually create the entry.
#这是一个气相实验,而且数据库没有关于这个的数据条目,所以我们要自己创建
#NIST是化学信息的标准参考数据库
exp_CO2 = ComputedEntry("CO2", -393.51)  #Exp entries should be in kJ/mol.

exp_reaction = ComputedReaction([exp_CaO, exp_CO2], [exp_CaCO3])
예제 #26
0
 def compute(self, input_data):
     return FloatWithUnit(input_data, "g")
예제 #27
0
    stable_result = get_most_stable_entry(result)
except IndexError:
    error["error"] = "No structure with that formula"
    json_dir = output_path + "/" + "output.json"
    with open(json_dir, "w") as outfile:
        json.dump(error, outfile)
    print(error)
    exit()

# print stable_result.name, phase.get_form_energy(stable_result)
(compo,
 factor) = stable_result.composition.get_reduced_composition_and_factor()
form_energy[stable_result.name] = phase.get_form_energy(stable_result) / factor

reaction = ComputedReaction(stable_formula, [stable_result])
energy = FloatWithUnit(reaction.calculated_reaction_energy, "eV atom^-1")

json_result = dict()
json_result["reaction"] = str(reaction)

value1 = dict()
value1["value"] = energy.to("kJ mol^-1")
value1["unit"] = "kJ mol^-1"

value2 = dict()
value2["value"] = energy.to("eV atom^-1")
value2["unit"] = "eV"

json_result["value1"] = value1
json_result["value2"] = value2
json_result["formationenergy"] = form_energy
예제 #28
0
 def b0_GPa(self):
     """
     Returns the bulk modulus in GPa
     """
     return FloatWithUnit(self.params[1], "eV ang^-3").to("GPa")