def setUp(self): struct = Structure.from_str("""FCC Al 1.0 2.473329 0.000000 1.427977 0.824443 2.331877 1.427977 0.000000 0.000000 2.855955 Al 1 direct 0.000000 0.000000 0.000000 Al""", fmt='POSCAR') self.energies = [ -3.69150886, -3.70788383, -3.71997361, -3.72522301, -3.73569569, -3.73649743, -3.74054982 ] self.volumes = [ 14.824542034870653, 18.118887714656875, 15.373596786943025, 17.569833126580278, 15.92265868064787, 17.02077912220064, 16.471717630914863 ] self.eos = "vinet" self.T = 500 self.qhda = QuasiharmonicDebyeApprox(self.energies, self.volumes, struct, t_min=self.T, t_max=self.T, eos=self.eos, anharmonic_contribution=True) self.opt_vol = 17.216094889116807
class TestAnharmonicQuasiharmociDebyeApprox(unittest.TestCase): def setUp(self): struct = Structure.from_str("""FCC Al 1.0 2.473329 0.000000 1.427977 0.824443 2.331877 1.427977 0.000000 0.000000 2.855955 Al 1 direct 0.000000 0.000000 0.000000 Al""", fmt='POSCAR') self.energies = [ -3.69150886, -3.70788383, -3.71997361, -3.72522301, -3.73569569, -3.73649743, -3.74054982 ] self.volumes = [ 14.824542034870653, 18.118887714656875, 15.373596786943025, 17.569833126580278, 15.92265868064787, 17.02077912220064, 16.471717630914863 ] self.eos = "vinet" self.T = 500 self.qhda = QuasiharmonicDebyeApprox(self.energies, self.volumes, struct, t_min=self.T, t_max=self.T, eos=self.eos, anharmonic_contribution=True) self.opt_vol = 17.216094889116807 def test_optimum_volume(self): opt_vol = self.qhda.optimum_volumes[0] np.testing.assert_almost_equal(opt_vol, self.opt_vol, 3) def test_debye_temperature(self): theta = self.qhda.debye_temperature(self.opt_vol) np.testing.assert_approx_equal(theta, 601.239096, 4) def test_gruneisen_paramter(self): gamma = self.qhda.gruneisen_parameter(0, self.qhda.ev_eos_fit.v0) np.testing.assert_almost_equal(gamma, 2.188302, 3) def test_thermal_conductivity(self): kappa = self.qhda.thermal_conductivity(self.T, self.opt_vol) np.testing.assert_almost_equal(kappa, 21.810997, 1) def test_vibrational_internal_energy(self): u = self.qhda.vibrational_internal_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(u, 0.13845, 3) def test_vibrational_free_energy(self): A = self.qhda.vibrational_free_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(A, -0.014620, 3)
class TestAnharmonicQuasiharmociDebyeApprox(unittest.TestCase): def setUp(self): struct = Structure.from_str("""FCC Al 1.0 2.473329 0.000000 1.427977 0.824443 2.331877 1.427977 0.000000 0.000000 2.855955 Al 1 direct 0.000000 0.000000 0.000000 Al""", fmt='POSCAR') self.energies = [-3.69150886, -3.70788383, -3.71997361, -3.72522301, -3.73569569, -3.73649743, -3.74054982] self.volumes = [14.824542034870653, 18.118887714656875, 15.373596786943025, 17.569833126580278, 15.92265868064787, 17.02077912220064, 16.471717630914863] self.eos = "vinet" self.T = 500 self.qhda = QuasiharmonicDebyeApprox(self.energies, self.volumes, struct, t_min=self.T, t_max=self.T, eos=self.eos, anharmonic_contribution=True) self.opt_vol = 17.216094889116807 def test_optimum_volume(self): opt_vol = self.qhda.optimum_volumes[0] np.testing.assert_almost_equal(opt_vol, self.opt_vol, 3) def test_debye_temperature(self): theta = self.qhda.debye_temperature(self.opt_vol) np.testing.assert_approx_equal(theta, 601.239096, 4 ) def test_gruneisen_paramter(self): gamma = self.qhda.gruneisen_parameter(0, self.qhda.ev_eos_fit.v0) np.testing.assert_almost_equal(gamma, 2.188302, 3) def test_thermal_conductivity(self): kappa = self.qhda.thermal_conductivity(self.T, self.opt_vol) np.testing.assert_almost_equal(kappa, 21.810997, 1) def test_vibrational_internal_energy(self): u = self.qhda.vibrational_internal_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(u, 0.13845, 3) def test_vibrational_free_energy(self): A = self.qhda.vibrational_free_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(A, -0.014620, 3)
def setUp(self): struct = Structure.from_dict({ 'lattice': {'a': 2.5630200477817295, 'alpha': 59.999993839702206, 'b': 2.563020442699644, 'beta': 59.999988742674944, 'c': 2.56301993, 'gamma': 60.00000504373715, 'matrix': [[2.21964022, 0.0, 1.28151046], [0.73987974, 2.09269747, 1.28151046], [-0.0, -0.0, 2.56301993]], 'volume': 11.905318492097948}, 'sites': [{'abc': [-0.0, -0.0, -0.0], 'label': 'B', 'species': [{'element': 'B', 'occu': 1}], 'xyz': [0.0, 0.0, 0.0]}, {'abc': [0.25, 0.25, 0.25], 'label': 'N', 'species': [{'element': 'N', 'occu': 1}], 'xyz': [0.73987999, 0.5231743675, 1.2815102125]}]}) self.energies = [-15.76315281, -16.11541813, -16.41784171, -16.47471523, -16.63624155, -16.6741551, -16.78661144, -16.88768073, -16.92450672, -17.04863261, -17.06126553, -17.15786866, -17.19784976, -17.25078749, -17.30017149, -17.32578594, -17.3708922, -17.38125127, -17.41231934, -17.41534352, -17.42636644] self.volumes = [8.678977833994137, 8.971505437031707, 9.27052889309282, 15.845976281427582, 15.417733609491387, 9.576127994353376, 14.997270631725604, 9.888370962140854, 14.584523227465766, 14.179424329180256, 10.20732378093211, 13.78189117535765, 10.533067462993838, 13.391864274742145, 10.865663655755416, 13.009260480347871, 11.205193091129587, 12.634015019827533, 11.551718049704352, 12.26606042141808, 11.90531496343142] self.eos = "vinet" self.T = 300 self.qhda = QuasiharmonicDebyeApprox(self.energies, self.volumes, struct, t_min=self.T, t_max=self.T, eos=self.eos) self.opt_vol = 11.957803302392925
def setUp(self): struct = Structure.from_str("""FCC Al 1.0 2.473329 0.000000 1.427977 0.824443 2.331877 1.427977 0.000000 0.000000 2.855955 Al 1 direct 0.000000 0.000000 0.000000 Al""", fmt='POSCAR') self.energies = [-3.69150886, -3.70788383, -3.71997361, -3.72522301, -3.73569569, -3.73649743, -3.74054982] self.volumes = [14.824542034870653, 18.118887714656875, 15.373596786943025, 17.569833126580278, 15.92265868064787, 17.02077912220064, 16.471717630914863] self.eos = "vinet" self.T = 500 self.qhda = QuasiharmonicDebyeApprox(self.energies, self.volumes, struct, t_min=self.T, t_max=self.T, eos=self.eos, anharmonic_contribution=True) self.opt_vol = 17.216094889116807
def run_task(self, fw_spec): gibbs_dict = {} tag = self["tag"] t_step = self.get("t_step", 10) t_min = self.get("t_min", 0) t_max = self.get("t_max", 1000) mesh = self.get("mesh", [20, 20, 20]) eos = self.get("eos", "vinet") qha_type = self.get("qha_type", "debye_model") pressure = self.get("pressure", 0.0) poisson = self.get("poisson", 0.25) anharmonic_contribution = self.get("anharmonic_contribution", False) gibbs_dict["metadata"] = self.get("metadata", {}) db_file = env_chk(self.get("db_file"), fw_spec) mmdb = VaspCalcDb.from_db_file(db_file, admin=True) # get the optimized structure d = mmdb.collection.find_one( {"task_label": "{} structure optimization".format(tag)}, {"calcs_reversed": 1}) structure = Structure.from_dict( d["calcs_reversed"][-1]["output"]['structure']) gibbs_dict["structure"] = structure.as_dict() gibbs_dict["formula_pretty"] = structure.composition.reduced_formula # get the data(energy, volume, force constant) from the deformation runs docs = mmdb.collection.find( { "task_label": { "$regex": "{} gibbs*".format(tag) }, "formula_pretty": structure.composition.reduced_formula }, {"calcs_reversed": 1}) energies = [] volumes = [] force_constants = [] for d in docs: s = Structure.from_dict( d["calcs_reversed"][-1]["output"]['structure']) energies.append(d["calcs_reversed"][-1]["output"]['energy']) if qha_type not in ["debye_model"]: force_constants.append( d["calcs_reversed"][-1]["output"]['force_constants']) volumes.append(s.volume) gibbs_dict["energies"] = energies gibbs_dict["volumes"] = volumes if qha_type not in ["debye_model"]: gibbs_dict["force_constants"] = force_constants try: # use quasi-harmonic debye approximation if qha_type in ["debye_model"]: from pymatgen.analysis.quasiharmonic import QuasiharmonicDebyeApprox qhda = QuasiharmonicDebyeApprox( energies, volumes, structure, t_min, t_step, t_max, eos, pressure=pressure, poisson=poisson, anharmonic_contribution=anharmonic_contribution) gibbs_dict.update(qhda.get_summary_dict()) gibbs_dict["anharmonic_contribution"] = anharmonic_contribution gibbs_dict["success"] = True # use the phonopy interface else: from atomate.vasp.analysis.phonopy import get_phonopy_gibbs G, T = get_phonopy_gibbs(energies, volumes, force_constants, structure, t_min, t_step, t_max, mesh, eos, pressure) gibbs_dict["gibbs_free_energy"] = G gibbs_dict["temperatures"] = T gibbs_dict["success"] = True # quasi-harmonic analysis failed, set the flag to false except: import traceback logger.warn("Quasi-harmonic analysis failed!") gibbs_dict["success"] = False gibbs_dict["traceback"] = traceback.format_exc() gibbs_dict['metadata'].update({"task_label_tag": tag}) gibbs_dict["created_at"] = datetime.utcnow() gibbs_dict = jsanitize(gibbs_dict) # TODO: @matk86: add a list of task_ids that were used to construct the analysis to DB? # -computron if not db_file: dump_file = "gibbs.json" logger.info("Dumping the analysis summary to {}".format(dump_file)) with open(dump_file, "w") as f: f.write(json.dumps(gibbs_dict, default=DATETIME_HANDLER)) else: coll = mmdb.db["gibbs_tasks"] coll.insert_one(gibbs_dict) logger.info("Gibbs free energy calculation complete.") if not gibbs_dict["success"]: return FWAction(defuse_children=True)
class TestQuasiharmociDebyeApprox(unittest.TestCase): def setUp(self): struct = Structure.from_dict( { "lattice": { "a": 2.5630200477817295, "alpha": 59.999993839702206, "b": 2.563020442699644, "beta": 59.999988742674944, "c": 2.56301993, "gamma": 60.00000504373715, "matrix": [ [2.21964022, 0.0, 1.28151046], [0.73987974, 2.09269747, 1.28151046], [-0.0, -0.0, 2.56301993], ], "volume": 11.905318492097948, }, "sites": [ { "abc": [-0.0, -0.0, -0.0], "label": "B", "species": [{"element": "B", "occu": 1}], "xyz": [0.0, 0.0, 0.0], }, { "abc": [0.25, 0.25, 0.25], "label": "N", "species": [{"element": "N", "occu": 1}], "xyz": [0.73987999, 0.5231743675, 1.2815102125], }, ], } ) self.energies = [ -15.76315281, -16.11541813, -16.41784171, -16.47471523, -16.63624155, -16.6741551, -16.78661144, -16.88768073, -16.92450672, -17.04863261, -17.06126553, -17.15786866, -17.19784976, -17.25078749, -17.30017149, -17.32578594, -17.3708922, -17.38125127, -17.41231934, -17.41534352, -17.42636644, ] self.volumes = [ 8.678977833994137, 8.971505437031707, 9.27052889309282, 15.845976281427582, 15.417733609491387, 9.576127994353376, 14.997270631725604, 9.888370962140854, 14.584523227465766, 14.179424329180256, 10.20732378093211, 13.78189117535765, 10.533067462993838, 13.391864274742145, 10.865663655755416, 13.009260480347871, 11.205193091129587, 12.634015019827533, 11.551718049704352, 12.26606042141808, 11.90531496343142, ] self.eos = "vinet" self.T = 300 self.qhda = QuasiharmonicDebyeApprox( self.energies, self.volumes, struct, t_min=self.T, t_max=self.T, eos=self.eos, ) self.opt_vol = 11.957803302392925 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) def test_optimum_volume(self): opt_vol = self.qhda.optimum_volumes[0] np.testing.assert_almost_equal(opt_vol, self.opt_vol, 3) def test_debye_temperature(self): theta = self.qhda.debye_temperature(self.opt_vol) np.testing.assert_almost_equal(theta, 2559.675227, 3) def test_gruneisen_paramter(self): gamma = self.qhda.gruneisen_parameter(self.T, self.opt_vol) np.testing.assert_almost_equal(gamma, 1.670486, 3) def test_thermal_conductivity(self): kappa = self.qhda.thermal_conductivity(self.T, self.opt_vol) np.testing.assert_almost_equal(kappa, 131.736242, 1) def test_vibrational_internal_energy(self): u = self.qhda.vibrational_internal_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(u, 0.50102, 3) def test_vibrational_free_energy(self): A = self.qhda.vibrational_free_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(A, 0.494687, 3)
class TestQuasiharmociDebyeApprox(unittest.TestCase): def setUp(self): struct = Structure.from_dict({ 'lattice': {'a': 2.5630200477817295, 'alpha': 59.999993839702206, 'b': 2.563020442699644, 'beta': 59.999988742674944, 'c': 2.56301993, 'gamma': 60.00000504373715, 'matrix': [[2.21964022, 0.0, 1.28151046], [0.73987974, 2.09269747, 1.28151046], [-0.0, -0.0, 2.56301993]], 'volume': 11.905318492097948}, 'sites': [{'abc': [-0.0, -0.0, -0.0], 'label': 'B', 'species': [{'element': 'B', 'occu': 1}], 'xyz': [0.0, 0.0, 0.0]}, {'abc': [0.25, 0.25, 0.25], 'label': 'N', 'species': [{'element': 'N', 'occu': 1}], 'xyz': [0.73987999, 0.5231743675, 1.2815102125]}]}) self.energies = [-15.76315281, -16.11541813, -16.41784171, -16.47471523, -16.63624155, -16.6741551, -16.78661144, -16.88768073, -16.92450672, -17.04863261, -17.06126553, -17.15786866, -17.19784976, -17.25078749, -17.30017149, -17.32578594, -17.3708922, -17.38125127, -17.41231934, -17.41534352, -17.42636644] self.volumes = [8.678977833994137, 8.971505437031707, 9.27052889309282, 15.845976281427582, 15.417733609491387, 9.576127994353376, 14.997270631725604, 9.888370962140854, 14.584523227465766, 14.179424329180256, 10.20732378093211, 13.78189117535765, 10.533067462993838, 13.391864274742145, 10.865663655755416, 13.009260480347871, 11.205193091129587, 12.634015019827533, 11.551718049704352, 12.26606042141808, 11.90531496343142] self.eos = "vinet" self.T = 300 self.qhda = QuasiharmonicDebyeApprox(self.energies, self.volumes, struct, t_min=self.T, t_max=self.T, eos=self.eos) self.opt_vol = 11.957803302392925 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) def test_optimum_volume(self): opt_vol = self.qhda.optimum_volumes[0] np.testing.assert_almost_equal(opt_vol, self.opt_vol, 3) def test_debye_temperature(self): theta = self.qhda.debye_temperature(self.opt_vol) np.testing.assert_almost_equal(theta, 2559.675227, 3) def test_gruneisen_paramter(self): gamma = self.qhda.gruneisen_parameter(self.T, self.opt_vol) np.testing.assert_almost_equal(gamma, 1.670486, 3) def test_thermal_conductivity(self): kappa = self.qhda.thermal_conductivity(self.T, self.opt_vol) np.testing.assert_almost_equal(kappa, 131.736242, 1) def test_vibrational_internal_energy(self): u = self.qhda.vibrational_internal_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(u, 0.50102, 3) def test_vibrational_free_energy(self): A = self.qhda.vibrational_free_energy(self.T, self.opt_vol) np.testing.assert_almost_equal(A, 0.494687, 3)
def run_task(self, fw_spec): gibbs_dict = {} tag = self["tag"] t_step = self.get("t_step", 10) t_min = self.get("t_min", 0) t_max = self.get("t_max", 1000) mesh = self.get("mesh", [20, 20, 20]) eos = self.get("eos", "vinet") qha_type = self.get("qha_type", "debye_model") pressure = self.get("pressure", 0.0) poisson = self.get("poisson", 0.25) anharmonic_contribution = self.get("anharmonic_contribution", False) gibbs_dict["metadata"] = self.get("metadata", {}) db_file = env_chk(self.get("db_file"), fw_spec) mmdb = VaspCalcDb.from_db_file(db_file, admin=True) # get the optimized structure d = mmdb.collection.find_one({"task_label": "{} structure optimization".format(tag)}, {"calcs_reversed": 1}) structure = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure']) gibbs_dict["structure"] = structure.as_dict() gibbs_dict["formula_pretty"] = structure.composition.reduced_formula # get the data(energy, volume, force constant) from the deformation runs docs = mmdb.collection.find({"task_label": {"$regex": "{} gibbs*".format(tag)}, "formula_pretty": structure.composition.reduced_formula}, {"calcs_reversed": 1}) energies = [] volumes = [] force_constants = [] for d in docs: s = Structure.from_dict(d["calcs_reversed"][-1]["output"]['structure']) energies.append(d["calcs_reversed"][-1]["output"]['energy']) if qha_type not in ["debye_model"]: force_constants.append(d["calcs_reversed"][-1]["output"]['force_constants']) volumes.append(s.volume) gibbs_dict["energies"] = energies gibbs_dict["volumes"] = volumes if qha_type not in ["debye_model"]: gibbs_dict["force_constants"] = force_constants try: # use quasi-harmonic debye approximation if qha_type in ["debye_model"]: from pymatgen.analysis.quasiharmonic import QuasiharmonicDebyeApprox qhda = QuasiharmonicDebyeApprox(energies, volumes, structure, t_min, t_step, t_max, eos, pressure=pressure, poisson=poisson, anharmonic_contribution=anharmonic_contribution) gibbs_dict.update(qhda.get_summary_dict()) gibbs_dict["anharmonic_contribution"] = anharmonic_contribution gibbs_dict["success"] = True # use the phonopy interface else: from atomate.vasp.analysis.phonopy import get_phonopy_gibbs G, T = get_phonopy_gibbs(energies, volumes, force_constants, structure, t_min, t_step, t_max, mesh, eos, pressure) gibbs_dict["gibbs_free_energy"] = G gibbs_dict["temperatures"] = T gibbs_dict["success"] = True # quasi-harmonic analysis failed, set the flag to false except: import traceback logger.warn("Quasi-harmonic analysis failed!") gibbs_dict["success"] = False gibbs_dict["traceback"] = traceback.format_exc() gibbs_dict['metadata'].update({"task_label_tag": tag}) gibbs_dict["created_at"] = datetime.utcnow() gibbs_dict = jsanitize(gibbs_dict) # TODO: @matk86: add a list of task_ids that were used to construct the analysis to DB? # -computron if not db_file: dump_file = "gibbs.json" logger.info("Dumping the analysis summary to {}".format(dump_file)) with open(dump_file, "w") as f: f.write(json.dumps(gibbs_dict, default=DATETIME_HANDLER)) else: coll = mmdb.db["gibbs_tasks"] coll.insert_one(gibbs_dict) logger.info("Gibbs free energy calculation complete.") if not gibbs_dict["success"]: return FWAction(defuse_children=True)