def from_files(cls, gsr_paths, phdos_paths): """ Creates an instance of QHA from a list of GSR files and a list of PHDOS.nc files. The list should have the same size and the volumes should match. Args: gsr_paths: list of paths to GSR files. phdos_paths: list of paths to PHDOS.nc files. Returns: A new instance of QHA """ energies = [] structures = [] for gp in gsr_paths: with GsrFile.from_file(gp) as g: energies.append(g.energy) structures.append(g.structure) #doses = [PhononDos.as_phdos(dp) for dp in phdos_paths] doses = [] structures_from_phdos = [] for path in phdos_paths: with PhdosFile(path) as p: doses.append(p.phdos) structures_from_phdos.append(p.structure) cls._check_volumes(structures, structures_from_phdos) return cls(structures, doses, energies)
def from_files(cls, gsr_files_paths, grun_file_path, ind_doses): """ Creates an instance of QHA from a list og GSR files and a list PHDOS.nc files. The list should have the same size and the volumes should match. Args: gsr_files_paths: list of paths to GSR files. phdos_files_paths: list of paths to three PHDOS.nc files. ind_doses: list of three values indicating, for each of the three doses, the index of the corresponding gsr_file in "gsr_files_paths". Returns: A new instance of QHA """ energies = [] structures = [] for gp in gsr_files_paths: with GsrFile.from_file(gp) as g: energies.append(g.energy) structures.append(g.structure) gruns = GrunsNcFile(grun_file_path) return cls(structures, gruns, energies, ind_doses)
def match_results(fw, abitask): fw_gsr_path = Directory(os.path.join(fw.launches[-1].launch_dir, abiflows.fireworks.tasks.abinit_common.OUTDIR_NAME)).has_abiext("GSR") with GsrFile(fw_gsr_path) as gsr1, abitask.open_gsr() as gsr2: if gsr1.energy - gsr2.energy > 0.0001: return False return True
def test_gsr_silicon(self): """spin unpolarized GSR file""" almost_equal = self.assertAlmostEqual with GsrFile(abidata.ref_file("si_scf_GSR.nc")) as gsr: print(repr(gsr)) print(gsr) print(gsr.ebands) assert gsr.filepath == abidata.ref_file("si_scf_GSR.nc") assert gsr.nsppol == 1 assert gsr.mband == 8 and gsr.nband == 8 and gsr.nelect == 8 and len(gsr.kpoints) == 29 almost_equal(gsr.energy.to("Ha"), -8.86527676798556) almost_equal(gsr.energy_per_atom * len(gsr.structure), gsr.energy) # Test energy_terms eterm = gsr.energy_terms print(eterm) almost_equal(eterm.e_xc.to("Ha"), -3.51815936301812) almost_equal(eterm.e_nonlocalpsp.to("Ha"), 1.91660690901782) almost_equal(eterm.e_kinetic.to("Ha"), 2.96421325671218) almost_equal(eterm.e_fermie.to("Ha"), 0.205739364929368) # Forces and stress self.assert_almost_equal(gsr.cart_forces.flat, [-5.98330096024095e-30, -5.64111024387213e-30, 1.49693284867669e-29, 5.98330096024095e-30, 5.64111024387213e-30, -1.49693284867669e-29]) almost_equal(gsr.max_force, 0) print(gsr.force_stats()) #self.assert_almost_equal(gsr.cart_stress_tensor.flat, # Cartesian components of stress tensor (hartree/bohr^3) # sigma(1 1)= 1.77139311E-04 sigma(3 2)= 0.00000000E+00 # sigma(2 2)= 1.77139311E-04 sigma(3 1)= 0.00000000E+00 # sigma(3 3)= 1.77139311E-04 sigma(2 1)= 2.67294316E-15 almost_equal(gsr.pressure, -5.21162150) # Test gsr.density. print(gsr.density) almost_equal(gsr.magnetization, 0) # Test as_dict pprint(gsr.as_dict()) #import json #with open("hello.json", "w") as fp: # json.dump(gsr.as_dict(), fp) #assert 0 # Test pymatgen computed_entries for inc_structure in (True, False): e = gsr.get_computed_entry(inc_structure=inc_structure) print(e) print(e.as_dict()) assert gsr.energy == e.energy
def open_gsr(self): """ Open the GSR file located in the in self.outdir. Returns :class:`GsrFile` object, None if file could not be found or file is not readable. """ gsr_path = self.gsr_path if not gsr_path: if self.status == self.S_OK: logger.critical( "%s reached S_OK but didn't produce a GSR file in %s" % (self, self.outdir)) return None # Open the GSR file. from abipy.electrons.gsr import GsrFile try: return GsrFile(gsr_path) except Exception as exc: logger.critical("Exception while reading GSR file at %s:\n%s" % (gsr_path, str(exc))) return None
def __init__(self, data, silent=False): if silent: block_print() name = 'tmp_GSR.nc' f = open(name, 'w') f.write(data) f.close() with GsrFile(filepath=name) as gsr_file: self.ebands = gsr_file.ebands self.lumo = self.ebands.lumos[0].eig self.lumo_kp = self.ebands.lumos[0].kpoint self.lumo_i = self.ebands.kindex(self.lumo_kp) self.lumo_b = self.ebands.lumos[0].band self.lumo_s = self.ebands.lumos[0].spin self.h**o = self.ebands.homos[0].eig self.homo_kp = self.ebands.homos[0].kpoint self.homo_i = self.ebands.kindex(self.homo_kp) self.homo_b = self.ebands.homos[0].band self.homo_s = self.ebands.homos[0].spin self.en_max_band = self.ebands.enemax() if silent: enable_print()
def from_files(cls, gsr_files_paths, phdos_files_paths): """ Creates an instance of QHA from a list og GSR files and a list PHDOS.nc files. The list should have the same size and the volumes should match. Args: gsr_files_paths: list of paths to GSR files. phdos_files_paths: list of paths to PHDOS.nc files. Returns: A new instance of QHA """ energies = [] structures = [] for gp in gsr_files_paths: with GsrFile.from_file(gp) as g: energies.append(g.energy) structures.append(g.structure) doses = [PhononDos.as_phdos(dp) for dp in phdos_files_paths] return cls(structures, doses, energies)
def phonopy_to_abinit(unit_cell, supercell_matrix, out_ddb_path, ngqpt=None, qpt_list=None, force_constants=None, force_sets=None, born=None, primitive_matrix="auto", symprec=1e-5, tolsym=None, supercell=None, calculator=None, manager=None, workdir=None, pseudos=None, verbose=False): """ Converts the data from phonopy to an abinit DDB file. The data can be provided in form of arrays or paths to the phonopy files that should be parsed. The minimal input should contains the FORCE_CONSTANTS or FORCE_SETS. If BORN is present the Born effective charges (BEC) and dielectric tensor will also be added to the DDB. The best agreement is obtained with supercell_matrix and ngqpt being equivalent (i.e. supercell_matrix a diagonal matrix with ngqpt as diagonal elements). Non diagonal supercell_matrix are allowed as well, but the information encoded in the DDB will be the result of an interpolation done through phonopy. Phonopy is used to convert the IFC to the dynamical matrix. However, in order to determine the list of q-points in the irreducible Brillouin zone and to prepare the base for the final DDB file, abinit will be called for a very short and inexpensive run. Performs a check to verify if the two codes identify the same symmetries and it gives a warning in case of failure. Mismatching symmetries may lead to incorrect conversions. Args: unit_cell: a |Structure| object that identifies the unit cell used for the phonopy calculation. supercell_matrix: a 3x3 array representing the supercell matrix used to generated the forces with phonopy. out_ddb_path: a full path to the file where the new DDB will be written ngqpt: a list of 3 elements indicating the grid of q points that will be used in the DDB. qpt_list: alternatively to ngqpt an explicit list of q-points can be provided here. At least one among ngqpt and qpt_list should be defined. force_constants: an array with shape (num atoms unit cell, num atoms supercell, 3, 3) containing the force constants. Alternatively a string with the path to the FORCE_CONSTANTS file. This or force_set should be defined. If both given this has precedence. force_sets: a dictionary obtained from the force sets generated with phonopy. Alternatively a string with the path to the FORCE_SETS file. This or force_constants should be defined. born: a dictionary with "dielectric" and "born" keywords as obtained from the nac_params in phonopy. Alternatively a string with the path to the BORN file. Notice that the "factor" attribute is not taken into account, so the values should be in default phonopy units. primitive_matrix: a 3x3 array with the primitive matrix passed to Phonopy. "auto" will use spglib to try to determine it automatically. If the DDB file should contain the actual unit cell this should be the identity matrix. symprec: distance tolerance in Cartesian coordinates to find crystal symmetry in phonopy. It might be that the value should be tuned so that it leads to the the same symmetries as in the abinit calculation. tolsym: Gives the tolerance to identify symmetries in abinit. See abinit documentation for more details. supercell: if given it should represent the supercell used to get the force constants, without any perturbation. It will be used to match it to the phonopy supercell and sort the IFC in the correct order. calculator: a string with the name of the calculator. Will be used to set the conversion factor for the force constants coming from phonopy. manager: |TaskManager| object. If None, the object is initialized from the configuration file pseudos: List of filenames or list of |Pseudo| objects or |PseudoTable| object. It will be used by abinit to generate the base DDB file. If None the abipy.data.hgh_pseudos.HGH_TABLE table will be used. verbose: verbosity level. Set it to a value > 0 to get more information workdir: path to the directory where the abinit calculation will be executed. Returns: a DdbFile instance of the file written in out_ddb_path. """ if ngqpt is None and qpt_list is None: raise ValueError( "at least one among nqgpt and qpt_list should be defined") if force_sets is None and force_constants is None: raise ValueError( "at least one of force_sets and force_constants should be provided" ) phon_at = get_phonopy_structure(unit_cell) if isinstance(force_constants, str): force_constants = parse_FORCE_CONSTANTS(filename=force_constants) elif force_constants is not None: force_constants = np.array(force_constants) force_sets = None if isinstance(force_sets, str): force_sets = parse_FORCE_SETS(filename=force_sets) # no nac_params here, otherwise they will be used for the interpolation phonon = Phonopy(phon_at, supercell_matrix, primitive_matrix=primitive_matrix, nac_params=None, symprec=symprec, calculator=calculator) primitive = get_pmg_structure(phonon.primitive) if isinstance(born, str): born = parse_BORN(phonon.primitive, filename=born) if supercell is not None: ph_supercell = get_pmg_structure(phonon.supercell) if not np.allclose(supercell.lattice.matrix, ph_supercell.lattice.matrix): raise RuntimeError("The lattice of the supercells do not match") sc_mapping = [] for i, site_orig in enumerate(supercell): for j, site_ph in enumerate(ph_supercell): d = supercell.lattice.get_distance_and_image( site_orig.frac_coords, site_ph.frac_coords)[0] if d < 1e-5: sc_mapping.append(j) break else: raise RuntimeError( f"Could not find a match for site {i} with coords " f"{site_orig.cart_coords} in the supercell.") # cross check that the same atom was not matched twice n_matches = len(set(sc_mapping)) if n_matches < len(supercell): raise RuntimeError( f"Found matches for {n_matches} different atoms in the supercell: {sc_mapping}" ) force_constants = force_constants[:, sc_mapping] if force_constants is not None: phonon.set_force_constants(force_constants) else: phonon.dataset = force_sets phonon.produce_force_constants() if calculator: units = get_default_physical_units(calculator) fc_factor = get_force_constant_conversion_factor( units["force_constants_unit"], None) phonon.set_force_constants(phonon.force_constants * fc_factor) if pseudos is None: from abipy.data.hgh_pseudos import HGH_TABLE pseudos = HGH_TABLE inp = minimal_scf_input(primitive, pseudos) # get the qpoints list if not defined if qpt_list is None: inp["ngkpt"] = ngqpt qpt_list = inp.abiget_ibz(verbose=verbose)[0] dm_list = get_dm(phonon, qpt_list, primitive) if born is not None: # for the conversion of the BEC the zion (i.e. the ionic charge of the pseudo) # it is an additive factor and should be the same that goes in the header of the DDB, # so take it from the pseudos used to generate it. zion = inp.valence_electrons_per_atom born_data = generate_born_deriv(born, zion, primitive) else: born_data = None inp = minimal_scf_input(primitive, pseudos) if tolsym is not None: inp["tolsym"] = tolsym task = inp.run_in_shell(workdir=workdir, manager=manager, verbose=verbose) # use the output of abinit to check that the spacegroup identified by # phonopy and abinit are the same. with GsrFile(task.opath_from_ext("GSR.nc")) as gsr: abi_spg = gsr.structure.abi_spacegroup.spgid spglib_spg = phonon.symmetry.dataset["number"] if abi_spg != spglib_spg: warnings.warn( "The space group number obtained based on the DDB symmetries differs " f"from the one calculated with spglib: {abi_spg} versus " f"{spglib_spg}. The convertion may be incorrect. Try changing symprec or tolsym." ) tmp_ddb_path = task.opath_from_ext("DDB") ddb = DdbFile(tmp_ddb_path) # remove the blocks generated by the calculation and that are meaningless ddb.remove_block(dord=0) ddb.remove_block(dord=1) add_data_ddb(ddb, dm_list, qpt_list, born_data) ddb.write(out_ddb_path) new_ddb = DdbFile(out_ddb_path) return new_ddb
def test_gsr_silicon(self): """spin unpolarized GSR file""" with GsrFile(abidata.ref_file("si_scf_GSR.nc")) as gsr: assert gsr.basename == "si_scf_GSR.nc" assert gsr.relpath == os.path.relpath( abidata.ref_file("si_scf_GSR.nc")) assert gsr.filetype assert gsr.filestat() assert len(gsr.ncdump()) repr(gsr) str(gsr) assert gsr.to_string(verbose=2) assert gsr.abinit_version == "8.0.6" str(gsr.ebands) assert gsr.filepath == abidata.ref_file("si_scf_GSR.nc") assert gsr.nsppol == 1 assert gsr.mband == 8 and gsr.nband == 8 and gsr.nelect == 8 and len( gsr.kpoints) == 29 assert gsr.mband == gsr.hdr.mband assert "nelect" in gsr.hdr and gsr.nelect == gsr.hdr.nelect self.assert_almost_equal(gsr.energy.to("Ha"), -8.86527676798556) self.assert_almost_equal(gsr.energy_per_atom * len(gsr.structure), gsr.energy) assert gsr.params["nband"] == 8 assert gsr.params["nkpt"] == 29 # Test energy_terms eterms = gsr.energy_terms repr(eterms) str(eterms) assert eterms.to_string(with_doc=True) self.assert_almost_equal(eterms.e_xc.to("Ha"), -3.51815936301812) self.assert_almost_equal(eterms.e_nonlocalpsp.to("Ha"), 1.91660690901782) self.assert_almost_equal(eterms.e_kinetic.to("Ha"), 2.96421325671218) self.assert_almost_equal(eterms.e_fermie.to("Ha"), 0.205739364929368) # Forces and stress self.assert_almost_equal( gsr.cart_forces.to("Ha bohr^-1").flat, [ -1.14726679671674e-28, -3.76037290483622e-29, 5.65937773808884e-29, 1.14726679671674e-28, 3.76037290483622e-29, -5.65937773808884e-29 ]) self.assert_almost_equal(gsr.max_force, 0) assert gsr.force_stats() assert gsr.residm > 0 assert str(gsr.xc) == "LDA_XC_TETER93" #self.assert_almost_equal(gsr.cart_stress_tensor.flat, # Cartesian components of stress tensor (hartree/bohr^3) # sigma(1 1)= 1.77139311E-04 sigma(3 2)= 0.00000000E+00 # sigma(2 2)= 1.77139311E-04 sigma(3 1)= 0.00000000E+00 # sigma(3 3)= 1.77139311E-04 sigma(2 1)= 2.67294316E-15 for i in range(3): self.assert_almost_equal(gsr.cart_stress_tensor[0, 0], 1.77139311E-04 * abu.HaBohr3_GPa) self.assert_almost_equal(gsr.pressure, -5.211617575719521) # Test pymatgen computed_entries for inc_structure in (True, False): e = gsr.get_computed_entry(inc_structure=inc_structure) str(e) d = e.as_dict() if inc_structure: assert "structure" in d assert d["energy"] == gsr.energy assert gsr.energy == e.energy if self.has_matplotlib(): assert gsr.plot_ebands(show=False) assert gsr.plot_ebands_with_edos(edos=gsr.get_edos(), show=False) if self.has_nbformat(): gsr.write_notebook(nbpath=self.get_tmpname(text=True))
def test_gsr_silicon(self): """spin unpolarized GSR file""" almost_equal = self.assertAlmostEqual with GsrFile(abidata.ref_file("si_scf_GSR.nc")) as gsr: assert gsr.basename == "si_scf_GSR.nc" assert gsr.relpath == os.path.relpath( abidata.ref_file("si_scf_GSR.nc")) assert gsr.filetype assert gsr.filestat() assert len(gsr.ncdump()) print(repr(gsr)) print(gsr) print(gsr.ebands) assert gsr.filepath == abidata.ref_file("si_scf_GSR.nc") assert gsr.nsppol == 1 assert gsr.mband == 8 and gsr.nband == 8 and gsr.nelect == 8 and len( gsr.kpoints) == 29 almost_equal(gsr.energy.to("Ha"), -8.86527676798556) almost_equal(gsr.energy_per_atom * len(gsr.structure), gsr.energy) # Test energy_terms eterm = gsr.energy_terms print(eterm) almost_equal(eterm.e_xc.to("Ha"), -3.51815936301812) almost_equal(eterm.e_nonlocalpsp.to("Ha"), 1.91660690901782) almost_equal(eterm.e_kinetic.to("Ha"), 2.96421325671218) almost_equal(eterm.e_fermie.to("Ha"), 0.205739364929368) # Forces and stress self.assert_almost_equal( gsr.cart_forces.to("Ha bohr^-1").flat, [ -1.14726679671674e-28, -3.76037290483622e-29, 5.65937773808884e-29, 1.14726679671674e-28, 3.76037290483622e-29, -5.65937773808884e-29 ]) almost_equal(gsr.max_force, 0) print(gsr.force_stats()) assert gsr.residm > 0 assert str(gsr.xc) == "LDA_XC_TETER93" #self.assert_almost_equal(gsr.cart_stress_tensor.flat, # Cartesian components of stress tensor (hartree/bohr^3) # sigma(1 1)= 1.77139311E-04 sigma(3 2)= 0.00000000E+00 # sigma(2 2)= 1.77139311E-04 sigma(3 1)= 0.00000000E+00 # sigma(3 3)= 1.77139311E-04 sigma(2 1)= 2.67294316E-15 almost_equal(gsr.pressure, -5.21162150) # Test as_dict pprint(gsr.as_dict()) #import json #with open("hello.json", "w") as fp: # json.dump(gsr.as_dict(), fp) #assert 0 # Test pymatgen computed_entries for inc_structure in (True, False): e = gsr.get_computed_entry(inc_structure=inc_structure) print(e) print(e.as_dict()) assert gsr.energy == e.energy if self.has_nbformat(): gsr.write_notebook(nbpath=self.get_tmpname(text=True))