def setup(self): """ setup static jobs for all the calibrate objects copies CONTCAR to POSCAR sets NSW = 0 """ for cal in self.cal_objs: for i, jdir in enumerate(cal.old_job_dir_list): job_dir = self.job_dir + os.sep \ + jdir.replace(os.sep, '_').replace('.', '_') \ + os.sep + 'STATIC' logger.info('setting up job in {}'.format(job_dir)) cal.incar = Incar.from_file(jdir + os.sep + 'INCAR') cal.incar['EDIFF'] = '1E-6' cal.incar['NSW'] = 0 cal.potcar = Potcar.from_file(jdir + os.sep + 'POTCAR') cal.kpoints = Kpoints.from_file(jdir + os.sep + 'KPOINTS') contcar_file = jdir + os.sep + 'CONTCAR' if os.path.isfile(contcar_file): logger.info('setting poscar file from {}' .format(contcar_file)) cal.poscar = Poscar.from_file(contcar_file) cal.add_job(job_dir=job_dir) else: logger.critical("""CONTCAR doesnt exist. Setting up job using input set in the old calibration directory""") cal.poscar = Poscar.from_file(jdir + os.sep + 'POSCAR') cal.add_job(job_dir=job_dir)
def test_write(self): filepath = os.path.join(test_dir, "POSCAR") poscar = Poscar.from_file(filepath) tempfname = "POSCAR.testing" poscar.write_file(tempfname) p = Poscar.from_file(tempfname) self.assertArrayAlmostEqual(poscar.structure.lattice.abc, p.structure.lattice.abc, 5) os.remove(tempfname)
def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.Li2O'), check_for_POTCAR=False) s1 = p.structure p = Poscar.from_file(os.path.join(test_dir, 'CONTCAR.Li2O'), check_for_POTCAR=False) s2 = p.structure self.analyzer = RelaxationAnalyzer(s1, s2)
def test_write(self): filepath = self.TEST_FILES_DIR / 'POSCAR' poscar = Poscar.from_file(filepath) tempfname = Path("POSCAR.testing") poscar.write_file(tempfname) p = Poscar.from_file(tempfname) self.assertArrayAlmostEqual(poscar.structure.lattice.abc, p.structure.lattice.abc, 5) tempfname.unlink()
def test_write_MD_poscar(self): # Parsing from an MD type run with velocities and predictor corrector data # And writing a new POSCAR from the new structure p = Poscar.from_file(os.path.join(test_dir, "CONTCAR.MD"), check_for_POTCAR=False) tempfname = "POSCAR.testing" p.write_file(tempfname) p3 = Poscar.from_file(tempfname) self.assertArrayAlmostEqual(p.structure.lattice.abc, p3.structure.lattice.abc, 5) self.assertArrayAlmostEqual(p.velocities, p3.velocities, 5) self.assertArrayAlmostEqual(p.predictor_corrector, p3.predictor_corrector, 5) self.assertEqual(p.predictor_corrector_preamble, p3.predictor_corrector_preamble) os.remove(tempfname)
def test_static_constructors(self): kpoints = Kpoints.gamma_automatic([3, 3, 3], [0, 0, 0]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) self.assertEqual(kpoints.kpts, [[3, 3, 3]]) kpoints = Kpoints.monkhorst_automatic([2, 2, 2], [0, 0, 0]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Monkhorst) self.assertEqual(kpoints.kpts, [[2, 2, 2]]) kpoints = Kpoints.automatic(100) self.assertEqual(kpoints.style, Kpoints.supported_modes.Automatic) self.assertEqual(kpoints.kpts, [[100]]) filepath = os.path.join(test_dir, "POSCAR") poscar = Poscar.from_file(filepath) kpoints = Kpoints.automatic_density(poscar.structure, 500) self.assertEqual(kpoints.kpts, [[2, 4, 4]]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Monkhorst) kpoints = Kpoints.automatic_density(poscar.structure, 500, True) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) kpoints = Kpoints.automatic_density_by_vol(poscar.structure, 1000) self.assertEqual(kpoints.kpts, [[6, 11, 13]]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) s = poscar.structure s.make_supercell(3) kpoints = Kpoints.automatic_density(s, 500) self.assertEqual(kpoints.kpts, [[1, 1, 1]]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma)
def set_sd_flags(poscar_input=None, n_layers=2, top=True, bottom=True, poscar_output='POSCAR2'): """ set the relaxation flags for top and bottom layers of interface. The upper and lower bounds of the z coordinate are determined based on the slab. Args: poscar_input: input poscar file name n_layers: number of layers to be relaxed top: whether n_layers from top are be relaxed bottom: whether n_layers from bottom are be relaxed poscar_output: output poscar file name Returns: None writes the modified poscar file """ poscar1 = Poscar.from_file(poscar_input) sd_flags = np.zeros_like(poscar1.structure.frac_coords) z_coords = poscar1.structure.frac_coords[:, 2] z_lower_bound, z_upper_bound = None, None if bottom: z_lower_bound = np.unique(z_coords)[n_layers - 1] sd_flags[np.where(z_coords <= z_lower_bound)] = np.ones((1, 3)) if top: z_upper_bound = np.unique(z_coords)[-n_layers] sd_flags[np.where(z_coords >= z_upper_bound)] = np.ones((1, 3)) poscar2 = Poscar(poscar1.structure, selective_dynamics=sd_flags.tolist()) poscar2.write_file(filename=poscar_output)
def test_apply_transformation(self): trans = MagOrderingTransformation({"Fe": 5}) p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) s = p.structure alls = trans.apply_transformation(s, 10) self.assertEqual(len(alls), 3) f = SpacegroupAnalyzer(alls[0]["structure"], 0.1) self.assertEqual(f.get_space_group_number(), 31) model = IsingModel(5, 5) trans = MagOrderingTransformation({"Fe": 5}, energy_model=model) alls2 = trans.apply_transformation(s, 10) # Ising model with +J penalizes similar neighbor magmom. self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"]) self.assertEqual(alls[0]["structure"], alls2[2]["structure"]) s = self.get_structure('Li2O') # Li2O doesn't have magnetism of course, but this is to test the # enumeration. trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3) alls = trans.apply_transformation(s, 100) # TODO: check this is correct, unclear what len(alls) should be self.assertEqual(len(alls), 12) trans = MagOrderingTransformation({"Ni": 5}) alls = trans.apply_transformation(self.NiO.get_primitive_structure(), return_ranked_list=10) self.assertEqual(self.NiO_AFM_111.lattice, alls[0]["structure"].lattice) self.assertEqual(self.NiO_AFM_001.lattice, alls[1]["structure"].lattice)
def test_static_constructors(self): kpoints = Kpoints.gamma_automatic([3, 3, 3], [0, 0, 0]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) self.assertEqual(kpoints.kpts, [[3, 3, 3]]) kpoints = Kpoints.monkhorst_automatic([2, 2, 2], [0, 0, 0]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Monkhorst) self.assertEqual(kpoints.kpts, [[2, 2, 2]]) kpoints = Kpoints.automatic(100) self.assertEqual(kpoints.style, Kpoints.supported_modes.Automatic) self.assertEqual(kpoints.kpts, [[100]]) filepath = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(filepath) kpoints = Kpoints.automatic_density(poscar.structure, 500) self.assertEqual(kpoints.kpts, [[1, 3, 3]]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) kpoints = Kpoints.automatic_density(poscar.structure, 500, True) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) kpoints = Kpoints.automatic_density_by_vol(poscar.structure, 1000) self.assertEqual(kpoints.kpts, [[6, 10, 13]]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) s = poscar.structure s.make_supercell(3) kpoints = Kpoints.automatic_density(s, 500) self.assertEqual(kpoints.kpts, [[1, 1, 1]]) self.assertEqual(kpoints.style, Kpoints.supported_modes.Gamma) kpoints = Kpoints.from_string("""k-point mesh 0 G 10 10 10 0.5 0.5 0.5 """) self.assertArrayAlmostEqual(kpoints.kpts_shift, [0.5, 0.5, 0.5])
def test_from_md_run(self): #Parsing from an MD type run with velocities p = Poscar.from_file(os.path.join(test_dir, "CONTCAR.MD"), check_for_POTCAR=False) self.assertAlmostEqual(np.sum(np.array(p.velocities)), 0.0065417961324) self.assertEqual(p.predictor_corrector[0][0], 1) self.assertEqual(p.predictor_corrector[1][0], 2)
def read_poscar(i_path, l_get_sorted_symbols=False): poscar = Poscar.from_file("{}".format(i_path)) struct = poscar.structure if l_get_sorted_symbols: return struct, poscar.site_symbols else: return struct
def setUp(self): file_path = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(file_path) self.struct = poscar.structure self.mvl_npt_set = MVLNPTMDSet(self.struct, start_temp=0, end_temp=300, nsteps=1000) warnings.simplefilter("ignore")
def test_ferrimagnetic(self): trans = MagOrderingTransformation({"Fe": 5}, 0.75, max_cell_size=1) p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) s = p.structure alls = trans.apply_transformation(s, 10) self.assertEqual(len(alls), 2)
def test_get_structure(self): if not aio.ase_loaded: raise SkipTest("ASE not present. Skipping...") p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) atoms = aio.AseAtomsAdaptor.get_atoms(p.structure) self.assertEqual(aio.AseAtomsAdaptor.get_structure(atoms).formula, "Fe4 P4 O16")
def test_apply_transformation(self): enum_trans = EnumerateStructureTransformation(refine_structure=True) p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) struct = p.structure expected_ans = [1, 3, 1] for i, frac in enumerate([0.25, 0.5, 0.75]): trans = SubstitutionTransformation({'Fe': {'Fe': frac}}) s = trans.apply_transformation(struct) oxitrans = OxidationStateDecorationTransformation( {'Li': 1, 'Fe': 2, 'P': 5, 'O': -2}) s = oxitrans.apply_transformation(s) alls = enum_trans.apply_transformation(s, 100) self.assertEqual(len(alls), expected_ans[i]) self.assertIsInstance(trans.apply_transformation(s), Structure) for s in alls: self.assertIn("energy", s) #make sure it works for non-oxidation state decorated structure trans = SubstitutionTransformation({'Fe': {'Fe': 0.5}}) s = trans.apply_transformation(struct) alls = enum_trans.apply_transformation(s, 100) self.assertEqual(len(alls), 3) self.assertIsInstance(trans.apply_transformation(s), Structure) for s in alls: self.assertNotIn("energy", s)
def test_init_from_structure(self): filepath = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(filepath) struct = poscar.structure xyz = XYZ(struct) ans = """24 Fe4 P4 O16 Fe 2.277347 4.550379 2.260125 Fe 2.928536 1.516793 4.639870 Fe 7.483231 4.550379 0.119620 Fe 8.134420 1.516793 2.499364 P 0.985089 1.516793 1.990624 P 4.220794 4.550379 4.370369 P 6.190973 1.516793 0.389120 P 9.426677 4.550379 2.768865 O 0.451582 4.550379 3.365614 O 1.006219 1.516793 3.528306 O 1.725331 0.279529 1.358282 O 1.725331 2.754057 1.358282 O 3.480552 3.313115 3.738027 O 3.480552 5.787643 3.738027 O 4.199665 4.550379 1.148562 O 4.754301 1.516793 0.985870 O 5.657466 4.550379 3.773620 O 6.212102 1.516793 3.610928 O 6.931215 0.279529 1.021463 O 6.931215 2.754057 1.021463 O 8.686436 3.313115 3.401208 O 8.686436 5.787643 3.401208 O 9.405548 4.550379 1.231183 O 9.960184 1.516793 1.393875""" self.assertEqual(str(xyz), ans)
def run_task(self, fw_spec): chgcar_start = False # read the VaspInput from the previous run poscar = Poscar.from_file(zpath('POSCAR')) incar = Incar.from_file(zpath('INCAR')) # figure out what GGA+U values to use and override them # LDAU values to use mpvis = MPVaspInputSet() ggau_incar = mpvis.get_incar(poscar.structure).as_dict() incar_updates = {k: ggau_incar[k] for k in ggau_incar.keys() if 'LDAU' in k} for k in ggau_incar: # update any parameters not set explicitly in previous INCAR if k not in incar and k in ggau_incar: incar_updates[k] = ggau_incar[k] incar.update(incar_updates) # override the +U keys # start from the CHGCAR of previous run if os.path.exists('CHGCAR'): incar['ICHARG'] = 1 chgcar_start = True # write back the new INCAR to the current directory incar.write_file('INCAR') return FWAction(stored_data={'chgcar_start': chgcar_start})
def setUp(self): if "VASP_PSP_DIR" not in os.environ: os.environ["VASP_PSP_DIR"] = test_dir filepath = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(filepath) self.struct = poscar.structure self.mitparamset = MITVaspInputSet() self.mitparamset_unsorted = MITVaspInputSet(sort_structure=False) self.mithseparamset = MITHSEVaspInputSet() self.paramset = MPVaspInputSet() self.userparamset = MPVaspInputSet( user_incar_settings={'MAGMOM': {"Fe": 10, "S": -5, "Mn3+": 100}} ) self.mitggaparam = MITGGAVaspInputSet() self.mpstaticparamset = MPStaticVaspInputSet() self.mpnscfparamsetu = MPNonSCFVaspInputSet( {"NBANDS": 50}, mode="Uniform") self.mpnscfparamsetl = MPNonSCFVaspInputSet( {"NBANDS": 60}, mode="Line") self.mphseparamset = MPHSEVaspInputSet() self.mpbshseparamsetl = MPBSHSEVaspInputSet(mode="Line") self.mpbshseparamsetu = MPBSHSEVaspInputSet( mode="Uniform", added_kpoints=[[0.5, 0.5, 0.0]]) self.mpdielparamset = MPStaticDielectricDFPTVaspInputSet()
def test_from_md_run(self): # Parsing from an MD type run with velocities and predictor corrector data p = Poscar.from_file(os.path.join(test_dir, "CONTCAR.MD"), check_for_POTCAR=False) self.assertAlmostEqual(np.sum(np.array(p.velocities)), 0.0065417961324) self.assertEqual(p.predictor_corrector[0][0][0], 0.33387820E+00) self.assertEqual(p.predictor_corrector[0][1][1], -0.10583589E-02)
def setUp(self): file_path = self.TEST_FILES_DIR / 'POSCAR' poscar = Poscar.from_file(file_path) self.struct = poscar.structure self.mvl_npt_set = MVLNPTMDSet(self.struct, start_temp=0, end_temp=300, nsteps=1000) warnings.simplefilter("ignore")
def test_from_file(self): filepath = os.path.join(test_dir, "POSCAR.symbols_natoms_multilines") poscar = Poscar.from_file(filepath, check_for_POTCAR=False, read_velocities=False) ordered_expected_elements = [ "Fe", "Cr", "Fe", "Fe", "Cr", "Cr", "Cr", "Cr", "Fe", "Fe", "Cr", "Fe", "Cr", "Fe", "Fe", "Cr", "Fe", "Cr", "Fe", "Fe", "Fe", "Fe", "Cr", "Fe", "Ni", "Fe", "Fe", "Fe", "Fe", "Fe", "Cr", "Cr", "Cr", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Cr", "Fe", "Fe", "Ni", "Fe", "Fe", "Fe", "Cr", "Cr", "Fe", "Fe", "Fe", "Fe", "Fe", ] self.assertEqual([site.specie.symbol for site in poscar.structure], ordered_expected_elements)
def setUp(self): file_path = self.TEST_FILES_DIR / 'POSCAR' poscar = Poscar.from_file(file_path) self.struct = poscar.structure self.mvl_rlx_set = MVLRelax52Set( self.struct, potcar_functional="PBE_54", user_incar_settings={"NSW": 500}) warnings.simplefilter("ignore")
def test_get_atoms(self): if not aio.ase_loaded: raise SkipTest("ASE not present. Skipping...") p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) structure = p.structure atoms = aio.AseAtomsAdaptor.get_atoms(structure) ase_composition = Composition(atoms.get_chemical_formula()) self.assertEqual(ase_composition, structure.composition)
def setUp(self): file_path = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(file_path) self.struct = poscar.structure self.mvl_scan_set = MVLScanRelaxSet(self.struct, potcar_functional="PBE_52", user_incar_settings={"NSW": 500}) warnings.simplefilter("ignore")
def test_apply_transformations_complete_ranking(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) t1 = OxidationStateDecorationTransformation({"Li": 1, "Fe": 2, "P": 5, "O": -2}) s = t1.apply_transformation(p.structure) t = PartialRemoveSpecieTransformation("Li+", 0.5, PartialRemoveSpecieTransformation.ALGO_COMPLETE) self.assertEqual(len(t.apply_transformation(s, 10)), 6)
def test_get_lattice_from_lattice_type(self): cif_structure = """#generated using pymatgen data_FePO4 _symmetry_space_group_name_H-M Pnma _cell_length_a 10.41176687 _cell_length_b 6.06717188 _cell_length_c 4.75948954 _chemical_formula_structural FePO4 _chemical_formula_sum 'Fe4 P4 O16' _cell_volume 300.65685512 _cell_formula_units_Z 4 _symmetry_cell_setting Orthorhombic loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' loop_ _atom_site_type_symbol _atom_site_label _atom_site_symmetry_multiplicity _atom_site_fract_x _atom_site_fract_y _atom_site_fract_z _atom_site_occupancy Fe Fe1 1 0.218728 0.750000 0.474867 1 Fe Fe2 1 0.281272 0.250000 0.974867 1 Fe Fe3 1 0.718728 0.750000 0.025133 1 Fe Fe4 1 0.781272 0.250000 0.525133 1 P P5 1 0.094613 0.250000 0.418243 1 P P6 1 0.405387 0.750000 0.918243 1 P P7 1 0.594613 0.250000 0.081757 1 P P8 1 0.905387 0.750000 0.581757 1 O O9 1 0.043372 0.750000 0.707138 1 O O10 1 0.096642 0.250000 0.741320 1 O O11 1 0.165710 0.046072 0.285384 1 O O12 1 0.165710 0.453928 0.285384 1 O O13 1 0.334290 0.546072 0.785384 1 O O14 1 0.334290 0.953928 0.785384 1 O O15 1 0.403358 0.750000 0.241320 1 O O16 1 0.456628 0.250000 0.207138 1 O O17 1 0.543372 0.750000 0.792862 1 O O18 1 0.596642 0.250000 0.758680 1 O O19 1 0.665710 0.046072 0.214616 1 O O20 1 0.665710 0.453928 0.214616 1 O O21 1 0.834290 0.546072 0.714616 1 O O22 1 0.834290 0.953928 0.714616 1 O O23 1 0.903358 0.750000 0.258680 1 O O24 1 0.956628 0.250000 0.292862 1 """ cp = CifParser.from_string(cif_structure) s_test = cp.get_structures(False)[0] filepath = self.TEST_FILES_DIR / 'POSCAR' poscar = Poscar.from_file(filepath) s_ref = poscar.structure sm = StructureMatcher(stol=0.05, ltol=0.01, angle_tol=0.1) self.assertTrue(sm.fit(s_ref, s_test))
def setup(self): """ setup static jobs for the calibrate objects copies CONTCAR to POSCAR sets NSW = 0 write system.json file for database crawler """ d = {} for cal in self.cal_objs: for i, jdir in enumerate(cal.old_job_dir_list): job_dir = self.job_dir + os.sep \ + jdir.replace(os.sep, '_').replace('.', '_') + \ os.sep + 'STATIC' cal.incar = Incar.from_file(jdir + os.sep + 'INCAR') cal.incar['EDIFF'] = '1E-6' cal.incar['NSW'] = 0 cal.potcar = Potcar.from_file(jdir + os.sep + 'POTCAR') cal.kpoints = Kpoints.from_file(jdir + os.sep + 'KPOINTS') contcar_file = jdir + os.sep + 'CONTCAR' if os.path.isfile(contcar_file): cal.poscar = Poscar.from_file(contcar_file) if cal in self.cal_slabs or cal in self.cal_interfaces: try: d['hkl'] = cal.system['hkl'] except: logger.critical("""the calibrate object doesnt have a system set for calibrating""") if cal in self.cal_interfaces: try: d['ligand'] = cal.system['ligand']['name'] except: logger.critical("""the calibrate object doesnt have a system set for calibrating""") if not os.path.exists(job_dir): os.makedirs(job_dir) if d: with open(job_dir + os.sep + 'system.json', 'w') as f: json.dump(d, f) cal.add_job(job_dir=job_dir) else: logger.critical("""CONTCAR doesnt exist. Setting up job using input set in the old calibration directory""") cal.poscar = Poscar.from_file(jdir + os.sep + 'POSCAR') cal.add_job(job_dir=job_dir)
def test_apply_transformation(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) t = AutoOxiStateDecorationTransformation() s = t.apply_transformation(p.structure) expected_oxi = {"Li": 1, "P": 5, "O":-2, "Fe": 2} for site in s: self.assertEqual(site.specie.oxi_state, expected_oxi[site.specie.symbol])
def test_write_MD_poscar(self): # Parsing from an MD type run with velocities and predictor corrector data # And writing a new POSCAR from the new structure p = Poscar.from_file(self.TEST_FILES_DIR / "CONTCAR.MD", check_for_POTCAR=False) tempfname = Path("POSCAR.testing.md") p.write_file(tempfname) p3 = Poscar.from_file(tempfname) self.assertArrayAlmostEqual(p.structure.lattice.abc, p3.structure.lattice.abc, 5) self.assertArrayAlmostEqual(p.velocities, p3.velocities, 5) self.assertArrayAlmostEqual(p.predictor_corrector, p3.predictor_corrector, 5) self.assertEqual(p.predictor_corrector_preamble, p3.predictor_corrector_preamble) tempfname.unlink()
def test_init(self): filepath = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(filepath,check_for_POTCAR=False) comp = poscar.structure.composition self.assertEqual(comp, Composition("Fe4P4O16")) # Vasp 4 type with symbols at the end. poscar_string = """Test1 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 Si 0.750000 0.500000 0.750000 F """ poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.structure.composition, Composition("SiF")) poscar_string = "" self.assertRaises(ValueError, Poscar.from_string, poscar_string) # Vasp 4 tyle file with default names, i.e. no element symbol found. poscar_string = """Test2 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 direct 0.000000 0.000000 0.000000 0.750000 0.500000 0.750000 """ with warnings.catch_warnings(): warnings.simplefilter("ignore") poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.structure.composition, Composition("HHe")) # Vasp 4 tyle file with default names, i.e. no element symbol found. poscar_string = """Test3 1.0 3.840198 0.000000 0.000000 1.920099 3.325710 0.000000 0.000000 -2.217138 3.135509 1 1 Selective dynamics direct 0.000000 0.000000 0.000000 T T T Si 0.750000 0.500000 0.750000 F F F O """ poscar = Poscar.from_string(poscar_string) self.assertEqual(poscar.selective_dynamics, [[True, True, True], [False, False, False]]) self.selective_poscar = poscar
def test_apply_transformation(self): enum_trans = EnumerateStructureTransformation(refine_structure=True) enum_trans2 = EnumerateStructureTransformation(refine_structure=True, sort_criteria="nsites") p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) struct = p.structure expected_ans = [1, 3, 1] for i, frac in enumerate([0.25, 0.5, 0.75]): trans = SubstitutionTransformation({'Fe': {'Fe': frac}}) s = trans.apply_transformation(struct) oxitrans = OxidationStateDecorationTransformation({ 'Li': 1, 'Fe': 2, 'P': 5, 'O': -2 }) s = oxitrans.apply_transformation(s) alls = enum_trans.apply_transformation(s, 100) self.assertEqual(len(alls), expected_ans[i]) self.assertIsInstance(trans.apply_transformation(s), Structure) for ss in alls: self.assertIn("energy", ss) alls = enum_trans2.apply_transformation(s, 100) self.assertEqual(len(alls), expected_ans[i]) self.assertIsInstance(trans.apply_transformation(s), Structure) for ss in alls: self.assertIn("num_sites", ss) # make sure it works for non-oxidation state decorated structure trans = SubstitutionTransformation({'Fe': {'Fe': 0.5}}) s = trans.apply_transformation(struct) alls = enum_trans.apply_transformation(s, 100) self.assertEqual(len(alls), 3) self.assertIsInstance(trans.apply_transformation(s), Structure) for s in alls: self.assertNotIn("energy", s)
def makeposcarobject(): global folderposcar folderposcar = os.path.join(os.path.abspath("."), filetype) fd = os.open( '/dev/null', os.O_WRONLY ) # redirect stderr to null to avoid error for Ca_sv potential savefd = os.dup(2) os.dup2(fd, 2) global poscar poscar = Poscar.from_file(folderposcar) os.dup2(savefd, 2) # undo redirect for stderr global structure structure = poscar.structure global sheet1 sheet1.write(i, 0, folder) sheet1.write(i, 1, structure.lattice.a) sheet1.write(i, 2, structure.lattice.b) sheet1.write(i, 3, structure.lattice.c) sheet1.write(i, 4, structure.lattice.alpha) sheet1.write(i, 5, structure.lattice.beta) sheet1.write(i, 6, structure.lattice.gamma) sheet1.write(i, 7, structure.lattice.volume)
def test_apply_transformation(self): trans = MagOrderingTransformation({"Fe": 5}) p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) s = p.structure alls = trans.apply_transformation(s, 10) self.assertEqual(len(alls), 3) f = SpacegroupAnalyzer(alls[0]["structure"], 0.1) self.assertEqual(f.get_space_group_number(), 31) model = IsingModel(5, 5) trans = MagOrderingTransformation({"Fe": 5}, energy_model=model) alls2 = trans.apply_transformation(s, 10) # Ising model with +J penalizes similar neighbor magmom. self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"]) self.assertEqual(alls[0]["structure"], alls2[2]["structure"]) s = self.get_structure('Li2O') # Li2O doesn't have magnetism of course, but this is to test the # enumeration. trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3) alls = trans.apply_transformation(s, 100) self.assertEqual(len(alls), 12)
def __init__(self, folder, spin='up'): self.folder = folder self.spin = spin self.vasprun = Vasprun(f'{folder}/vasprun.xml', parse_dos=True, parse_eigen=False, parse_potcar_file=False) self.poscar = Poscar.from_file(f'{folder}/POSCAR', check_for_POTCAR=False, read_velocities=False) self.color_dict = { 0: '#052F5F', 1: '#F46036', 2: '#28502E', 3: '#005377', 4: '#EC465A', 5: '#06A77D', 6: '#4D3956', 7: '#A80874', 8: '#009FFD', } self.spin_dict = {'up': Spin.up, 'down': Spin.down} self.tdos_dict = self.load_tdos() self.pdos_dict = self.load_pdos()
def parse_dft_input(input: str): """ Returns the positions, species, and cell of a POSCAR file. Outputs are specced for OTF module. :param input: POSCAR file input :return: """ pmg_structure = Poscar.from_file(input).structure flare_structure = Structure.from_pmg_structure(pmg_structure) positions = flare_structure.positions species = flare_structure.species_labels cell = flare_structure.cell #TODO Allow for custom masses in POSCAR elements = set(species) # conversion from amu to md units mass_dict = {elt: Element(elt).atomic_mass * 0.000103642695727 for elt in elements} return positions, species, cell, mass_dict
def setup(self): self.currdir = os.getcwd() os.chdir(os.path.join(MODULE_DIR, "../../../test_files")) structure = Poscar.from_file("CONTCAR").structure cr = CoreRegion(Potcar.from_file("POTCAR")) pps = {} labels = {} label = 0 for e in cr.pps: pps[label] = cr.pps[e] labels[e] = label label += 1 clabels = np.array([], np.int32) ls = np.array([], np.int32) projectors = np.array([], np.float64) aewaves = np.array([], np.float64) pswaves = np.array([], np.float64) wgrids = np.array([], np.float64) pgrids = np.array([], np.float64) num_els = 0 for num in pps: pp = pps[num] clabels = np.append(clabels, [num, len(pp.ls), pp.ndata, len(pp.grid)]) ls = np.append(ls, pp.ls) wgrids = np.append(wgrids, pp.grid) pgrids = np.append(pgrids, pp.projgrid) num_els += 1 for i in range(len(pp.ls)): proj = pp.realprojs[i] aepw = pp.aewaves[i] pspw = pp.pswaves[i] projectors = np.append(projectors, proj) aewaves = np.append(aewaves, aepw) pswaves = np.append(pswaves, pspw) print("rmax", cr.pps["Ga"].rmax * 0.529177) selfnums = np.array([labels[el(s)] for s in structure], dtype=np.int32) selfcoords = np.array([], np.float64) for s in structure: selfcoords = np.append(selfcoords, s.frac_coords) f = open("potholder.txt", "w") f.write("%d " % num_els) for i in range(len(clabels)): f.write("%d " % clabels[i]) f.write("%d " % len(ls)) for i in range(len(ls)): f.write("%d " % ls[i]) f.write("%d " % len(pgrids)) for i in range(len(pgrids)): f.write("%f " % pgrids[i]) f.write("%d " % len(wgrids)) for i in range(len(wgrids)): f.write("%f " % wgrids[i]) f.write("%d " % len(projectors)) for i in range(len(projectors)): f.write("%f " % projectors[i]) f.write("%d " % len(aewaves)) for i in range(len(aewaves)): f.write("%f " % aewaves[i]) f.write("%d " % len(pswaves)) for i in range(len(pswaves)): f.write("%f " % pswaves[i]) f.write("%f " % (cr.pps["Ga"].rmax * 0.529177)) f.write("%d " % len(selfnums)) for i in range(len(selfnums)): f.write("%d " % selfnums[i]) for i in range(len(selfnums) * 3): f.write("%f " % selfcoords[i]) f.close()
def update_checkpoint(job_ids=None, jfile=None, **kwargs): """ rerun the jobs with job ids in the job_ids list. The jobs are read from the json checkpoint file, jfile. If no job_ids are given then the checkpoint file will be updated with corresponding final energy Args: job_ids: list of job ids to update or q resolve jfile: check point file """ cal_log = loadfn(jfile, cls=MontyDecoder) cal_log_new = [] all_jobs = [] run_jobs = [] handlers = [] final_energy = None incar = None kpoints = None qadapter = None # if updating the specs of the job for k, v in kwargs.items(): if k == 'incar': incar = v if k == 'kpoints': kpoints = v if k == 'que': qadapter = v for j in cal_log: job = j["job"] job.job_id = j['job_id'] all_jobs.append(job) if job_ids and (j['job_id'] in job_ids or job.job_dir in job_ids): logger.info('setting job {0} in {1} to rerun'.format( j['job_id'], job.job_dir)) contcar_file = job.job_dir + os.sep + 'CONTCAR' poscar_file = job.job_dir + os.sep + 'POSCAR' if os.path.isfile(contcar_file) and len( open(contcar_file).readlines()) != 0: logger.info('setting poscar file from {}'.format(contcar_file)) job.vis.poscar = Poscar.from_file(contcar_file) else: logger.info('setting poscar file from {}'.format(poscar_file)) job.vis.poscar = Poscar.from_file(poscar_file) if incar: logger.info('incar overridden') job.vis.incar = incar if kpoints: logger.info('kpoints overridden') job.vis.kpoints = kpoints if qadapter: logger.info('qadapter overridden') job.vis.qadapter = qadapter run_jobs.append(job) if run_jobs: c = Custodian(handlers, run_jobs, max_errors=5) c.run() for j in all_jobs: final_energy = j.get_final_energy() cal_log_new.append({ "job": j.as_dict(), 'job_id': j.job_id, "corrections": [], 'final_energy': final_energy }) dumpfn(cal_log_new, jfile, cls=MontyEncoder, indent=4)
def direct2cartesian(POSCAR_input, POSCAR_output): """ given a poscar file in direct coords, output a poscar file in cartesian coords """ poscar = Poscar.from_file(POSCAR_input) poscar.write_file(POSCAR_output, direct=False)
def add_alt_projected_dispersion(ax, data, pdata, quantity, projected, bandmin=None, bandmax=None, temperature=300, direction='avg', poscar='POSCAR', main=True, log=False, interpolate=10000, smoothing=10, colour='viridis', cmin=None, cmax=None, cscale=None, unoccupied='grey', workers=32, xmarkkwargs={}, **kwargs): """Plots a phono3py quantity on a high-symmetry path and projection. Just because you can, doesn't mean you should. A maxim I may fail to live up to, so I leave it to you, dear reader, to decide for yourself. Requires a POSCAR. Arguments --------- ax : axes axes to plot on. data : dict Phono3py-like data containing: qpoint : array-like q-point locations. (quantities) : array-like plotted and projected quantities. temperature : array-like, optional temperature, if necessary for quantities. pdata : dict phonon dispersion data containing: q-point : array-like qpoint locations. x : array-like high-symmetry path. tick_position : array-like x-tick positions. tick_label : array-like x-tick labels. quantity : str quantity to plot. projected: str quantity to project. bandmin : int, optional Zero-indexed minimum band index to plot. Default: 0. bandmax : int, optional Zero-indexed maximum band index to plot. Default: max index. temperature : float, optional approximate temperature in K (finds closest). Default: 300. direction : str, optional direction from anisotropic data, accepts x-z/ a-c, average/ avg or normal/ norm. Default: average. poscar : str, optional VASP POSCAR filepath. Default: POSCAR. main : bool, optional set axis ticks, label, limits. Default: True. log : bool, optional log the y scale. Default: False. interpolate : int, optional number of points per line. Default: 10,000. smoothing : int, optional every n points to sample. Default: 10. colour : colormap or str, optional colourmap or colourmap name. Default: viridis. cmin : float, optional colour scale minimum. Default: display 99 % data. cmax : float, optional colour scale maximum. Default: display 99.9 % data. cscale : str, optional override colour scale (linear/ log). Default: None. unoccupied : str, optional if the colour variable is occuption, values below 1 are coloured in this colour. Id set to None, or cmin is set, this feature is turned off. Default: grey. workers : int, optional number of workers for paralellised section. Default: 32. xmarkkwargs : dict, optional keyword arguments for x markers passed to matplotlib.pyplot.axvline. Set color to None to turn off. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: color: black linewidth: axis line width rasterized: False kwargs keyword arguments passed to matplotlib.pyplot.scatter. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: marker: . rasterized: True Returns ------- colorbar colour bar for projected data. """ from functools import partial from multiprocessing import Pool from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer from pymatgen.io.vasp.inputs import Poscar import pymatgen.symmetry.analyzer as pmg from copy import copy from scipy.interpolate import interp1d # defaults defkwargs = {'marker': '.', 'rasterized': True} if conf is None or 'alt_projected_dispersion_kwargs' not in conf or \ conf['alt_projected_dispersion_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = { **defkwargs, **conf['alt_projected_dispersion_kwargs'], **kwargs } # check inputs for name, value in zip(['main', 'log'], [main, log]): assert isinstance(value, bool), '{} must be True or False'.format(name) # Phono3py data formatting tnames = tp.settings.to_tp() if quantity in tnames: quantity = tnames[quantity] if projected in tnames: projected = tnames[projected] if quantity == 'kappa': quantity = 'mode_kappa' if projected == 'kappa': projected = 'mode_kappa' qs = quantity if quantity == projected else [quantity, projected] data = tp.data.resolve.resolve(data, qs, temperature, direction) y = data[quantity] c = data[projected] if bandmin is None: bandmin = 0 else: bandmin = np.amax([0, bandmin]) if bandmax is None: bandmax = len(y[0]) else: bandmax = np.amin([len(y[0]), bandmax]) y = np.array(y)[:, bandmin:bandmax] c = np.array(c)[:, bandmin:bandmax] qk = data['qpoint'] # Phonopy data formatting qp = pdata['qpoint'] x = pdata['x'] # map Phono3py to Phonopy struct = Poscar.from_file(poscar).structure sg = SpacegroupAnalyzer(struct) symops = sg.get_point_group_operations(cartesian=False) geq = partial(get_equivalent_qpoint, np.array(qk), symops) with Pool(processes=workers) as pool: min_id = pool.map(geq, qp) y2 = y[min_id, :] c2 = c[min_id, :] x, indices = np.unique(x, return_index=True) y2 = np.array(y2)[indices] c2 = np.array(c2)[indices] if len(x) > 100: xi = [x[i] for i in range(len(x)) if i % smoothing == 0] y2 = [y2[i] for i in range(len(y2)) if i % smoothing == 0] else: xi = x y2 = y2 if xi[-1] != x[-1]: y2.append(y2[-1]) xi.append(x[-1]) # interpolate x2 = np.linspace(min(x), max(x), interpolate) yinterp = interp1d(xi, y2, kind='cubic', axis=0) y2 = np.abs(yinterp(x2)) ysort = np.ravel(y2) ysort = ysort[ysort.argsort()] ymin = ysort[int(round(len(ysort) / 100 - 1, 0))] ymax = ysort[int(round(len(ysort) * 99.9 / 100 - 1, 0))] cinterp = interp1d(x, c2, kind='cubic', axis=0) c2 = np.abs(cinterp(x2)) if isinstance(colour, str): cmap = copy(plt.cm.get_cmap(colour)) else: cmap = copy(colour) cnorm, extend = tp.plot.utilities.colour_scale(c2, projected, cmap, cmin, cmax, cscale, unoccupied) # plotting for n in range(len(y2[0])): line = ax.scatter(x2, y2[:, n], c=c2[:, n], cmap=cmap, norm=cnorm, **kwargs) # axes formatting axlabels = tp.settings.labels() cbar = plt.colorbar(line, extend=extend) cbar.set_alpha(1) cbar.set_label(axlabels[projected]) tp.plot.utilities.set_locators(cbar.ax, y=cbar.ax.yaxis.get_scale()) cbar.draw_all() if main: ax.set_ylim(ymin, ymax) formatting(ax, pdata, quantity, log=log, **xmarkkwargs) return cbar
def add_alt_dispersion( ax, data, pdata, quantity, bandmin=None, bandmax=None, temperature=300, direction='avg', label=['Longitudinal', 'Transverse_1', 'Transverse_2', 'Optic'], poscar='POSCAR', main=True, log=False, interpolate=10000, smoothing=5, colour=['#44ffff', '#ff8044', '#ff4444', '#00000010'], linestyle='-', workers=32, xmarkkwargs={}, **kwargs): """Plots a phono3py quantity on a high-symmetry path. Labels, colours and linestyles can be given one for the whole dispersion, or one for each band, with the last entry filling all remaining bands. Requires a POSCAR. Arguments --------- ax : axes axes to plot on. data : dict Phono3py-like data containing: qpoint : array-like q-point locations. (quantity) : array-like plotted quantity. temperature : array-like, optional temperature, if necessary for quantity. pdata : dict phonon dispersion data containing: q-point : array-like qpoint locations. x : array-like high-symmetry path. tick_position : array-like x-tick positions. tick_label : array-like x-tick labels. quantity : str quantity to plot. bandmin : int, optional Zero-indexed minimum band index to plot. Default: 0. bandmax : int, optional Zero-indexed maximum band index to plot. Default: max index. temperature : float, optional approximate temperature in K (finds closest). Default: 300. direction : str, optional direction from anisotropic data, accepts x-z/ a-c, average/ avg or normal/ norm. Default: average. label : array-like, optional labels per line. A single dataset could have a single label, or the default labels the lines by type. You'll want to change this if a minimum band index is set. Default: ['Longitudinal', 'Transverse_1', 'Transverse_2', 'Optic']. poscar : str, optional VASP POSCAR filepath. Default: POSCAR. main : bool, optional set axis ticks, label, limits. Default: True. log : bool, optional log the y scale. Default: False. interpolate : int, optional number of points per line. Default: 10,000. smoothing : int, optional every n points to sample. Default: 5. colour : str or array-like, optional line colour(s). Note if retrieved from a colourmap or in [r,g,b] notation, the colour should be enclosed in [], e.g. colour = plt.get_cmap('winter_r')(linspace(0, 1, len(files))) tp.plot.phonons.add_dispersion(..., colour=[colour[0]], ...) Default: ['#44ffff', '#ff8044', '#ff4444', '#00000010']. linestyle : str or array-like, optional linestyle(s) ('-', '--', '.-', ':'). Default: solid. workers : int, optional number of workers for paralellised section. Default: 32. xmarkkwargs : dict, optional keyword arguments for x markers passed to matplotlib.pyplot.axvline. Set color to None to turn off. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: color: black linewidth: axis line width rasterized: False kwargs keyword arguments passed to matplotlib.pyplot.plot. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: False Returns ------- None adds plot directly to ax. """ from functools import partial from multiprocessing import Pool from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer from pymatgen.io.vasp.inputs import Poscar import pymatgen.symmetry.analyzer as pmg from scipy.interpolate import interp1d # defaults defkwargs = {'rasterized': False} if conf is None or 'alt_dispersion_kwargs' not in conf or \ conf['alt_dispersion_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['alt_dispersion_kwargs'], **kwargs} # check inputs for name, value in zip(['main', 'log'], [main, log]): assert isinstance(value, bool), '{} must be True or False'.format(name) # Phono3py data formatting tnames = tp.settings.to_tp() if quantity in tnames: quantity = tnames[quantity] if quantity == 'kappa': quantity = 'mode_kappa' data = tp.data.resolve.resolve(data, quantity, temperature, direction) y = data[quantity] if bandmin is None: bandmin = 0 else: bandmin = np.amax([0, bandmin]) if bandmax is None: bandmax = len(y[0]) else: bandmax = np.amin([len(y[0]), bandmax]) y = np.array(y)[:, bandmin:bandmax] qk = data['qpoint'] # Phonopy data formatting qp = pdata['qpoint'] x = pdata['x'] if len(x) > 100: xi = [x[i] for i in range(len(x)) if i % smoothing == 0] qpi = [qp[i] for i in range(len(qp)) if i % smoothing == 0] else: xi = x qpi = qp if xi[-1] != x[-1]: qpi.append(qp[-1]) xi.append(x[-1]) # map Phono3py to Phonopy struct = Poscar.from_file(poscar).structure sg = SpacegroupAnalyzer(struct) symops = sg.get_point_group_operations(cartesian=False) geq = partial(get_equivalent_qpoint, np.array(qk), symops) with Pool(processes=workers) as pool: min_id = pool.map(geq, qpi) y2 = y[min_id, :] x, indices = np.unique(xi, return_index=True) y2 = np.array(y2)[indices] # interpolate x2 = np.linspace(min(x), max(x), interpolate) yinterp = interp1d(x, y2, kind='cubic', axis=0) y2 = np.abs(yinterp(x2)) ysort = np.ravel(y2) ysort = ysort[ysort.argsort()] ymin = ysort[int(round(len(ysort) / 100, 0))] ymax = ysort[-1] # line appearance colour = tile_properties(colour, bandmin, bandmax) linestyle = tile_properties(linestyle, bandmin, bandmax) # prevents unintentionally repeated legend entries label2 = [] if isinstance(label, str): label2.extend(['$\mathregular{{{}}}$'.format(label)]) else: try: label = ['$\mathregular{{{}}}$'.format(l) for l in label] label2.extend(label) except Exception: label2.extend([label]) label2.append(None) label2 = tile_properties(label2, bandmin, bandmax) # plotting for n in range(len(y2[0])): ax.plot(x2, y2[:, n], color=colour[n], linestyle=linestyle[n], label=label2[n], **kwargs) # axes formatting if main: ax.set_ylim(ymin, ymax) formatting(ax, pdata, quantity, log=log, **xmarkkwargs) return
def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) self.structure = p.structure self.sg1 = SpacegroupAnalyzer(self.structure, 0.001).get_space_group_operations()
def test_from_file(self): filepath = self.TEST_FILES_DIR / "POSCAR.symbols_natoms_multilines" poscar = Poscar.from_file( filepath, check_for_POTCAR=False, read_velocities=False ) ordered_expected_elements = [ "Fe", "Cr", "Fe", "Fe", "Cr", "Cr", "Cr", "Cr", "Fe", "Fe", "Cr", "Fe", "Cr", "Fe", "Fe", "Cr", "Fe", "Cr", "Fe", "Fe", "Fe", "Fe", "Cr", "Fe", "Ni", "Fe", "Fe", "Fe", "Fe", "Fe", "Cr", "Cr", "Cr", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Cr", "Fe", "Fe", "Ni", "Fe", "Fe", "Fe", "Cr", "Cr", "Fe", "Fe", "Fe", "Fe", "Fe", ] self.assertEqual( [site.specie.symbol for site in poscar.structure], ordered_expected_elements )
def test_Auto_kpoints(): poscar = Poscar.from_file(pos) kp = list(Auto_Kpoints(mat=poscar, length=20).kpts[0]) assert kp == [6, 6, 6]
def sample_structure(): poscar = Poscar.from_file(pos) return poscar
def setUp(self): filepath = os.path.join(test_dir, 'POSCAR') p = Poscar.from_file(filepath) structure = BVAnalyzer().get_oxi_state_decorated_structure(p.structure) self.zeocssr = ZeoCssr(structure)
def setUp(self): filepath = os.path.join(test_dir, 'POSCAR') p = Poscar.from_file(filepath) self.zeocssr = ZeoCssr(p.structure)
def phonon_bandplot(filename, poscar=None, prefix=None, directory=None, dim=None, born=None, qmesh=None, spg=None, primitive_axis=None, line_density=60, symprec=0.01, mode='bradcrack', kpt_list=None, eigenvectors=False, labels=None, height=6., width=6., style=None, no_base_style=False, ymin=None, ymax=None, image_format='pdf', dpi=400, plt=None, fonts=None, dos=None): """A script to plot phonon band structure diagrams. Args: filename (str): Path to phonopy output. Can be a band structure yaml file, ``FORCE_SETS``, ``FORCE_CONSTANTS``, or ``force_constants.hdf5``. poscar (:obj:`str`, optional): Path to POSCAR file of unitcell. Not required if plotting the phonon band structure from a yaml file. If not specified, the script will search for a POSCAR file in the current directory. prefIx (:obj:`str`, optional): Prefix for file names. directory (:obj:`str`, optional): The directory in which to save files. born (:obj:`str`, optional): Path to file containing Born effective charges. Should be in the same format as the file produced by the ``phonopy-vasp-born`` script provided by phonopy. qmesh (:obj:`list` of :obj:`int`, optional): Q-point mesh to use for calculating the density of state. Formatted as a 3x1 :obj:`list` of :obj:`int`. spg (:obj:`str` or :obj:`int`, optional): The space group international number or symbol to override the symmetry determined by spglib. This is not recommended and only provided for testing purposes. This option will only take effect when ``mode = 'bradcrack'``. primitive_matrix (:obj:`list`, optional): The transformation matrix from the conventional to primitive cell. Only required when the conventional cell was used as the starting structure. Should be provided as a 3x3 :obj:`list` of :obj:`float`. line_density (:obj:`int`, optional): Density of k-points along the path. mode (:obj:`str`, optional): Method used for calculating the high-symmetry path. The options are: bradcrack Use the paths from Bradley and Cracknell. See [brad]_. pymatgen Use the paths from pymatgen. See [curt]_. seekpath Use the paths from SeeK-path. See [seek]_. kpt_list (:obj:`list`, optional): List of k-points to use, formatted as a list of subpaths, each containing a list of fractional k-points. For example:: [ [[0., 0., 0.], [0., 0., 0.5]], [[0.5, 0., 0.], [0.5, 0.5, 0.]] ] Will return points along ``0 0 0 -> 0 0 1/2 | 1/2 0 0 -> 1/2 1/2 0`` path_labels (:obj:`list`, optional): The k-point labels. These should be provided as a :obj:`list` of :obj:`str` for each subpath of the overall path. For example:: [ ['Gamma', 'Z'], ['X', 'M'] ] combined with the above example for ``kpt_list`` would indicate the path: Gamma -> Z | X -> M. If no labels are provided, letters from A -> Z will be used instead. eigenvectors (:obj:`bool`, optional): Write the eigenvectors to the yaml file. dos (str): Path to Phonopy total dos .dat file height (:obj:`float`, optional): The height of the plot. width (:obj:`float`, optional): The width of the plot. ymin (:obj:`float`, optional): The minimum energy on the y-axis. ymax (:obj:`float`, optional): The maximum energy on the y-axis. style (:obj:`list` or :obj:`str`, optional): (List of) matplotlib style specifications, to be composed on top of Sumo base style. no_base_style (:obj:`bool`, optional): Prevent use of sumo base style. This can make alternative styles behave more predictably. image_format (:obj:`str`, optional): The image file format. Can be any format supported by matplotlib, including: png, jpg, pdf, and svg. Defaults to pdf. dpi (:obj:`int`, optional): The dots-per-inch (pixel density) for the image. plt (:obj:`matplotlib.pyplot`, optional): A :obj:`matplotlib.pyplot` object to use for plotting. fonts (:obj:`list`, optional): Fonts to use in the plot. Can be a a single font, specified as a :obj:`str`, or several fonts, specified as a :obj:`list` of :obj:`str`. Returns: A matplotlib pyplot object. """ if '.yaml' in filename: yaml_file = filename elif ('FORCE_SETS' == filename or 'FORCE_CONSTANTS' == filename or '.hdf5' in filename): try: poscar = poscar if poscar else 'POSCAR' poscar = Poscar.from_file(poscar) except IOError: msg = "Cannot find POSCAR file, cannot generate symmetry path." logging.error("\n {}".format(msg)) sys.exit() if not dim: logging.info("Supercell size (--dim option) not provided.\n" "Attempting to guess supercell dimensions.\n") try: sposcar = Poscar.from_file("SPOSCAR") except IOError: msg = "Could not determine supercell size (use --dim flag)." logging.error("\n {}".format(msg)) sys.exit() dim = (sposcar.structure.lattice.matrix * poscar.structure.lattice.inv_matrix) # round due to numerical noise error dim = np.around(dim, 5) elif np.array(dim).shape != (3, 3): dim = np.diagflat(dim) logging.info("Using supercell with dimensions:") logging.info('\t' + str(dim).replace('\n', '\n\t') + '\n') phonon = load_phonopy(filename, poscar.structure, dim, symprec=symprec, primitive_matrix=primitive_axis, factor=VaspToTHz, symmetrise=True, born=born, write_fc=False) # calculate band structure kpath, kpoints, labels = get_path_data(poscar.structure, mode=mode, symprec=symprec, spg=spg, kpt_list=kpt_list, labels=labels, phonopy=True) # todo: calculate dos and plot also # phonon.set_mesh(mesh, is_gamma_center=False, is_eigenvectors=True, # is_mesh_symmetry=False) # phonon.set_partial_DOS() phonon.set_band_structure(kpoints, is_eigenvectors=eigenvectors) yaml_file = 'sumo_band.yaml' phonon._band_structure.write_yaml(labels=labels, filename=yaml_file) else: msg = "Do not recognise file type of {}".format(filename) logging.error("\n {}".format(msg)) sys.exit() save_files = False if plt else True # don't save if pyplot object provided bs = get_ph_bs_symm_line(yaml_file, has_nac=False, labels_dict=kpath.kpoints) # Replace dos filename with data array if dos is not None: if isfile(dos): dos = np.genfromtxt(dos, comments='#') elif dos: phonon.set_mesh(qmesh, is_gamma_center=False, is_eigenvectors=True, is_mesh_symmetry=False) phonon.set_total_DOS() dos_freq, dos_val = phonon.get_total_DOS() dos = np.zeros((len(dos_freq), 2)) dos[:, 0], dos[:, 1] = dos_freq, dos_val plotter = SPhononBSPlotter(bs) plt = plotter.get_plot(ymin=ymin, ymax=ymax, height=height, width=width, plt=plt, fonts=fonts, dos=dos) if save_files: basename = 'phonon_band.{}'.format(image_format) filename = '{}_{}'.format(prefix, basename) if prefix else basename if directory: filename = os.path.join(directory, filename) if dpi is None: dpi = rcParams['figure.dpi'] plt.savefig(filename, format=image_format, dpi=dpi, bbox_inches='tight') filename = save_data_files(bs, prefix=prefix, directory=directory) else: return plt
""" lattice = struc.lattice.matrix vector_a = lattice[0] + lattice[1] vector_b = lattice[1] + lattice[2] vector_c = lattice[0] + lattice[2] new_lattice = Lattice([vector_a, vector_b, vector_c]) #the atoms new_sites = [] for site in struc.sites: new_sites.append(PeriodicSite(site.species_and_occu, site.coords, new_lattice, coords_are_cartesian=True)) new_sites.append(PeriodicSite(site.species_and_occu, site.coords+lattice[0], new_lattice, coords_are_cartesian=True)) species = [] coords = [] for site in new_sites: species.append(site.specie) coords.append(site.coords) new_struc = Structure(new_lattice, species, coords, to_unit_cell=True, coords_are_cartesian=True) return new_struc if __name__=='__main__': folder = '/Users/yao/Google Drive/data/2116/InTl/tetragonal_exp/' struc = Poscar.from_file(folder+'POSCAR.vasp').structure new_struc = double_unit_cell(struc) Poscar(new_struc).write_file(folder+'POSCAR_dp.vasp')
def test_from_md_run(self): # Parsing from an MD type run with velocities and predictor corrector data p = Poscar.from_file(self.TEST_FILES_DIR / "CONTCAR.MD", check_for_POTCAR=False) self.assertAlmostEqual(np.sum(np.array(p.velocities)), 0.0065417961324) self.assertEqual(p.predictor_corrector[0][0][0], 0.33387820e00) self.assertEqual(p.predictor_corrector[0][1][1], -0.10583589e-02)
def _bs_from_filename( filename, poscar, dim, symprec, spg, kpt_list, labels, primitive_axis, units, born, mode, eigenvectors, line_density, ): """Analyse input files to create band structure""" if ".yaml" in filename: logging.warning( f"Reading pre-computed band structure from {filename}. " "Be aware that many phonon-bandplot options will not " "be relevant.") yaml_file = filename phonon = None try: poscar = poscar if poscar else "POSCAR" poscar = Poscar.from_file(poscar) except OSError: msg = "Cannot find POSCAR file, cannot generate symmetry path." logging.error(f"\n {msg}") sys.exit() elif ("FORCE_SETS" in filename or "FORCE_CONSTANTS" in filename or ".hdf5" in filename): try: poscar = poscar if poscar else "POSCAR" poscar = Poscar.from_file(poscar) except OSError: msg = "Cannot find POSCAR file, cannot generate symmetry path." logging.error(f"\n {msg}") sys.exit() if not dim: logging.info("Supercell size (--dim option) not provided.\n" "Attempting to guess supercell dimensions.\n") try: sposcar = Poscar.from_file("SPOSCAR") except OSError: msg = "Could not determine supercell size (use --dim flag)." logging.error(f"\n {msg}") sys.exit() dim = sposcar.structure.lattice.matrix @ poscar.structure.lattice.inv_matrix # round due to numerical noise error dim = np.around(dim, 5) elif len(dim) == 9: dim = np.array(dim).reshape(3, 3) elif np.array(dim).shape != (3, 3): dim = np.diagflat(dim) logging.info("Using supercell with dimensions:") logging.info("\t" + str(dim).replace("\n", "\n\t") + "\n") factors = { "ev": VaspToEv, "thz": VaspToTHz, "mev": VaspToEv * 1000, "cm-1": VaspToCm, } phonon = load_phonopy( filename, poscar.structure, dim, primitive_matrix=primitive_axis, factor=factors[units.lower()], symmetrise=True, born=born, write_fc=False, ) elif ".phonon" in filename: logging.warning("Reading pre-computed band structure from CASTEP. " "Be aware that many phonon-bandplot options will not " "be relevant.") castep_phonon = CastepPhonon.from_file(filename) cell_file = ".".join(filename.split(".")[:-1] + ["cell"]) if isfile(cell_file): logging.info( f"Found .cell file, reading x-axis labels from {cell_file}") castep_phonon.set_labels_from_file(cell_file) else: logging.warning("No .cell file found, cannot read x-axis labels.") factors = { "cm-1": 1.0, "thz": 1 / THzToCm, "ev": CmToEv, "mev": 1000 * CmToEv } castep_phonon.frequencies *= factors[units.lower()] bs = castep_phonon.get_band_structure() return bs, None else: msg = f"Do not recognise file type of {filename}" logging.error(f"\n {msg}") sys.exit() # calculate band structure kpath, kpoints, labels = get_path_data( poscar.structure, mode=mode, symprec=symprec, spg=spg, kpt_list=kpt_list, labels=labels, phonopy=True, line_density=line_density, ) # todo: calculate dos and plot also # phonon.set_mesh(mesh, is_gamma_center=False, is_eigenvectors=True, # is_mesh_symmetry=False) # phonon.set_partial_DOS() if ".yaml" not in filename: phonon.run_band_structure(kpoints, with_eigenvectors=eigenvectors, labels=labels) yaml_file = "sumo_band.yaml" phonon.band_structure.write_yaml(filename=yaml_file) bs = get_ph_bs_symm_line(yaml_file, has_nac=False, labels_dict=kpath.kpoints) return bs, phonon
def setUp(self): p = Poscar.from_file( os.path.join(PymatgenTest.TEST_FILES_DIR, "POSCAR")) self.structure = p.structure self.sg1 = SpacegroupAnalyzer(self.structure, 0.001).get_space_group_operations()
def post_process(self, dir_name, d): """ Post-processing for various files other than the vasprun.xml and OUTCAR. Looks for files: transformations.json and custodian.json. Modify this if other output files need to be processed. Args: dir_name: The dir_name. d: Current doc generated. """ logger.info("Post-processing dir:{}".format(dir_name)) fullpath = os.path.abspath(dir_name) # VASP input generated by pymatgen's alchemy has a transformations.json file that tracks # the origin of a particular structure. If such a file is found, it is inserted into the # task doc as d["transformations"] transformations = {} filenames = glob.glob(os.path.join(fullpath, "transformations.json*")) if len(filenames) >= 1: with zopen(filenames[0], "rt") as f: transformations = json.load(f) try: m = re.match("(\d+)-ICSD", transformations["history"][0]["source"]) if m: d["icsd_id"] = int(m.group(1)) except Exception as ex: logger.warning("Cannot parse ICSD from transformations file.") pass else: logger.warning("Transformations file does not exist.") other_parameters = transformations.get("other_parameters") new_tags = None if other_parameters: # We don't want to leave tags or authors in the # transformations file because they'd be copied into # every structure generated after this one. new_tags = other_parameters.pop("tags", None) new_author = other_parameters.pop("author", None) if new_author: d["author"] = new_author if not other_parameters: # if dict is now empty remove it transformations.pop("other_parameters") d["transformations"] = transformations # Calculations done using custodian has a custodian.json, # which tracks the jobs performed and any errors detected and fixed. # This is useful for tracking what has actually be done to get a # result. If such a file is found, it is inserted into the task doc # as d["custodian"] filenames = glob.glob(os.path.join(fullpath, "custodian.json*")) if len(filenames) >= 1: with zopen(filenames[0], "rt") as f: d["custodian"] = json.load(f) # Convert to full uri path. if self.use_full_uri: d["dir_name"] = get_uri(dir_name) if new_tags: d["tags"] = new_tags # Calculations using custodian generate a *.orig file for the inputs # This is useful to know how the calculation originally started # if such files are found they are inserted into orig_inputs filenames = glob.glob(os.path.join(fullpath, "*.orig*")) if len(filenames) >= 1: d["orig_inputs"] = {} for f in filenames: if "INCAR.orig" in f: d["orig_inputs"]["incar"] = Incar.from_file(f).as_dict() if "POTCAR.orig" in f: d["orig_inputs"]["potcar"] = Potcar.from_file(f).as_dict() if "KPOINTS.orig" in f: d["orig_inputs"]["kpoints"] = Kpoints.from_file(f).as_dict() if "POSCAR.orig" in f: d["orig_inputs"]["poscar"] = Poscar.from_file(f).as_dict() logger.info("Post-processed " + fullpath)
def add_wideband(ax, kdata, pdata, temperature=300, poscar='POSCAR', main=True, smoothing=5, colour='viridis', workers=32, xmarkkwargs={}, **kwargs): """Plots a phonon dispersion with broadened bands. Requires a POSCAR. Arguments --------- ax : axes axes to plot on. kdata : dict Phono3py-like data containing: qpoint : array-like q-point locations. gamma : array-like imaginary component of the self-energy. temperature : array-like temperature. pdata : dict phonon dispersion data containing: q-point : array-like qpoint locations. x : array-like high-symmetry path. frequency : array-like phonon frequencies. tick_position : array-like x-tick positions. tick_label : array-like x-tick labels. temperature : float, optional approximate temperature in K (finds closest). Default: 300. poscar : str, optional VASP POSCAR filepath. Default: POSCAR. main : bool, optional set axis ticks, label, limits. Default: True. smoothing : int, optional every n points to sample. Default: 5. colour : colormap or str or list, optional colourmap or colourmap name or max #RRGGBB colour (fades to white) or min and max #RRGGBB colours. Default: viridis. workers : int, optional number of workers for paralellised section. Default: 32. xmarkkwargs : dict, optional keyword arguments for x markers passed to matplotlib.pyplot.axvline. Set color to None to turn off. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: color: None linewidth: axis line width rasterized: False kwargs keyword arguments passed to matplotlib.pyplot.pcolormesh. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: True shading: auto Returns ------- None adds plot directly to ax. """ from functools import partial from multiprocessing import Pool from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer from pymatgen.io.vasp.inputs import Poscar import pymatgen.symmetry.analyzer as pmg from scipy.interpolate import interp1d from tp.calculate import lorentzian # defaults defkwargs = {'rasterized': True, 'shading': 'auto'} if conf is None or 'wideband_kwargs' not in conf or \ conf['wideband_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['wideband_kwargs'], **kwargs} defxmarkkwargs = {'color': None} xmarkkwargs = {**defxmarkkwargs, **xmarkkwargs} # check inputs assert isinstance(main, bool), 'main must be True or False' # Phono3py data formatting kdata = tp.data.resolve.resolve(kdata, 'gamma', temperature) c = np.array(kdata['gamma']) qk = kdata['qpoint'] # Phonopy data formatting qp = pdata['qpoint'] x = pdata['x'] qpi = [qp[i] for i in range(len(qp)) if i % smoothing == 0] xi = [x[i] for i in range(len(x)) if i % smoothing == 0] if xi[-1] != x[-1]: qpi.append(qp[-1]) xi.append(x[-1]) # map Phono3py to Phonopy struct = Poscar.from_file(poscar).structure sg = SpacegroupAnalyzer(struct) symops = sg.get_point_group_operations(cartesian=False) geq = partial(get_equivalent_qpoint, np.array(qk), symops) with Pool(processes=workers) as pool: min_id = pool.map(geq, qpi) c2 = c[min_id, :] x, indices = np.unique(x, return_index=True) f = np.array(pdata['frequency'])[indices] where = np.where(c2 == np.amax(c2)) # interpolate x2 = np.linspace(min(x), max(x), 2500) finterp = interp1d(x, f, kind='cubic', axis=0) f = finterp(x2) cinterp = interp1d(xi, c2, kind='cubic', axis=0) c2 = np.abs(cinterp(x2)) fmax = np.amax(np.add(f, c2)) fmin = np.amin(np.subtract(f, c2)) f2 = np.linspace(fmin, fmax, 2500) # broadening area = np.zeros((len(x2), len(f2))) for q in range(len(area)): for b in range(len(c2[q])): area[q] = np.add(area[q], lorentzian(f2, f[q][b], c2[q][b])) cnorm = mpl.colors.LogNorm(vmin=np.nanmin(area), vmax=np.nanmax(area)) # colours # Tries colourmap name or colourmap object, then tries a single # colour as the max of a linear colourmap, then tries two colours as # the min and max values. try: colours = mpl.cm.get_cmap(colour) except Exception: if isinstance(colour, mpl.colors.ListedColormap): colours = colour else: try: colours = tp.plot.colour.linear(colour) except Exception: colours = tp.plot.colour.linear(colour[1], colour[0]) # plotting ax.pcolormesh(x2, f2, np.transpose(area), cmap=colours, norm=cnorm, **kwargs) # axes formatting if main: if round(np.amin(f), 1) == 0: ax.set_ylim(bottom=0) formatting(ax, pdata, 'frequency', **xmarkkwargs) return
def kgen( filename="POSCAR", code="vasp", directory=None, make_folders=False, symprec=0.01, kpts_per_split=None, ibzkpt=None, spg=None, density=60, phonon=False, mode="bradcrack", cart_coords=False, kpt_list=None, labels=None, ): """Generate KPOINTS files for VASP band structure calculations. This script provides a wrapper around several frameworks used to generate k-points along a high-symmetry path. The paths found in Bradley and Cracknell, SeeK-path, and pymatgen are all supported. It is important to note that the standard primitive cell symmetry is different between SeeK-path and pymatgen. If the correct the structure is not used, the high-symmetry points (and band path) may be invalid. Args: filename (:obj:`str`, optional): Path to VASP structure file. Default is ``POSCAR``. code (:obj:`str`, optional): Calculation type. Default is 'vasp'; 'questaal' also supported. directory (:obj:`str`, optional): The output file directory. make_folders (:obj:`bool`, optional): Generate folders and copy in required files (INCAR, POTCAR, POSCAR, and possibly CHGCAR) from the current directory. symprec (:obj:`float`, optional): The precision used for determining the cell symmetry. kpts_per_split (:obj:`int`, optional): If set, the k-points are split into separate k-point files (or folders) each containing the number of k-points specified. This is useful for hybrid band structure calculations where it is often intractable to calculate all k-points in the same calculation. ibzkpt (:obj:`str`, optional): Path to IBZKPT file. If set, the generated k-points will be appended to the k-points in this file and given a weight of 0. This is necessary for hybrid band structure calculations. spg (:obj:`str` or :obj:`int`, optional): The space group international number or symbol to override the symmetry determined by spglib. This is not recommended and only provided for testing purposes. This option will only take effect when ``mode = 'bradcrack'``. line_density (:obj:`int`, optional): Density of k-points along the path. phonon (:obj:`bool`, optional): Write phonon q-point path instead of k-points. (Not appropriate for most codes.) mode (:obj:`str`, optional): Method used for calculating the high-symmetry path. The options are: bradcrack Use the paths from Bradley and Cracknell. See [brad]_. pymatgen Use the paths from pymatgen. See [curt]_. latimer-munro Use the paths from Latimer & Munro. See [lm]_. seekpath Use the paths from SeeK-path. See [seek]_. cart_coords (:obj:`bool`, optional): Whether the k-points are returned in cartesian or reciprocal coordinates. Defaults to ``False`` (fractional coordinates). kpt_list (:obj:`list`, optional): List of k-points to use, formatted as a list of subpaths, each containing a list of fractional k-points. For example:: [ [[0., 0., 0.], [0., 0., 0.5]], [[0.5, 0., 0.], [0.5, 0.5, 0.]] ] Will return points along ``0 0 0 -> 0 0 1/2 | 1/2 0 0 -> 1/2 1/2 0`` path_labels (:obj:`list`, optional): The k-point labels. These should be provided as a :obj:`list` of :obj:`str` for each subpath of the overall path. For example:: [ ['Gamma', 'Z'], ['X', 'M'] ] combined with the above example for ``kpt_list`` would indicate the path: Gamma -> Z | X -> M. If no labels are provided, letters from A -> Z will be used instead. If a label begins with '@' it will be concealed when plotting with sumo-bandplot. """ if code.lower() == "vasp": structure = Poscar.from_file(filename).structure elif code.lower() == "questaal": if filename.split(".")[0] == "site": site = QuestaalSite.from_file(filename) structure = site.structure alat = site.alat else: structure = QuestaalInit.from_file(filename).structure alat = None elif code.lower() == "castep": if cart_coords: logging.warning("Ignoring request for Cartesian coordinates: " "not applicable to CASTEP band structure format.") cart_coords = False if ibzkpt: logging.warning('Ignoring request to use IBZKPT ("hybrid mode"), ' "for CASTEP workflow the SCF mesh should already " "be set in input .cell file.") structure = CastepCell.from_file(filename).structure else: raise ValueError(f'Code "{code}" not recognized.') if phonon and (code.lower() not in phonon_supported_codes): logging.error("Cannot write phonon path for {code}. " "Supported codes: {supported}".format( code=code, supported=", ".join(phonon_supported_codes))) sys.exit() kpath, kpoints, labels = get_path_data( structure, mode=mode, symprec=symprec, kpt_list=kpt_list, labels=labels, spg=spg, line_density=density, cart_coords=cart_coords, ) logging.info("\nk-point label indices:") for i, label in enumerate(labels): if label: logging.info(f"\t{label}: {i + 1}") if not kpt_list and not np.allclose(structure.lattice.matrix, kpath.prim.lattice.matrix): prim_filename = f"{os.path.basename(filename)}_prim" if code.lower() == "questaal": QuestaalInit.from_structure(kpath.prim).to_file(prim_filename) elif code.lower() == "castep": CastepCell.from_structure(kpath.prim).to_file(prim_filename) else: kpath.prim.to(filename=prim_filename) logging.error( "\nWARNING: The input structure does not match the " "expected standard\nprimitive symmetry, the path may be " "incorrect! Use at your own risk.\n\nThe correct " "symmetry primitive structure has been saved as {}.".format( prim_filename)) ibz = _parse_ibzkpt(ibzkpt) if ibz and kpts_per_split is None: logging.info("\nFound {} total kpoints in path, do you want to " "split them up? (y/n)".format(len(kpoints))) if input()[0].lower() == "y": logging.info("How many kpoints per file?") kpts_per_split = int(input()) if code.lower() == "vasp": sumo.io.vasp.write_kpoint_files( filename, kpoints, labels, make_folders=make_folders, ibzkpt=ibz, kpts_per_split=kpts_per_split, directory=directory, cart_coords=cart_coords, ) elif code.lower() == "castep": sumo.io.castep.write_kpoint_files( filename, kpoints, labels, make_folders=make_folders, kpts_per_split=kpts_per_split, phonon=phonon, directory=directory, ) elif code.lower() == "questaal": if cart_coords: kpoints = [kpoint / (2 * np.pi) for kpoint in kpoints] if alat is not None: logging.info( f"Multiplying kpoint values by ALAT = {alat} Bohr") _bohr_to_angstrom = 0.5291772 kpoints = [ kpoint * alat * _bohr_to_angstrom for kpoint in kpoints ] sumo.io.questaal.write_kpoint_files( filename, kpoints, labels, make_folders=make_folders, directory=directory, cart_coords=cart_coords, )
def add_projected_dispersion(ax, data, pdata, quantity, bandmin=None, bandmax=None, temperature=300, direction='avg', poscar='POSCAR', main=True, interpolate=500, colour='viridis_r', cmin=None, cmax=None, cscale=None, unoccupied='grey', workers=32, xmarkkwargs={}, **kwargs): """Plots a phonon dispersion with projected colour. Plots a phonon dispersion, and projects a quantity onto the colour axis. Requires a POSCAR. Arguments --------- ax : axes axes to plot on. data : dict Phono3py-like data containing: qpoint : array-like q-point locations. (quantity) : array-like projected quantity. temperature : array-like, optional temperature, if necessary for quantity. pdata : dict phonon dispersion data containing: q-point : array-like qpoint locations. x : array-like high-symmetry path. frequency : array-like phonon frequencies. tick_position : array-like x-tick positions. tick_label : array-like x-tick labels. quantity : str quantity to project. bandmin : int, optional Zero-indexed minimum band index to plot. Default: 0. bandmax : int, optional Zero-indexed maximum band index to plot. Default: max index. temperature : float, optional approximate temperature in K (finds closest). Default: 300. direction : str, optional direction from anisotropic data, accepts x-z/ a-c, average/ avg or normal/ norm. Default: average. poscar : str, optional VASP POSCAR filepath. Default: POSCAR. main : bool, optional set axis ticks, label, limits. Default: True. interpolate : int, optional number of points per path (e.g. gamma -> X) per line. Default: 500. colour : colormap or str, optional colourmap or colourmap name. Default: viridis_r. cmin : float, optional colour scale minimum. Default: display 99 % data. cmax : float, optional colour scale maximum. Default: display 99.9 % data. cscale : str, optional override colour scale (linear/ log). Default: None. unoccupied : str or array-like, optional if the colour variable is occuption, values below 1 are coloured in this colour. If set to None, or cmin is set, this feature is turned off. Default: grey. workers : int, optional number of workers for paralellised section. Default: 32. xmarkkwargs : dict, optional keyword arguments for x markers passed to matplotlib.pyplot.axvline. Set color to None to turn off. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Default color: black linewidth: axis line width rasterized: False kwargs keyword arguments passed to matplotlib.pyplot.scatter. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: marker: . rasterized: True Returns ------- colorbar colour bar for projected data. """ from functools import partial from multiprocessing import Pool from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer from pymatgen.io.vasp.inputs import Poscar import pymatgen.symmetry.analyzer as pmg from copy import copy from scipy.interpolate import interp1d # defaults defkwargs = {'marker': '.', 'rasterized': True} if conf is None or 'projected_dispersion_kwargs' not in conf or \ conf['projected_dispersion_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['projected_dispersion_kwargs'], **kwargs} # check inputs assert isinstance(main, bool), 'main must be True or False' # Phono3py data formatting tnames = tp.settings.to_tp() quantity = tnames[quantity] if quantity in tnames else quantity if quantity == 'kappa': quantity = 'mode_kappa' data = tp.data.resolve.resolve(data, quantity, temperature, direction) c = data[quantity] if bandmin is None: bandmin = 0 else: bandmin = np.amax([0, bandmin]) if bandmax is None: bandmax = len(c[0]) else: bandmax = np.amin([len(c[0]), bandmax]) c = np.array(c)[:, bandmin:bandmax] qk = data['qpoint'] # Phonopy data formatting qp = pdata['qpoint'] x = pdata['x'] f = np.array(pdata['frequency'])[:, bandmin:bandmax] # map Phono3py to Phonopy struct = Poscar.from_file(poscar).structure sg = SpacegroupAnalyzer(struct) symops = sg.get_point_group_operations(cartesian=False) geq = partial(get_equivalent_qpoint, np.array(qk), symops) with Pool(processes=workers) as pool: min_id = pool.map(geq, qp) c = c[min_id, :] x, indices = np.unique(x, return_index=True) f = np.array(f)[indices] c = np.array(c)[indices] # interpolate index = [0, 0] x2, f2, c2 = [], [], [] for d in pdata['tick_position'][1:]: index[0] = index[1] + 1 index[1] = next(i[0] for i in enumerate(x) if i[1] == d) xtemp = np.linspace(x[index[0]], x[index[1]], interpolate) finterp = interp1d(x[index[0]:index[1]], f[index[0]:index[1]], kind='cubic', axis=0, fill_value='extrapolate') x2.append(xtemp) f2.append(finterp(xtemp)) cinterp = interp1d(x[index[0]:index[1]], c[index[0]:index[1]], kind='cubic', axis=0, fill_value='extrapolate') c2.append(np.abs(cinterp(xtemp))) if isinstance(colour, str): cmap = copy(plt.cm.get_cmap(colour)) else: cmap = copy(colour) cnorm, extend = tp.plot.utilities.colour_scale(c2, quantity, cmap, cmin, cmax, cscale, unoccupied) # plotting for n in range(len(f2[0][0])): for i in range(len(x2)): line = ax.scatter(x2[i], np.array(f2[i])[:, n], c=np.array(c2[i])[:, n], cmap=cmap, norm=cnorm, **kwargs) # axes formatting axlabels = tp.settings.labels() cbar = plt.colorbar(line, extend=extend) cbar.set_alpha(1) cbar.set_label(axlabels[quantity]) tp.plot.utilities.set_locators(cbar.ax, y=cbar.ax.yaxis.get_scale()) cbar.draw_all() if main: if round(np.amin(f), 1) == 0: ax.set_ylim(bottom=0) formatting(ax, pdata, 'frequency', **xmarkkwargs) return cbar
logging.info("parsing dos subdirectory") if 'restart' in listdironly(joinpath(args.path,'charge_0',cell,vac,'')): folder = joinpath(args.path,'charge_0',cell,vac,'restart','') logging.info("parsing restart subdirectory") vr_file = joinpath(folder,'vasprun.xml') vr_ref_file = joinpath(folder_ref,'vasprun.xml') if not os.path.exists(vr_file): logging.warning("%s file does not exist"%vr_file) elif not os.path.exists(vr_ref_file): logging.warning("%s file does not exist"%vr_ref_file) else: natoms = np.sum(Poscar.from_file(joinpath(folder_ref,'POSCAR')).natoms) vr = Vasprun(vr_file) vr_ref = Vasprun(vr_ref_file) if not vr.converged: logging.warning("Vasp calculation in %s may not be converged" %folder) if not vr_ref.converged: logging.warning("Vasp calculation in %s may not be converged" %(joinpath(folder,'bulkref',''))) df0.loc[len(df0)] = [vac, cell, natoms, 1/natoms, vr.final_energy,
def test_symmetrized(self): filepath = self.TEST_FILES_DIR / 'POSCAR' poscar = Poscar.from_file(filepath, check_for_POTCAR=False) writer = CifWriter(poscar.structure, symprec=0.1) ans = """# generated using pymatgen data_FePO4 _symmetry_space_group_name_H-M Pnma _cell_length_a 10.41176687 _cell_length_b 6.06717188 _cell_length_c 4.75948954 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 62 _chemical_formula_structural FePO4 _chemical_formula_sum 'Fe4 P4 O16' _cell_volume 300.65685512 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 2 '-x, -y, -z' 3 '-x+1/2, -y, z+1/2' 4 'x+1/2, y, -z+1/2' 5 'x+1/2, -y+1/2, -z+1/2' 6 '-x+1/2, y+1/2, z+1/2' 7 '-x, y+1/2, -z' 8 'x, -y+1/2, z' loop_ _atom_site_type_symbol _atom_site_label _atom_site_symmetry_multiplicity _atom_site_fract_x _atom_site_fract_y _atom_site_fract_z _atom_site_occupancy Fe Fe1 4 0.218728 0.250000 0.525133 1 P P2 4 0.094613 0.750000 0.581757 1 O O3 8 0.165710 0.546072 0.714616 1 O O4 4 0.043372 0.250000 0.292862 1 O O5 4 0.096642 0.750000 0.258680 1""" cif = CifParser.from_string(str(writer)) m = StructureMatcher() self.assertTrue(m.fit(cif.get_structures()[0], poscar.structure)) # for l1, l2 in zip(str(writer).split("\n"), ans.split("\n")): # self.assertEqual(l1.strip(), l2.strip()) ans = """# generated using pymatgen data_LiFePO4 _symmetry_space_group_name_H-M Pnma _cell_length_a 10.41037000 _cell_length_b 6.06577000 _cell_length_c 4.74480000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 62 _chemical_formula_structural LiFePO4 _chemical_formula_sum 'Li4 Fe4 P4 O16' _cell_volume 299.619458734 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 2 '-x, -y, -z' 3 '-x+1/2, -y, z+1/2' 4 'x+1/2, y, -z+1/2' 5 'x+1/2, -y+1/2, -z+1/2' 6 '-x+1/2, y+1/2, z+1/2' 7 '-x, y+1/2, -z' 8 'x, -y+1/2, z' loop_ _atom_site_type_symbol _atom_site_label _atom_site_symmetry_multiplicity _atom_site_fract_x _atom_site_fract_y _atom_site_fract_z _atom_site_occupancy Li Li1 4 0.000000 0.000000 0.000000 1.0 Fe Fe2 4 0.218845 0.750000 0.474910 1.0 P P3 4 0.094445 0.250000 0.417920 1.0 O O4 8 0.165815 0.044060 0.286540 1.0 O O5 4 0.043155 0.750000 0.708460 1.0 O O6 4 0.096215 0.250000 0.741480 1.0 """ s = Structure.from_file(self.TEST_FILES_DIR / 'LiFePO4.cif') writer = CifWriter(s, symprec=0.1) s2 = CifParser.from_string(str(writer)).get_structures()[0] self.assertTrue(m.fit(s, s2)) s = self.get_structure("Li2O") writer = CifWriter(s, symprec=0.1) s2 = CifParser.from_string(str(writer)).get_structures()[0] self.assertTrue(m.fit(s, s2)) # test angle tolerance. s = Structure.from_file(self.TEST_FILES_DIR / 'LiFePO4.cif') writer = CifWriter(s, symprec=0.1, angle_tolerance=0) d = list(writer.ciffile.data.values())[0] self.assertEqual(d["_symmetry_Int_Tables_number"], 14) s = Structure.from_file(self.TEST_FILES_DIR / 'LiFePO4.cif') writer = CifWriter(s, symprec=0.1, angle_tolerance=2) d = list(writer.ciffile.data.values())[0] self.assertEqual(d["_symmetry_Int_Tables_number"], 62)
print('''Script that sets up files for vacancy calculations''') print('''POSCAR file named "POSCAR_unit" must be present in work dir''') print( '''You must set up the desired CHARGE STATES for each vacancy type in the dictionary at the beginning of the script''' ) print('') # system name to be inserted in job_vasp.sh system_name = 'N' # SETTING CHARGE STATE DICTIONARY charge_states_dict = {'Sr': [0, 1, 2], 'Ca': [0, 1, 2]} potcar_symbols = ['Na', 'Nb_pv', 'O'] ########################################################################### structure = Poscar.from_file('POSCAR_unit').structure default_inputs = DefaultInputs(structure) incar_settings = default_inputs.get_incar_default(xc='PBE') incar_settings['LVTOT'] = '.TRUE.' kpoints = Kpoints.gamma_automatic(kpts=(2, 2, 2)) supercell_size = 3 structure.make_supercell(supercell_size) structure_pure = structure.copy() for el in charge_states_dict: structure = structure_pure.copy() for s in structure.sites: if s.species_string == 'Na': defect_site = PeriodicSite(el, s.frac_coords, s.lattice)
from pymatgen.io.vasp.inputs import Poscar from jarvis.vasp.joptb88vdw import smart_converge p = Poscar.from_file('POSCAR') smart_converge(mat=p)
def phonopy_dos(filename, poscar='POSCAR', atoms=None): """Loads phonopy DoS and collates data per atom and as a total. By default reads atom names from a POSCAR, but can be overridden to allow for separation of environments. Arguments --------- filename : str path to phonopy projected_dos.dat or similar. poscar : str, optional path to POSCAR. Ignored if atoms specified. Default: POSCAR. atoms : str or array-like, optional atoms in POSCAR order. Atom names can be repeated, in which case their contributions are summed. Numbers can indicate repetition in the manner of a chemical formula, so the following are all acceptable and equivalent: "Ba 1 Sn 2 O 3", "Ba Sn Sn O O O", "Ba Sn O 3". Different environments can be distinguised with different atom names. Default: read from POSCAR. Returns ------- dict frequency, DoS per atom and total. """ # load data data = np.transpose(np.loadtxt(filename)) units = tp.settings.units() data2 = { 'frequency': data[0], 'meta': { 'phonon_dos_source': 'phonopy', 'units': { 'frequency': units['frequency'] } } } conversions = settings.phonopy_conversions() if 'frequency' in conversions: data2['frequency'] *= conversions['frequency'] if atoms is None: from pymatgen.io.vasp.inputs import Poscar poscar = Poscar.from_file(poscar, check_for_POTCAR=False, read_velocities=False).as_dict() atoms = [p['label'] for p in poscar['structure']['sites']] elif isinstance(atoms, str): atoms = atoms.split() # combine atoms contributions i = 0 n = 1 while i < len(atoms): try: atoms[i + 1] = int(atoms[i + 1]) if atoms[i] in data2: data2[atoms[i]] += np.sum(data[n:n + atoms[i + 1]], axis=0) else: data2[atoms[i]] = np.sum(data[n:n + atoms[i + 1]], axis=0) n += atoms[i + 1] i += 2 except Exception: if atoms[i] in data2: data2[atoms[i]] += data[n] else: data2[atoms[i]] = data[n] n += 1 i += 1 data2['total'] = np.sum(data[1:], axis=0) return data2