def anaget_emacro_and_becs(self, chneut=1, workdir=None, manager=None, verbose=0): """ Call anaddb to compute the macroscopic dielectric tensor and the Born effective charges. Args: chneut: Anaddb input variable. See official documentation. manager: :class:`TaskManager` object. If None, the object is initialized from the configuration file verbose: verbosity level. Set it to a value > 0 to get more information Return: emacro, becs """ inp = AnaddbInput(self.structure, anaddb_kwargs={"chneut": chneut}) task = AnaddbTask.temp_shell_task(inp, ddb_node=self.filepath, workdir=workdir, manager=manager) if verbose: print("ANADDB INPUT:\n", inp) print("workdir:", task.workdir) # Run the task here. task.start_and_wait(autoparal=False) report = task.get_event_report() if not report.run_completed: raise self.AnaddbError(task=task, report=report) # Read data from the netcdf output file produced by anaddb. with ETSF_Reader(os.path.join(task.workdir, "anaddb.nc")) as r: structure = r.read_structure() emacro = Tensor.from_cartesian_tensor(r.read_value("emacro_cart"), structure.lattice, space="r"), becs = Becs(r.read_value("becs_cart"), structure, chneut=inp["chneut"], order="f") return emacro, becs
def test_AnaDdbAbinitTask(self): ana_inp = AnaddbInput.phbands_and_dos(self.si_structure, ngqpt=[4, 4, 4], nqsmall=10) task = abinit_tasks.AnaDdbAbinitTask(ana_inp) task.to_dict() self.assertFwSerializable(task)
def abinp_anaph(options): """Build Anaddb input file for the computation of phonon bands DOS.""" ddb = DdbFile(options.filepath) nqsmall = 10 inp = AnaddbInput.phbands_and_dos(ddb.structure, ddb.guessed_ngqpt, nqsmall, ndivsm=20, q1shft=(0, 0, 0), qptbounds=None, asr=2, chneut=0, dipdip=1, dos_method="tetra", lo_to_splitting=False, anaddb_args=None, anaddb_kwargs=None) return finalize(inp, options)
def anaget_ifc(self, ifcout=None, asr=2, chneut=1, dipdip=1, ngqpt=None, workdir=None, manager=None, verbose=0, anaddb_kwargs=None): """ Execute anaddb to compute the interatomic forces. Args: ifcout: Number of neighbouring atoms for which the ifc's will be output. If None all the atoms in the big box. asr, chneut, dipdip: Anaddb input variable. See official documentation. ngqpt: Number of divisions for the q-mesh in the DDB file. Auto-detected if None (default) workdir: Working directory. If None, a temporary directory is created. manager: :class:`TaskManager` object. If None, the object is initialized from the configuration file verbose: verbosity level. Set it to a value > 0 to get more information anaddb_kwargs: additional kwargs for anaddb Returns: :class:`InteratomicForceConstants` with the calculated ifc. """ if ngqpt is None: ngqpt = self.guessed_ngqpt inp = AnaddbInput.ifc(self.structure, ngqpt=ngqpt, ifcout=ifcout, q1shft=(0, 0, 0), asr=asr, chneut=chneut, dipdip=dipdip, anaddb_kwargs=anaddb_kwargs) task = AnaddbTask.temp_shell_task(inp, ddb_node=self.filepath, workdir=workdir, manager=manager) if verbose: print("ANADDB INPUT:\n", inp) print("workdir:", task.workdir) # Run the task here. task.start_and_wait(autoparal=False) report = task.get_event_report() if not report.run_completed: raise self.AnaddbError(task=task, report=report) return InteratomicForceConstants.from_file( os.path.join(task.workdir, 'anaddb.nc'))
def anaget_phbst_and_phdos_files(self, nqsmall=10, ndivsm=20, asr=2, chneut=1, dipdip=1, dos_method="tetra", ngqpt=None, workdir=None, manager=None, verbose=0, lo_to_splitting=False): """ Execute anaddb to compute the phonon band structure and the phonon DOS Args: nqsmall: Defines the homogeneous q-mesh used for the DOS. Gives the number of divisions used to sample the smallest lattice vector. ndivsm: Number of division used for the smallest segment of the q-path asr, chneut, dipdp: Anaddb input variable. See official documentation. dos_method: Technique for DOS computation in Possible choices: "tetra", "gaussian" or "gaussian:0.001 eV". In the later case, the value 0.001 eV is used as gaussian broadening ngqpt: Number of divisions for the q-mesh in the DDB file. Auto-detected if None (default) workdir: Working directory. If None, a temporary directory is created. manager: :class:`TaskManager` object. If None, the object is initialized from the configuration file verbose: verbosity level. Set it to a value > 0 to get more information lo_to_splitting: if True calculation of the LO-TO splitting will be calculated and included in the band structure Returns: :class:`PhbstFile` with the phonon band structure. :class:`PhdosFile` with the the phonon DOS. """ if ngqpt is None: ngqpt = self.guessed_ngqpt inp = AnaddbInput.phbands_and_dos( self.structure, ngqpt=ngqpt, ndivsm=ndivsm, nqsmall=nqsmall, q1shft=(0,0,0), qptbounds=None, asr=asr, chneut=chneut, dipdip=dipdip, dos_method=dos_method, lo_to_splitting=lo_to_splitting) task = AnaddbTask.temp_shell_task(inp, ddb_node=self.filepath, workdir=workdir, manager=manager) if verbose: print("ANADDB INPUT:\n", inp) print("workdir:", task.workdir) # Run the task here. task.start_and_wait(autoparal=False) report = task.get_event_report() if not report.run_completed: raise self.AnaddbError(task=task, report=report) phbst = task.open_phbst() if lo_to_splitting: with ETSF_Reader(os.path.join(task.workdir, "anaddb.nc")) as r: directions = r.read_value("non_analytical_directions") non_anal_phfreq = r.read_value("non_analytical_phonon_modes") phbst.phbands.non_anal_directions = directions phbst.phbands.non_anal_phfreqs = non_anal_phfreq return phbst, task.open_phdos()
def anaget_phmodes_at_qpoint(self, qpoint=None, asr=2, chneut=1, dipdip=1, workdir=None, manager=None, verbose=0): """ Execute anaddb to compute phonon modes at the given q-point. Args: qpoint: Reduced coordinates of the qpoint where phonon modes are computed. asr, chneut, dipdp: Anaddb input variable. See official documentation. workdir: Working directory. If None, a temporary directory is created. manager: :class:`TaskManager` object. If None, the object is initialized from the configuration file verbose: verbosity level. Set it to a value > 0 to get more information Return: :class:`PhononBands` object. """ if qpoint is None: qpoint = self.qpoints[0] if len(self.qpoints) != 1: raise ValueError("%s contains %s qpoints and the choice is ambiguous.\n" "Please specify the qpoint." % (self, len(self.qpoints))) # Check if qpoint is in the DDB. try: self.qindex(qpoint) except: raise ValueError("input qpoint %s not in ddb.qpoints:%s\n" % (qpoint, self.qpoints)) inp = AnaddbInput.modes_at_qpoint(self.structure, qpoint, asr=asr, chneut=chneut, dipdip=dipdip) task = AnaddbTask.temp_shell_task(inp, ddb_node=self.filepath, workdir=workdir, manager=manager) if verbose: print("ANADDB INPUT:\n", inp) print("workdir:", task.workdir) # Run the task here task.start_and_wait(autoparal=False) report = task.get_event_report() if not report.run_completed: raise self.AnaddbError(task=task, report=report) with task.open_phbst() as ncfile: return ncfile.phbands
def anaget_phbst_and_phdos_files(self, nqsmall=10, ndivsm=20, asr=2, chneut=1, dipdip=1, dos_method="tetra", ngqpt=None, workdir=None, manager=None, verbose=0): """ Execute anaddb to compute the phonon band structure and the phonon DOS Args: nqsmall: Defines the homogeneous q-mesh used for the DOS. Gives the number of divisions used to sample the smallest lattice vector. ndivsm: Number of division used for the smallest segment of the q-path asr, chneut, dipdp: Anaddb input variable. See official documentation. dos_method: Technique for DOS computation in Possible choices: "tetra", "gaussian" or "gaussian:0.001 eV". In the later case, the value 0.001 eV is used as gaussian broadening ngqpt: Number of divisions for the q-mesh in the DDB file. Auto-detected if None (default) workdir: Working directory. If None, a temporary directory is created. manager: :class:`TaskManager` object. If None, the object is initialized from the configuration file verbose: verbosity level. Set it to a value > 0 to get more information Returns: :class:`PhbstFile` with the phonon band structure. :class:`PhdosFile` with the the phonon DOS. """ if ngqpt is None: ngqpt = self.guessed_ngqpt inp = AnaddbInput.phbands_and_dos( self.structure, ngqpt=ngqpt, ndivsm=ndivsm, nqsmall=nqsmall, q1shft=(0,0,0), qptbounds=None, asr=asr, chneut=chneut, dipdip=dipdip, dos_method=dos_method) task = AnaddbTask.temp_shell_task(inp, ddb_node=self.filepath, workdir=workdir, manager=manager) if verbose: print("ANADDB INPUT:\n", inp) print("workdir:", task.workdir) # Run the task here. task.start_and_wait(autoparal=False) report = task.get_event_report() if not report.run_completed: raise self.AnaddbError(task=task, report=report) return task.open_phbst(), task.open_phdos()
def from_ddb_list(cls, ddb_list, nqsmall=10, qppa=None, ndivsm=20, line_density=None, asr=2, chneut=1, dipdip=1, dos_method="tetra", lo_to_splitting="automatic", ngqpt=None, qptbounds=None, anaddb_kwargs=None, verbose=0, mpi_procs=1, workdir=None, manager=None): """ Execute anaddb to compute generate the object from a list of ddbs. Args: ddb_list: A list with the paths to the ddb_files at different volumes. There should be an odd number of DDB files and the volume increment must be constant. The DDB files will be ordered according to the volume of the unit cell and the middle one will be considered as the DDB at the relaxed volume. nqsmall: Defines the homogeneous q-mesh used for the DOS. Gives the number of divisions used to sample the smallest lattice vector. If 0, DOS is not computed and (phbst, None) is returned. qppa: Defines the homogeneous q-mesh used for the DOS in units of q-points per reciprocal atom. Overrides nqsmall. ndivsm: Number of division used for the smallest segment of the q-path. line_density: Defines the a density of k-points per reciprocal atom to plot the phonon dispersion. Overrides ndivsm. asr, chneut, dipdip: Anaddb input variable. See official documentation. dos_method: Technique for DOS computation in Possible choices: "tetra", "gaussian" or "gaussian:0.001 eV". In the later case, the value 0.001 eV is used as gaussian broadening. lo_to_splitting: Allowed values are [True, False, "automatic"]. Defaults to "automatic" If True the LO-TO splitting will be calculated and the non_anal_directions and the non_anal_phfreqs attributes will be addeded to the phonon band structure. "automatic" activates LO-TO if the DDB file contains the dielectric tensor and Born effective charges. ngqpt: Number of divisions for the q-mesh in the DDB file. Auto-detected if None (default). qptbounds: Boundaries of the path. If None, the path is generated from an internal database depending on the input structure. anaddb_kwargs: additional kwargs for anaddb. verbose: verbosity level. Set it to a value > 0 to get more information. mpi_procs: Number of MPI processes to use. workdir: Working directory. If None, a temporary directory is created. manager: |TaskManager| object. If None, the object is initialized from the configuration file. Returns: A GrunsNcFile object. """ if len(ddb_list) % 2 != 1: raise ValueError("An odd number of ddb file paths should be provided") ddbs = [DdbFile(d) for d in ddb_list] ddbs = sorted(ddbs, key=lambda d: d.structure.volume) iv0 = int((len(ddbs) - 1) / 2) ddb0 = ddbs[iv0] # update list of paths with absolute paths in the correct order ddb_list = [d.filepath for d in ddbs] if ngqpt is None: ngqpt = ddb0.guessed_ngqpt if lo_to_splitting == "automatic": lo_to_splitting = ddb0.has_lo_to_data() and dipdip != 0 if lo_to_splitting and not ddb0.has_lo_to_data(): cprint("lo_to_splitting is True but Emacro and Becs are not available in DDB: %s" % ddb0.filepath, "yellow") inp = AnaddbInput.phbands_and_dos( ddb0.structure, ngqpt=ngqpt, ndivsm=ndivsm, nqsmall=nqsmall, qppa=qppa, line_density=line_density, q1shft=(0, 0, 0), qptbounds=qptbounds, asr=asr, chneut=chneut, dipdip=dipdip, dos_method=dos_method, lo_to_splitting=lo_to_splitting, anaddb_kwargs=anaddb_kwargs) inp["gruns_ddbs"] = ['"'+p+'"\n' for p in ddb_list] inp["gruns_nddbs"] = len(ddb_list) task = AnaddbTask.temp_shell_task(inp, ddb_node=ddb0.filepath, workdir=workdir, manager=manager, mpi_procs=mpi_procs) if verbose: print("ANADDB INPUT:\n", inp) print("workdir:", task.workdir) # Run the task here. task.start_and_wait(autoparal=False) report = task.get_event_report() if not report.run_completed: raise ddb0.AnaddbError(task=task, report=report) gruns = cls.from_file(os.path.join(task.workdir, "run.abo_GRUNS.nc")) return gruns
def from_ddb(cls, ddb_path, directions=None, labels=None, num_points=20, qpt_norm=0.1, ignore_neg_freqs=True, asr=2, chneut=1, dipdip=1, ngqpt=None, spell_check=True, anaddb_kwargs=None, verbose=0, mpi_procs=1, workdir=None, manager=None): """ Creates and instance of the object. Runs anaddb along the specified directions or the standard directions in the standard paths given in :cite:`Setyawan2010`. The values of the speed of sound will be calculated as the slope of the linear fits along each direction. Args: ddb_path (str): path to the ddb file. directions (list): list of qpoints identifying the directions for the calculation of the speed of sound. In fractional coordinates. labels (list): list of string with the name of the directions. num_points (int): number of points calculated along each direction and used to fit the speed of sound. qpt_norm (float): Norm of the largest point in fractional coordinates for each of the directions considered. ignore_neg_freqs (bool): if True points with negative frequencies will not be considered in the fit, in order to ignore inaccuracies in the long range behavior. asr, chneut, dipdip: Anaddb input variable. See official documentation. ngqpt: Number of divisions for the q-mesh in the DDB file. Auto-detected if None (default). anaddb_kwargs: additional kwargs for anaddb. verbose: verbosity level. Set it to a value > 0 to get more information. mpi_procs: Number of MPI processes to use. workdir: Working directory. If None, a temporary directory is created. manager: |TaskManager| object. If None, the object is initialized from the configuration file. long. Returns: an instance of SoundVelocity """ with DdbFile(ddb_path) as ddb: if ngqpt is None: ngqpt = ddb.guessed_ngqpt inp = AnaddbInput(ddb.structure, comment="ANADDB input for speed of sound", anaddb_kwargs=anaddb_kwargs, spell_check=spell_check) q1shft = [[0, 0, 0]] inp.set_vars( ifcflag=1, ngqpt=np.array(ngqpt), q1shft=q1shft, nqshft=len(q1shft), asr=asr, chneut=chneut, dipdip=dipdip, ) if not directions: hs = ddb.structure.hsym_kpath kpath = hs.kpath directions = [] labels = [] for chunk in kpath["path"]: for i, q in enumerate(chunk): if "Gamma" in q: if i > 0 and q not in labels: new_q = kpath["kpoints"][chunk[i - 1]] directions.append(new_q) labels.append(chunk[i - 1]) if i < len(chunk) - 1 and q not in labels: new_q = kpath["kpoints"][chunk[i + 1]] directions.append(new_q) labels.append(chunk[i + 1]) qpts = [] for q in directions: q = qpt_norm * q / np.linalg.norm(q) steps = q / num_points qpts.extend((steps[:, None] * np.arange(num_points)).T) n_qpoints = len(qpts) qph1l = np.zeros((n_qpoints, 4)) qph1l[:, :-1] = qpts qph1l[:, -1] = 1 inp['qph1l'] = qph1l.tolist() inp['nph1l'] = n_qpoints task = ddb._run_anaddb_task(inp, mpi_procs=mpi_procs, workdir=workdir, manager=manager, verbose=verbose) phbst_path = os.path.join(task.workdir, "run.abo_PHBST.nc") return cls.from_phbst(phbst_path, ignore_neg_freqs=ignore_neg_freqs, labels=labels)
def get_anaddb_input(self, item): """ creates the AnaddbInput object. It also returns the list of qpoints labels for generating the PhononBandStructureSymmLine. """ ngqpt = item["abinit_input.ngqpt"] q1shft = [(0, 0, 0)] structure = Structure.from_dict(item["abinit_input.structure"]) hs = HighSymmKpath(structure, symprec=1e-2) spgn = hs._sym.get_space_group_number() if spgn != item["spacegroup.number"]: raise RuntimeError("Parsed specegroup number {} does not match " "calculation spacegroup {}".format(spgn, item["spacegroup.number"])) # for the moment use gaussian smearing prtdos = 1 dossmear = 3 / Ha_cmm1 lo_to_splitting = True dipdip = 1 asr = 2 chneut = 1 ng2qppa = 50000 inp = AnaddbInput(structure, comment="ANADB input for phonon bands and DOS") inp.set_vars( ifcflag=1, ngqpt=np.array(ngqpt), q1shft=q1shft, nqshft=len(q1shft), asr=asr, chneut=chneut, dipdip=dipdip, ) # Parameters for the dos. ng2qpt = KSampling.automatic_density(structure, kppa=ng2qppa).kpts[0] inp.set_vars(prtdos=prtdos, dosdeltae=None, dossmear=dossmear, ng2qpt=ng2qpt) # Parameters for the BS qpts, labels_list = hs.get_kpoints(line_density=18, coords_are_cartesian=False) n_qpoints = len(qpts) qph1l = np.zeros((n_qpoints, 4)) qph1l[:, :-1] = qpts qph1l[:, -1] = 1 inp['qph1l'] = qph1l.tolist() inp['nph1l'] = n_qpoints if lo_to_splitting: kpath = hs.kpath directions = [] for qptbounds in kpath['path']: for i, qpt in enumerate(qptbounds): if np.array_equal(kpath['kpoints'][qpt], (0, 0, 0)): # anaddb expects cartesian coordinates for the qph2l list if i > 0: directions.extend(structure.lattice.reciprocal_lattice_crystallographic.get_cartesian_coords( kpath['kpoints'][qptbounds[i - 1]])) directions.append(0) if i < len(qptbounds) - 1: directions.extend(structure.lattice.reciprocal_lattice_crystallographic.get_cartesian_coords( kpath['kpoints'][qptbounds[i + 1]])) directions.append(0) if directions: directions = np.reshape(directions, (-1, 4)) inp.set_vars( nph2l=len(directions), qph2l=directions ) return inp, labels_list
def anaget_phmodes_at_qpoint(self, qpoint=None, asr=2, chneut=1, dipdip=1, workdir=None, manager=None, verbose=0, lo_to_splitting=False, directions=None, anaddb_kwargs=None): """ Execute anaddb to compute phonon modes at the given q-point. Args: qpoint: Reduced coordinates of the qpoint where phonon modes are computed. asr, chneut, dipdp: Anaddb input variable. See official documentation. workdir: Working directory. If None, a temporary directory is created. manager: :class:`TaskManager` object. If None, the object is initialized from the configuration file verbose: verbosity level. Set it to a value > 0 to get more information lo_to_splitting: if True the LO-TO splitting will be calculated if qpoint==Gamma and the non_anal_directions non_anal_phfreqs attributes will be added to the returned object directions: list of 3D directions along which the LO-TO splitting will be calculated. If None the three cartesian direction will be used anaddb_kwargs: additional kwargs for anaddb Return: :class:`PhononBands` object. """ if qpoint is None: qpoint = self.qpoints[0] if len(self.qpoints) != 1: raise ValueError( "%s contains %s qpoints and the choice is ambiguous.\n" "Please specify the qpoint." % (self, len(self.qpoints))) # Check if qpoint is in the DDB. try: self.qindex(qpoint) except: raise ValueError("input qpoint %s not in ddb.qpoints:%s\n" % (qpoint, self.qpoints)) inp = AnaddbInput.modes_at_qpoint(self.structure, qpoint, asr=asr, chneut=chneut, dipdip=dipdip, lo_to_splitting=lo_to_splitting, directions=directions, anaddb_kwargs=anaddb_kwargs) task = AnaddbTask.temp_shell_task(inp, ddb_node=self.filepath, workdir=workdir, manager=manager) if verbose: print("ANADDB INPUT:\n", inp) print("workdir:", task.workdir) # Run the task here task.start_and_wait(autoparal=False) report = task.get_event_report() if not report.run_completed: raise self.AnaddbError(task=task, report=report) with task.open_phbst() as ncfile: if lo_to_splitting and np.allclose(qpoint, [0, 0, 0]): ncfile.phbands.read_non_anal_from_file( os.path.join(task.workdir, "anaddb.nc")) return ncfile.phbands
def add_phonon_works_and_build(self): """ Get relaxed structures from the tasks, build Phonons works with new structures. Add works to the flow and build new directories. """ ddb_paths, struct_middle, middle_idx = [], None, None relaxed_structs = [] for i, task in enumerate(self.relax_tasks): relaxed_structure = task.get_final_structure() relaxed_structs.append(relaxed_structure) if i == len(self.relax_tasks) // 2: middle_idx, struct_middle = i, relaxed_structure # work to compute phonons with new structure. gsinp_vol = self.gs_inp.new_with_structure(relaxed_structure) work = PhononWork.from_scf_input(gsinp_vol, self.ngqpt, is_ngqpt=True, tolerance=self.tolerance, with_becs=self.with_becs, ddk_tolerance=self.ddk_tolerance) # Add it to the flow. self.flow.register_work(work) ddb_paths.append(work.outdir.path_in("out_DDB")) # Write Anaddb input file to compute Gruneisen parameters in flow.outdata. from abipy.abio.inputs import AnaddbInput anaddb_inp = AnaddbInput.phbands_and_dos(struct_middle, self.ngqpt, nqsmall=20, ndivsm=20, chneut=1 if self.with_becs else 0, dipdip=1 if self.with_becs else 0, lo_to_splitting=self.with_becs, comment="Anaddb input file for Grunesein parameters") # Add DDB files for Gruns anaddb_inp["gruns_nddbs"] = len(ddb_paths) anaddb_inp["gruns_ddbs"] = "\n" + "\n".join('"%s"' % p for p in ddb_paths) in_path = self.flow.outdir.path_in("anaddb_gruns.in") anaddb_inp.write(in_path) files_file = [] app = files_file.append app(in_path) # 1) Path of the input file app(self.flow.outdir.path_in("anaddb_gruns.out")) # 2) Path of the output file app(ddb_paths[middle_idx]) # 3) Input derivative database (not used if Gruns) for i in range(4): app("FOOBAR") with open(self.flow.outdir.path_in("anaddb_gruns.files"), "wt") as fh: fh.write("\n".join(files_file)) #with_ebands = False #if with_ebands: # bands_work = Work(manager=self.manager) # for i, structure in enumerate(relaxed_structs): # nscf_inp = self.gs_inp.new_with_structure(structure) # nscf_inp.pop_tolerances() # nscf_inp.set_kpath(ndivsm, kptbounds=None, iscf=-2) # nscf_inp["tolwfr"] = 1e-18 # work.register_nscf_task(nscf_inp, deps={self.relax_tasks[i]: "DEN"}) # # Add it to the flow. # self.flow.register_work(work) # Allocate new works and update the pickle database. self.flow.allocate() self.flow.build_and_pickle_dump()
def test_AnaDdbAbinitTask(self): ana_inp = AnaddbInput.phbands_and_dos(self.si_structure, ngqpt=[4,4,4], nqsmall=10) task = abinit_tasks.AnaDdbAbinitTask(ana_inp) task.to_dict() self.assertFwSerializable(task)