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 setUp(self): if "PMG_VASP_PSP_DIR" not in os.environ: test_potcar_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "test_files")) os.environ["PMG_VASP_PSP_DIR"] = test_potcar_dir filepath = os.path.join(test_dir, 'POTCAR') self.potcar = Potcar.from_file(filepath)
def setUp(self): filepath = self.TEST_FILES_DIR / 'INCAR' incar = Incar.from_file(filepath) filepath = self.TEST_FILES_DIR / 'POSCAR' poscar = Poscar.from_file(filepath,check_for_POTCAR=False) if "PMG_VASP_PSP_DIR" not in os.environ: os.environ["PMG_VASP_PSP_DIR"] = str(self.TEST_FILES_DIR) filepath = self.TEST_FILES_DIR / 'POTCAR' potcar = Potcar.from_file(filepath) filepath = self.TEST_FILES_DIR / 'KPOINTS.auto' kpoints = Kpoints.from_file(filepath) self.vinput = VaspInput(incar, kpoints, poscar, potcar)
def setUp(self): filepath = os.path.join(test_dir, 'INCAR') incar = Incar.from_file(filepath) filepath = os.path.join(test_dir, 'POSCAR') poscar = Poscar.from_file(filepath,check_for_POTCAR=False) if "PMG_VASP_PSP_DIR" not in os.environ: test_potcar_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "test_files")) os.environ["PMG_VASP_PSP_DIR"] = test_potcar_dir filepath = os.path.join(test_dir, 'POTCAR') potcar = Potcar.from_file(filepath) filepath = os.path.join(test_dir, 'KPOINTS.auto') kpoints = Kpoints.from_file(filepath) self.vinput = VaspInput(incar, kpoints, poscar, potcar)
def setUp(self): filepath = os.path.join(test_dir, "INCAR") incar = Incar.from_file(filepath) filepath = os.path.join(test_dir, "POSCAR") poscar = Poscar.from_file(filepath) if "VASP_PSP_DIR" not in os.environ: test_potcar_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "test_files") ) os.environ["VASP_PSP_DIR"] = test_potcar_dir filepath = os.path.join(test_dir, "POTCAR") potcar = Potcar.from_file(filepath) filepath = os.path.join(test_dir, "KPOINTS.auto") kpoints = Kpoints.from_file(filepath) self.vinput = VaspInput(incar, kpoints, poscar, potcar)
def bader_analysis_from_path(path, suffix=''): """ Convenience method to run Bader analysis on a folder containing typical VASP output files. This method will: 1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped counterparts. 2. If AECCAR* files are present, constructs a temporary reference file as AECCAR0 + AECCAR2 3. Runs Bader analysis twice: once for charge, and a second time for the charge difference (magnetization density). :param path: path to folder to search in :param suffix: specific suffix to look for (e.g. '.relax1' for 'CHGCAR.relax1.gz' :return: summary dict """ def _get_filepath(filename, warning, path=path, suffix=suffix): paths = glob.glob(os.path.join(path, filename + suffix + '*')) if not paths: warnings.warn(warning) return None if len(paths) > 1: # using reverse=True because, if multiple files are present, # they likely have suffixes 'static', 'relax', 'relax2', etc. # and this would give 'static' over 'relax2' over 'relax' # however, better to use 'suffix' kwarg to avoid this! paths.sort(reverse=True) warnings.warn('Multiple files detected, using {}'.format(os.path.basename(path))) path = paths[0] return path chgcar_path = _get_filepath('CHGCAR', 'Could not find CHGCAR!') chgcar = Chgcar.from_file(chgcar_path) aeccar0_path = _get_filepath('AECCAR0', 'Could not find AECCAR0, interpret Bader results with caution.') aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None aeccar2_path = _get_filepath('AECCAR2', 'Could not find AECCAR2, interpret Bader results with caution.') aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None potcar_path = _get_filepath('POTCAR', 'Could not find POTCAR, cannot calculate charge transfer.') potcar = Potcar.from_file(potcar_path) if potcar_path else None return bader_analysis_from_objects(chgcar, potcar, aeccar0, aeccar2)
def __init__(self, chgcar_filename, potcar_filename=None): """ Initializes the Bader caller. Args: chgcar_filename: The filename of the CHGCAR. potcar_filename: Optional: the filename of the corresponding POTCAR file. Used for calculating the charge transfer. If None, the get_charge_transfer method will raise a ValueError. """ self.chgcar = Chgcar.from_file(chgcar_filename) self.potcar = Potcar.from_file(potcar_filename) \ if potcar_filename is not None else None self.natoms = self.chgcar.poscar.natoms chgcarpath = os.path.abspath(chgcar_filename) with ScratchDir(".") as temp_dir: shutil.copy(chgcarpath, os.path.join(temp_dir, "CHGCAR")) rs = subprocess.Popen(["bader", "CHGCAR"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) rs.communicate() if rs.returncode != 0: raise RuntimeError("bader exited with return code %d. " "Pls check your bader installation." % rs.returncode) data = [] with open("ACF.dat") as f: raw = f.readlines() headers = [s.lower() for s in raw.pop(0).split()] raw.pop(0) while True: l = raw.pop(0).strip() if l.startswith("-"): break vals = map(float, l.split()[1:]) data.append(dict(zip(headers[1:], vals))) for l in raw: toks = l.strip().split(":") if toks[0] == "VACUUM CHARGE": self.vacuum_charge = float(toks[1]) elif toks[0] == "VACUUM VOLUME": self.vacuum_volume = float(toks[1]) elif toks[0] == "NUMBER OF ELECTRONS": self.nelectrons = float(toks[1]) self.data = data
def setup(self): """ setup solvation jobs for the calibrate objects copies WAVECAR and sets the solvation params in the incar file also dumps system.json file in each directory for the database crawler mind: works only for cal objects that does only single calculations """ for cal in self.cal_objs: jdir = cal.old_job_dir_list[0] cal.poscar = Poscar.from_file(jdir + os.sep + 'POSCAR') cal.potcar = Potcar.from_file(jdir + os.sep + 'POTCAR') cal.kpoints = Kpoints.from_file(jdir + os.sep + 'KPOINTS') cal.incar = Incar.from_file(jdir + os.sep + 'INCAR') cal.incar['LSOL'] = '.TRUE.' syms = [site.specie.symbol for site in cal.poscar.structure] zvals = {p.symbol: p.nelectrons for p in cal.potcar} nelectrons = sum([zvals[a[0]] * len(tuple(a[1])) for a in itertools.groupby(syms)]) keys = [k for k in self.sol_params.keys() if self.sol_params[k]] prod_list = [self.sol_params.get(k) for k in keys] for params in itertools.product(*tuple(prod_list)): job_dir = self.job_dir + os.sep \ + cal.old_job_dir_list[0].replace(os.sep, '_').replace('.', '_') \ + os.sep + 'SOL' for i, k in enumerate(keys): if k == 'NELECT': cal.incar[k] = params[i] + nelectrons else: cal.incar[k] = params[i] job_dir = job_dir + os.sep + k + os.sep + str( cal.incar[k]).replace('.', '_') if not os.path.exists(job_dir): os.makedirs(job_dir) with open(job_dir + os.sep + 'system.json', 'w') as f: json.dump(dict(list(zip(keys, params))), f) wavecar_file = cal.old_job_dir_list[0] + os.sep + 'WAVECAR' if os.path.isfile(wavecar_file): shutil.copy(wavecar_file, job_dir + os.sep + 'WAVECAR') cal.add_job(job_dir=job_dir) else: logger.critical('WAVECAR doesnt exist. Aborting ...') sys.exit(0)
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_write(self): tempfname = Path("POTCAR.testing") self.potcar.write_file(tempfname) p = Potcar.from_file(tempfname) self.assertEqual(p.symbols, self.potcar.symbols) tempfname.unlink()
from pymatgen.io.vasp.inputs import Incar, Poscar, VaspInput,Potcar, Kpoints import os,shutil from custodian.vasp.jobs import VaspJob from custodian.vasp.handlers import VaspErrorHandler, UnconvergedErrorHandler,MeshSymmetryErrorHandler, NonConvergingErrorHandler, PotimErrorHandler from custodian.vasp.validators import VasprunXMLValidator from custodian.custodian import Custodian inc=Incar.from_file("INCAR") pot=Potcar.from_file("POTCAR") pos=Poscar.from_file("POSCAR") kp=Kpoints.from_file("KPOINTS") shutil.copy2('/users/knc6/bin/vdw_kernel.bindat','./') vinput = VaspInput.from_directory(".") job=VaspJob(['mpirun', '-np', '16', '/users/knc6/VASP/vasp54/src/vasp.5.4.1/bin/vasp_std'], final=False, backup=False) handlers = [VaspErrorHandler(), MeshSymmetryErrorHandler(),UnconvergedErrorHandler(), NonConvergingErrorHandler(),PotimErrorHandler()] validators = [VasprunXMLValidator()] c = Custodian(handlers, [job],max_errors=5,validators=validators) c.run()
def setUp(self): self.potcar = Potcar.from_file(test_dir+"/POTCAR") self.zval_dict = {'Ba': 10.0, 'Ti': 10.0, 'O': 6.0} self.ions = ions self.structures = structures
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(f"Post-processing dir:{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(r"(\d+)-ICSD", transformations["history"][0]["source"]) if m: d["icsd_id"] = int(m.group(1)) except Exception: logger.warning( "Cannot parse ICSD from transformations file.") 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: custodian = [] for fname in filenames: with zopen(fname, "rt") as f: custodian.append(json.load(f)[0]) d["custodian"] = custodian # 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() filenames = glob.glob(os.path.join(fullpath, "*.json*")) if self.store_additional_json and filenames: for filename in filenames: key = os.path.basename(filename).split(".")[0] if key != "custodian" and key != "transformations": with zopen(filename, "rt") as f: d[key] = json.load(f) logger.info("Post-processed " + fullpath)
def __init__(self, chgcar_filename, potcar_filename=None, chgref_filename=None, parse_atomic_densities=False): """ Initializes the Bader caller. Args: chgcar_filename (str): The filename of the CHGCAR. potcar_filename (str): Optional: the filename of the corresponding POTCAR file. Used for calculating the charge transfer. If None, the get_charge_transfer method will raise a ValueError. chgref_filename (str): Optional. The filename of the reference CHGCAR, which calculated by AECCAR0 + AECCAR2. (See http://theory.cm.utexas.edu/henkelman/code/bader/ for details.) parse_atomic_densities (bool): Optional. turns on atomic partition of the charge density charge densities are atom centered """ if not BADEREXE: raise RuntimeError( "BaderAnalysis requires the executable bader to be in the path." " Please download the library at http://theory.cm.utexas" ".edu/vasp/bader/ and compile the executable.") self.chgcar = Chgcar.from_file(chgcar_filename) self.potcar = Potcar.from_file(potcar_filename) \ if potcar_filename is not None else None self.natoms = self.chgcar.poscar.natoms chgcarpath = os.path.abspath(chgcar_filename) chgrefpath = os.path.abspath(chgref_filename) if chgref_filename else None self.reference_used = True if chgref_filename else False self.parse_atomic_densities = parse_atomic_densities with ScratchDir(".") as temp_dir: with zopen(chgcarpath, 'rt') as f_in: with open("CHGCAR", "wt") as f_out: shutil.copyfileobj(f_in, f_out) args = [BADEREXE, "CHGCAR"] if chgref_filename: with zopen(chgrefpath, 'rt') as f_in: with open("CHGCAR_ref", "wt") as f_out: shutil.copyfileobj(f_in, f_out) args += ['-ref', 'CHGCAR_ref'] if parse_atomic_densities: args += ['-p', 'all_atom'] rs = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) stdout, stderr = rs.communicate() if rs.returncode != 0: raise RuntimeError("bader exited with return code %d. " "Please check your bader installation." % rs.returncode) try: self.version = float(stdout.split()[5]) except: self.version = -1 # Unknown if self.version < 1.0: warnings.warn('Your installed version of Bader is outdated, ' 'calculation of vacuum charge may be incorrect.') data = [] with open("ACF.dat") as f: raw = f.readlines() headers = ('x', 'y', 'z', 'charge', 'min_dist', 'atomic_vol') raw.pop(0) raw.pop(0) while True: l = raw.pop(0).strip() if l.startswith("-"): break vals = map(float, l.split()[1:]) data.append(dict(zip(headers, vals))) for l in raw: toks = l.strip().split(":") if toks[0] == "VACUUM CHARGE": self.vacuum_charge = float(toks[1]) elif toks[0] == "VACUUM VOLUME": self.vacuum_volume = float(toks[1]) elif toks[0] == "NUMBER OF ELECTRONS": self.nelectrons = float(toks[1]) self.data = data if self.parse_atomic_densities: # convert the charge denisty for each atom spit out by Bader into Chgcar objects for easy parsing atom_chgcars = [Chgcar.from_file("BvAt{}.dat".format(str(i).zfill(4))) for i in range(1, len(self.chgcar.structure) + 1)] atomic_densities = [] # For each atom in the structure for atom, loc, chg in zip(self.chgcar.structure, self.chgcar.structure.frac_coords, atom_chgcars): # Find the index of the atom in the charge density atom index = np.round(np.multiply(loc, chg.dim)) data = chg.data['total'] # Find the shift vector in the array shift = (np.divide(chg.dim, 2) - index).astype(int) # Shift the data so that the atomic charge density to the center for easier manipulation shifted_data = np.roll(data, shift, axis=(0, 1, 2)) # Slices a central window from the data array def slice_from_center(data, xwidth, ywidth, zwidth): x, y, z = data.shape startx = x // 2 - (xwidth // 2) starty = y // 2 - (ywidth // 2) startz = z // 2 - (zwidth // 2) return data[startx:startx + xwidth, starty:starty + ywidth, startz:startz + zwidth] # Finds the central encompassing volume which holds all the data within a precision def find_encompassing_vol(data,prec=1e-3): total = np.sum(data) for i in range(np.max(data.shape)): sliced_data = slice_from_center(data,i,i,i) if total - np.sum(sliced_data) < 0.1: return sliced_data return None d = { "data": find_encompassing_vol(shifted_data), "shift": shift, "dim": self.chgcar.dim } atomic_densities.append(d) self.atomic_densities = atomic_densities
def assimilate(self, path): files = os.listdir(path) try: files_to_parse = {} if "relax1" in files and "relax2" in files: for filename in ("INCAR", "POTCAR", "POSCAR"): search_str = os.path.join(path, "relax1", filename + "*") files_to_parse[filename] = glob.glob(search_str)[0] for filename in ("CONTCAR", "OSZICAR"): search_str = os.path.join(path, "relax2", filename + "*") files_to_parse[filename] = glob.glob(search_str)[-1] else: for filename in ( "INCAR", "POTCAR", "CONTCAR", "OSZICAR", "POSCAR", "DYNMAT" ): files = sorted(glob.glob(os.path.join(path, filename + "*"))) if len(files) < 1: continue if len(files) == 1 or filename == "INCAR" or \ filename == "POTCAR" or filename == "DYNMAT": files_to_parse[filename] = files[-1]\ if filename == "POTCAR" else files[0] elif len(files) > 1: # Since multiple files are ambiguous, we will always # use the first one for POSCAR and the last one # alphabetically for CONTCAR and OSZICAR. if filename == "POSCAR": files_to_parse[filename] = files[0] else: files_to_parse[filename] = files[-1] warnings.warn( "%d files found. %s is being parsed." % (len(files), files_to_parse[filename])) poscar, contcar, incar, potcar, oszicar, dynmat = [None]*6 if 'POSCAR' in files_to_parse: poscar = Poscar.from_file(files_to_parse["POSCAR"]) if 'CONTCAR' in files_to_parse: contcar = Poscar.from_file(files_to_parse["CONTCAR"]) if 'INCAR' in files_to_parse: incar = Incar.from_file(files_to_parse["INCAR"]) if 'POTCAR' in files_to_parse: potcar = Potcar.from_file(files_to_parse["POTCAR"]) if 'OSZICAR' in files_to_parse: oszicar = Oszicar(files_to_parse["OSZICAR"]) if 'DYNMAT' in files_to_parse: dynmat = Dynmat(files_to_parse["DYNMAT"]) param = {"hubbards":{}} if poscar is not None and incar is not None and "LDAUU" in incar: param["hubbards"] = dict(zip(poscar.site_symbols, incar["LDAUU"])) param["is_hubbard"] = ( incar.get("LDAU", False) and sum(param["hubbards"].values()) > 0 ) if incar is not None else False param["run_type"] = None if incar is not None: param["run_type"] = "GGA+U" if param["is_hubbard"] else "GGA" # param["history"] = _get_transformation_history(path) param["potcar_spec"] = potcar.spec if potcar is not None else None energy = oszicar.final_energy if oszicar is not None else 1e10 structure = contcar.structure if contcar is not None\ else poscar.structure initial_vol = poscar.structure.volume if poscar is not None else \ None final_vol = contcar.structure.volume if contcar is not None else \ None delta_volume = None if initial_vol is not None and final_vol is not None: delta_volume = (final_vol / initial_vol - 1) data = {"filename": path, "delta_volume": delta_volume} if dynmat is not None: data['phonon_frequencies'] = dynmat.get_phonon_frequencies() if self._inc_structure: entry = ComputedStructureEntry( structure, energy, parameters=param, data=data ) else: entry = ComputedEntry( structure.composition, energy, parameters=param, data=data ) return entry except Exception as ex: logger.debug("error in {}: {}".format(path, ex)) return None
def setUp(self): self.potcar = Potcar.from_file(test_dir + "/POTCAR") self.zval_dict = {"Ba": 10.0, "Ti": 10.0, "O": 6.0} self.ions = ions self.structures = structures
magmom = [] for el in slab_sorted.get_chemical_symbols(): magmom.append(mag_dic[el]) # for k in range(len(slab_sorted)): # print(slab_sorted[k].symbol," ",magmom[i]) INCAR['MAGMOM'] = magmom magm = [] for m, g in itertools.groupby(INCAR['MAGMOM'], lambda x: float(x)): magm.append("{}*{}".format(len(tuple(g)), m)) """ POTCAR """ potcar_ori = Potcar.from_file('%03d_%s/2nd/POTCAR' % (idx + 1.0, formula)) potcar_symbols = potcar_ori.as_dict()['symbols'] potcar_symbols.sort() POTCAR = Potcar(potcar_symbols) f.writelines(['\t', 'POTCAR_symbols: ', str(potcar_symbols), '\n']) f.writelines([ '\t', 'LDAUL: ', str(INCAR['LDAUL']), '\t', 'LDAUU: ', str(INCAR['LDAUU']), '\t', 'LDAUJ: ', str(INCAR['LDAUJ']), '\n' ]) f.writelines(['\t', 'MAGMOM: ', str(magm), '\n']) """ Write files
def from_path(cls, path, suffix="", zpsp=None): """ Convenience method to run critic2 analysis on a folder containing typical VASP output files. This method will: 1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped counterparts. 2. If AECCAR* files are present, constructs a temporary reference file as AECCAR0 + AECCAR2. 3. Runs critic2 analysis twice: once for charge, and a second time for the charge difference (magnetization density). :param path: path to folder to search in :param suffix: specific suffix to look for (e.g. '.relax1' for 'CHGCAR.relax1.gz') :param zpsp: manually specify ZPSP if POTCAR not present :return: """ chgcar_path = get_filepath("CHGCAR", "Could not find CHGCAR!", path, suffix) chgcar = Chgcar.from_file(chgcar_path) chgcar_ref = None if not zpsp: potcar_path = get_filepath( "POTCAR", "Could not find POTCAR, will not be able to calculate charge transfer.", path, suffix, ) if potcar_path: potcar = Potcar.from_file(potcar_path) zpsp = {p.element: p.zval for p in potcar} if not zpsp: # try and get reference "all-electron-like" charge density if zpsp not present aeccar0_path = get_filepath( "AECCAR0", "Could not find AECCAR0, interpret Bader results with caution.", path, suffix, ) aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None aeccar2_path = get_filepath( "AECCAR2", "Could not find AECCAR2, interpret Bader results with caution.", path, suffix, ) aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None chgcar_ref = aeccar0.linear_add(aeccar2) if (aeccar0 and aeccar2) else None return cls.from_chgcar(chgcar.structure, chgcar, chgcar_ref, zpsp=zpsp)
def __init__( self, chgcar_filename=None, potcar_filename=None, chgref_filename=None, parse_atomic_densities=False, cube_filename=None, ): """ Initializes the Bader caller. Args: chgcar_filename (str): The filename of the CHGCAR. parse_atomic_densities (bool): Optional. turns on atomic partition of the charge density charge densities are atom centered """ if not BADEREXE: raise RuntimeError( "BaderAnalysis requires the executable bader to be in the path." " Please download the library at http://theory.cm.utexas" ".edu/vasp/bader/ and compile the executable.") if not (cube_filename or chgcar_filename): raise ValueError( "You must provide a file! Either a cube file or a CHGCAR") if cube_filename and chgcar_filename: raise ValueError( "You cannot parse a cube and a CHGCAR at the same time!") self.parse_atomic_densities = parse_atomic_densities if chgcar_filename: fpath = os.path.abspath(chgcar_filename) self.is_vasp = True self.chgcar = Chgcar.from_file(chgcar_filename) self.structure = self.chgcar.structure self.potcar = Potcar.from_file( potcar_filename) if potcar_filename is not None else None self.natoms = self.chgcar.poscar.natoms chgrefpath = os.path.abspath( chgref_filename) if chgref_filename else None self.reference_used = bool(chgref_filename) # List of nelects for each atom from potcar potcar_indices = [] for i, v in enumerate(self.natoms): potcar_indices += [i] * v self.nelects = ([ self.potcar[potcar_indices[i]].nelectrons for i in range(len(self.structure)) ] if self.potcar else []) else: fpath = os.path.abspath(cube_filename) self.is_vasp = False self.cube = Cube(fpath) self.structure = self.cube.structure self.nelects = None tmpfile = "CHGCAR" if chgcar_filename else "CUBE" with ScratchDir("."): with zopen(fpath, "rt") as f_in: with open(tmpfile, "wt") as f_out: shutil.copyfileobj(f_in, f_out) args = [BADEREXE, tmpfile] if chgref_filename: with zopen(chgrefpath, "rt") as f_in: with open("CHGCAR_ref", "wt") as f_out: shutil.copyfileobj(f_in, f_out) args += ["-ref", "CHGCAR_ref"] if parse_atomic_densities: args += ["-p", "all_atom"] with subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE, close_fds=True) as rs: stdout, stderr = rs.communicate() if rs.returncode != 0: raise RuntimeError("bader exited with return code %d. " "Please check your bader installation." % rs.returncode) try: self.version = float(stdout.split()[5]) except ValueError: self.version = -1 # Unknown if self.version < 1.0: warnings.warn("Your installed version of Bader is outdated, " "calculation of vacuum charge may be incorrect.") data = [] with open("ACF.dat") as f: raw = f.readlines() headers = ("x", "y", "z", "charge", "min_dist", "atomic_vol") raw.pop(0) raw.pop(0) while True: l = raw.pop(0).strip() if l.startswith("-"): break vals = map(float, l.split()[1:]) data.append(dict(zip(headers, vals))) for l in raw: toks = l.strip().split(":") if toks[0] == "VACUUM CHARGE": self.vacuum_charge = float(toks[1]) elif toks[0] == "VACUUM VOLUME": self.vacuum_volume = float(toks[1]) elif toks[0] == "NUMBER OF ELECTRONS": self.nelectrons = float(toks[1]) self.data = data if self.parse_atomic_densities: # convert the charge denisty for each atom spit out by Bader into Chgcar objects for easy parsing atom_chgcars = [ Chgcar.from_file("BvAt{}.dat".format(str(i).zfill(4))) for i in range(1, len(self.chgcar.structure) + 1) ] atomic_densities = [] # For each atom in the structure for atom, loc, chg in zip( self.chgcar.structure, self.chgcar.structure.frac_coords, atom_chgcars, ): # Find the index of the atom in the charge density atom index = np.round(np.multiply(loc, chg.dim)) data = chg.data["total"] # Find the shift vector in the array shift = (np.divide(chg.dim, 2) - index).astype(int) # Shift the data so that the atomic charge density to the center for easier manipulation shifted_data = np.roll(data, shift, axis=(0, 1, 2)) # Slices a central window from the data array def slice_from_center(data, xwidth, ywidth, zwidth): x, y, z = data.shape startx = x // 2 - (xwidth // 2) starty = y // 2 - (ywidth // 2) startz = z // 2 - (zwidth // 2) return data[startx:startx + xwidth, starty:starty + ywidth, startz:startz + zwidth, ] # Finds the central encompassing volume which holds all the data within a precision def find_encompassing_vol(data, prec=1e-3): total = np.sum(data) for i in range(np.max(data.shape)): sliced_data = slice_from_center(data, i, i, i) if total - np.sum(sliced_data) < 0.1: return sliced_data return None d = { "data": find_encompassing_vol(shifted_data), "shift": shift, "dim": self.chgcar.dim, } atomic_densities.append(d) self.atomic_densities = atomic_densities
def setUp(self): if "PMG_VASP_PSP_DIR" not in os.environ: os.environ["PMG_VASP_PSP_DIR"] = str(self.TEST_FILES_DIR) filepath = self.TEST_FILES_DIR / 'POTCAR' self.potcar = Potcar.from_file(filepath)
def assimilate(self, path): files = os.listdir(path) try: files_to_parse = {} if "relax1" in files and "relax2" in files: for filename in ("INCAR", "POTCAR", "POSCAR"): search_str = os.path.join(path, "relax1", filename + "*") files_to_parse[filename] = glob.glob(search_str)[0] for filename in ("CONTCAR", "OSZICAR"): search_str = os.path.join(path, "relax2", filename + "*") files_to_parse[filename] = glob.glob(search_str)[-1] else: for filename in ("INCAR", "POTCAR", "CONTCAR", "OSZICAR", "POSCAR", "DYNMAT"): files = glob.glob(os.path.join(path, filename + "*")) if len(files) < 1: continue if len(files) == 1 or filename == "INCAR" or \ filename == "POTCAR" or filename == "DYNMAT": files_to_parse[filename] = files[-1]\ if filename == "POTCAR" else files[0] elif len(files) > 1: """ This is a bit confusing, since there maybe be multiple steps. By default, assimilate will try to find a file simply named filename, filename.bz2, or filename.gz. Failing which it will try to get a relax2 from a custodian double relaxation style run if possible. Or else, a random file is chosen. """ for fname in files: if fnmatch.fnmatch( os.path.basename(fname), "{}(\.gz|\.bz2)*".format(filename)): files_to_parse[filename] = fname break if fname == "POSCAR" and \ re.search("relax1", fname): files_to_parse[filename] = fname break if (fname in ("CONTCAR", "OSZICAR") and re.search("relax2", fname)): files_to_parse[filename] = fname break files_to_parse[filename] = fname poscar, contcar, incar, potcar, oszicar, dynmat = [None] * 6 if 'POSCAR' in files_to_parse: poscar = Poscar.from_file(files_to_parse["POSCAR"]) if 'CONTCAR' in files_to_parse: contcar = Poscar.from_file(files_to_parse["CONTCAR"]) if 'INCAR' in files_to_parse: incar = Incar.from_file(files_to_parse["INCAR"]) if 'POTCAR' in files_to_parse: potcar = Potcar.from_file(files_to_parse["POTCAR"]) if 'OSZICAR' in files_to_parse: oszicar = Oszicar(files_to_parse["OSZICAR"]) if 'DYNMAT' in files_to_parse: dynmat = Dynmat(files_to_parse["DYNMAT"]) param = {"hubbards": {}} if poscar is not None and incar is not None and "LDAUU" in incar: param["hubbards"] = dict( zip(poscar.site_symbols, incar["LDAUU"])) param["is_hubbard"] = (incar.get("LDAU", False) and sum(param["hubbards"].values()) > 0 ) if incar is not None else False param["run_type"] = None if incar is not None: param["run_type"] = "GGA+U" if param["is_hubbard"] else "GGA" param["history"] = _get_transformation_history(path) param["potcar_spec"] = potcar.spec if potcar is not None else None energy = oszicar.final_energy if oszicar is not None else 1e10 structure = contcar.structure if contcar is not None\ else poscar.structure initial_vol = poscar.structure.volume if poscar is not None else \ None final_vol = contcar.structure.volume if contcar is not None else \ None delta_volume = None if initial_vol is not None and final_vol is not None: delta_volume = (final_vol / initial_vol - 1) data = {"filename": path, "delta_volume": delta_volume} if dynmat is not None: data['phonon_frequencies'] = dynmat.get_phonon_frequencies() if self._inc_structure: entry = ComputedStructureEntry(structure, energy, parameters=param, data=data) else: entry = ComputedEntry(structure.composition, energy, parameters=param, data=data) return entry except Exception as ex: logger.debug("error in {}: {}".format(path, ex)) return None
def setup(self): self.currdir = os.getcwd() os.chdir(os.path.join(MODULE_DIR, '../../../test_files')) self.vr = Vasprun("vasprun.xml") self.cr = CoreRegion(Potcar.from_file("POTCAR"))
def test_write(self): tempfname = "POTCAR.testing" self.potcar.write_file(tempfname) p = Potcar.from_file(tempfname) self.assertEqual(p.symbols, self.potcar.symbols) os.remove(tempfname)
def __init__( self, path=None, atomic_densities_path=None, run_chargemol=True, ): """ Initializes the Chargemol Analysis. Args: path (str): Path to the CHGCAR, POTCAR, AECCAR0, and AECCAR files. Note that it doesn't matter if the files gzip'd or not. Default: None (current working directory). atomic_densities_path (str|None): Path to the atomic densities directory required by Chargemol. If None, Pymatgen assumes that this is defined in a "DDEC6_ATOMIC_DENSITIES_DIR" environment variable. Only used if run_chargemol is True. Default: None. run_chargemol (bool): Whether to run the Chargemol analysis. If False, the existing Chargemol output files will be read from path. Default: True. """ if not path: path = os.getcwd() if run_chargemol and not (which("Chargemol_09_26_2017_linux_parallel") or which("Chargemol_09_26_2017_linux_serial") or which("chargemol"), ): raise EnvironmentError( "ChargemolAnalysis requires the Chargemol executable to be in the path." " Please download the library at https://sourceforge.net/projects/ddec/files" "and follow the instructions.") if atomic_densities_path == "": atomic_densities_path = os.getcwd() self._atomic_densities_path = atomic_densities_path self._chgcarpath = self._get_filepath(path, "CHGCAR") self._potcarpath = self._get_filepath(path, "POTCAR") self._aeccar0path = self._get_filepath(path, "AECCAR0") self._aeccar2path = self._get_filepath(path, "AECCAR2") if run_chargemol and not (self._chgcarpath and self._potcarpath and self._aeccar0path and self._aeccar2path): raise FileNotFoundError( "CHGCAR, AECCAR0, AECCAR2, and POTCAR are all needed for Chargemol." ) if self._chgcarpath: self.chgcar = Chgcar.from_file(self._chgcarpath) self.structure = self.chgcar.structure self.natoms = self.chgcar.poscar.natoms else: self.chgcar = None self.structure = None self.natoms = None warnings.warn( "No CHGCAR found. Some properties may be unavailable.", UserWarning) if self._potcarpath: self.potcar = Potcar.from_file(self._potcarpath) else: warnings.warn( "No POTCAR found. Some properties may be unavailable.", UserWarning) self.aeccar0 = Chgcar.from_file( self._aeccar0path) if self._aeccar0path else None self.aeccar2 = Chgcar.from_file( self._aeccar2path) if self._aeccar2path else None if run_chargemol: self._execute_chargemol() else: self._from_data_dir(chargemol_output_path=path)
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 assimilate(self, path): files = os.listdir(path) try: files_to_parse = {} if "relax1" in files and "relax2" in files: for filename in ("INCAR", "POTCAR", "POSCAR"): search_str = os.path.join(path, "relax1", filename + "*") files_to_parse[filename] = glob.glob(search_str)[0] for filename in ("CONTCAR", "OSZICAR"): search_str = os.path.join(path, "relax2", filename + "*") files_to_parse[filename] = glob.glob(search_str)[-1] else: for filename in ( "INCAR", "POTCAR", "CONTCAR", "OSZICAR", "POSCAR", "DYNMAT" ): files = sorted(glob.glob(os.path.join(path, filename + "*"))) if len(files) < 1: continue if len(files) == 1 or filename == "INCAR" or \ filename == "POTCAR" or filename == "DYNMAT": files_to_parse[filename] = files[-1] \ if filename == "POTCAR" else files[0] elif len(files) > 1: # Since multiple files are ambiguous, we will always # use the first one for POSCAR and the last one # alphabetically for CONTCAR and OSZICAR. if filename == "POSCAR": files_to_parse[filename] = files[0] else: files_to_parse[filename] = files[-1] warnings.warn( "%d files found. %s is being parsed." % (len(files), files_to_parse[filename])) poscar, contcar, incar, potcar, oszicar, dynmat = [None] * 6 if 'POSCAR' in files_to_parse: poscar = Poscar.from_file(files_to_parse["POSCAR"]) if 'CONTCAR' in files_to_parse: contcar = Poscar.from_file(files_to_parse["CONTCAR"]) if 'INCAR' in files_to_parse: incar = Incar.from_file(files_to_parse["INCAR"]) if 'POTCAR' in files_to_parse: potcar = Potcar.from_file(files_to_parse["POTCAR"]) if 'OSZICAR' in files_to_parse: oszicar = Oszicar(files_to_parse["OSZICAR"]) if 'DYNMAT' in files_to_parse: dynmat = Dynmat(files_to_parse["DYNMAT"]) param = {"hubbards": {}} if poscar is not None and incar is not None and "LDAUU" in incar: param["hubbards"] = dict(zip(poscar.site_symbols, incar["LDAUU"])) param["is_hubbard"] = ( incar.get("LDAU", True) and sum(param["hubbards"].values()) > 0 ) if incar is not None else False param["run_type"] = None if incar is not None: param["run_type"] = Vasprun.run_type # param["history"] = _get_transformation_history(path) param["potcar_spec"] = potcar.spec if potcar is not None else None energy = oszicar.final_energy if oszicar is not None else Vasprun.final_energy structure = contcar.structure if contcar is not None \ else poscar.structure initial_vol = poscar.structure.volume if poscar is not None else \ None final_vol = contcar.structure.volume if contcar is not None else \ None delta_volume = None if initial_vol is not None and final_vol is not None: delta_volume = (final_vol / initial_vol - 1) data = {"filename": path, "delta_volume": delta_volume} if dynmat is not None: data['phonon_frequencies'] = dynmat.get_phonon_frequencies() if self._inc_structure: entry = ComputedStructureEntry( structure, energy, parameters=param, data=data ) else: entry = ComputedEntry( structure.composition, energy, parameters=param, data=data ) return entry except Exception as ex: logger.debug("error in {}: {}".format(path, ex)) return None
INCAR = Incar.from_file(file_path + 'INCAR') POSCAR = Poscar.from_file(file_path + 'CONTCAR') INCAR['ISIF'] = 2 INCAR['IBRION'] = -1 INCAR['ISMEAR'] = 0 INCAR['ISYM'] = -1 INCAR['ICHARG'] = 11 INCAR['NSW'] = 0 INCAR.write_file(file_path + 'DOS/INCAR') KPOINTS.write_file(file_path + 'DOS/KPOINTS') POSCAR.write_file(file_path + 'DOS/POSCAR') # Potcar setup POTCAR = Potcar.from_file(file_path + 'POTCAR') POTCAR.write_file(file_path + 'DOS/POTCAR') # jobscript copy for n, line in enumerate( fileinput.FileInput('jobscript_vasp.sh')): if '#PBS -N' in line: n_line = n elif '#PBS -q' in line: q_line = n elif '#PBS -l' in line: w_line = n PBS_N = '#PBS -N %03d_%s\n' % (idx + 1.0, formula) replace_line('jobscript_vasp.sh', n_line, PBS_N)
def assimilate(self, path): files = os.listdir(path) try: files_to_parse = {} if "relax1" in files and "relax2" in files: for filename in ("INCAR", "POTCAR", "POSCAR"): search_str = os.path.join(path, "relax1", filename + "*") files_to_parse[filename] = glob.glob(search_str)[0] for filename in ("CONTCAR", "OSZICAR"): search_str = os.path.join(path, "relax2", filename + "*") files_to_parse[filename] = glob.glob(search_str)[-1] else: for filename in ( "INCAR", "POTCAR", "CONTCAR", "OSZICAR", "POSCAR", "DYNMAT" ): files = glob.glob(os.path.join(path, filename + "*")) if len(files) < 1: continue if len(files) == 1 or filename == "INCAR" or \ filename == "POTCAR" or filename == "DYNMAT": files_to_parse[filename] = files[-1]\ if filename == "POTCAR" else files[0] elif len(files) > 1: """ This is a bit confusing, since there maybe be multiple steps. By default, assimilate will try to find a file simply named filename, filename.bz2, or filename.gz. Failing which it will try to get a relax2 from a custodian double relaxation style run if possible. Or else, a random file is chosen. """ for fname in files: if fnmatch.fnmatch(os.path.basename(fname), "{}(\.gz|\.bz2)*" .format(filename)): files_to_parse[filename] = fname break if fname == "POSCAR" and \ re.search("relax1", fname): files_to_parse[filename] = fname break if (fname in ("CONTCAR", "OSZICAR") and re.search("relax2", fname)): files_to_parse[filename] = fname break files_to_parse[filename] = fname poscar, contcar, incar, potcar, oszicar, dynmat = [None]*6 if 'POSCAR' in files_to_parse: poscar = Poscar.from_file(files_to_parse["POSCAR"]) if 'CONTCAR' in files_to_parse: contcar = Poscar.from_file(files_to_parse["CONTCAR"]) if 'INCAR' in files_to_parse: incar = Incar.from_file(files_to_parse["INCAR"]) if 'POTCAR' in files_to_parse: potcar = Potcar.from_file(files_to_parse["POTCAR"]) if 'OSZICAR' in files_to_parse: oszicar = Oszicar(files_to_parse["OSZICAR"]) if 'DYNMAT' in files_to_parse: dynmat = Dynmat(files_to_parse["DYNMAT"]) param = {"hubbards":{}} if poscar is not None and incar is not None and "LDAUU" in incar: param["hubbards"] = dict(zip(poscar.site_symbols, incar["LDAUU"])) param["is_hubbard"] = ( incar.get("LDAU", False) and sum(param["hubbards"].values()) > 0 ) if incar is not None else False param["run_type"] = None if incar is not None: param["run_type"] = "GGA+U" if param["is_hubbard"] else "GGA" param["history"] = _get_transformation_history(path) param["potcar_spec"] = potcar.spec if potcar is not None else None energy = oszicar.final_energy if oszicar is not None else 1e10 structure = contcar.structure if contcar is not None\ else poscar.structure initial_vol = poscar.structure.volume if poscar is not None else \ None final_vol = contcar.structure.volume if contcar is not None else \ None delta_volume = None if initial_vol is not None and final_vol is not None: delta_volume = (final_vol / initial_vol - 1) data = {"filename": path, "delta_volume": delta_volume} if dynmat is not None: data['phonon_frequencies'] = dynmat.get_phonon_frequencies() if self._inc_structure: entry = ComputedStructureEntry( structure, energy, parameters=param, data=data ) else: entry = ComputedEntry( structure.composition, energy, parameters=param, data=data ) return entry except Exception as ex: logger.debug("error in {}: {}".format(path, ex)) return None
def setUp(self): if "PMG_VASP_PSP_DIR" not in SETTINGS: SETTINGS["PMG_VASP_PSP_DIR"] = str(PymatgenTest.TEST_FILES_DIR) filepath = PymatgenTest.TEST_FILES_DIR / "POTCAR" self.potcar = Potcar.from_file(filepath)
def from_path(cls, path, suffix="", zpsp=None): """ Convenience method to run critic2 analysis on a folder containing typical VASP output files. This method will: 1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped counterparts. 2. If AECCAR* files are present, constructs a temporary reference file as AECCAR0 + AECCAR2. 3. Runs critic2 analysis twice: once for charge, and a second time for the charge difference (magnetization density). :param path: path to folder to search in :param suffix: specific suffix to look for (e.g. '.relax1' for 'CHGCAR.relax1.gz') :param zpsp: manually specify ZPSP if POTCAR not present :return: """ def _get_filepath(filename, warning, path=path, suffix=suffix): paths = glob.glob(os.path.join(path, filename + suffix + "*")) if not paths: warnings.warn(warning) return None if len(paths) > 1: # using reverse=True because, if multiple files are present, # they likely have suffixes 'static', 'relax', 'relax2', etc. # and this would give 'static' over 'relax2' over 'relax' # however, better to use 'suffix' kwarg to avoid this! paths.sort(reverse=True) warnings.warn("Multiple files detected, using {}".format( os.path.basename(path))) path = paths[0] return path chgcar_path = _get_filepath("CHGCAR", "Could not find CHGCAR!") chgcar = Chgcar.from_file(chgcar_path) chgcar_ref = None if not zpsp: potcar_path = _get_filepath( "POTCAR", "Could not find POTCAR, will not be able to calculate charge transfer.", ) if potcar_path: potcar = Potcar.from_file(potcar_path) zpsp = {p.element: p.zval for p in potcar} if not zpsp: # try and get reference "all-electron-like" charge density if zpsp not present aeccar0_path = _get_filepath( "AECCAR0", "Could not find AECCAR0, interpret Bader results with caution.", ) aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None aeccar2_path = _get_filepath( "AECCAR2", "Could not find AECCAR2, interpret Bader results with caution.", ) aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None chgcar_ref = aeccar0.linear_add(aeccar2) if (aeccar0 and aeccar2) else None return cls(chgcar.structure, chgcar, chgcar_ref, zpsp=zpsp)
def generate_incar(struct, dirname='.', encut=1.5): """ Generate INCAR according to user's choice. Now these templates are available: a >>> Optimization calculation b >>> SCF calculation c >>> BAND structure calculation d >>> DOS calculation e >>> ELF calculation f >>> Bader charge calculation g >>> AIMD NPT calculation h >>> AIMD NVT calculation i >>> Potential calculation j >>> Partial charge calculation k >>> STM image calculation l >>> optical properties calculation m >>> Mechanical properties calculation n >>> Frequency calculation o >>> Transition state calculation p >>> Phonopy + vasp DFPT calculation q >>> Phonopy + vasp finite difference calculation """ try: pots = Potcar.from_file(os.path.join(dirname, "POTCAR")) pot_elems = [] max_encut_elems = [] for pot in pots: pot_elems.append(pot.element) max_encut_elems.append(pot.PSCTR['ENMAX']) struct_elems = [x.value for x in struct.types_of_specie] mlog.debug('Element order in POSCAR %s' % (struct_elems)) mlog.debug('Element order in POTCAR %s' % (pot_elems)) if struct_elems == pot_elems: pass else: print("The element order in POTCAR conflicts with POSCAR ") os._exit() except: warn_tip(0, '\nPOTCAR file not found\n') max_encut_elems = [500] prop_encut = max(max_encut_elems) * encut elec_relax1['ENCUT'] = prop_encut tip='\n'+\ 'for every letter you can append another letters for extra parameters\n'+\ 'The corresponding list are: \n'+\ 'a: SPIN \n'+\ 'b: SOC \n'+\ 'c: HSE \n'+\ 'd: DIPOLE correction \n'+\ 'e: Electric filed \n'+\ 'f: Add grid \n'+\ 'g: Add Pressure \n'+\ 'h: DFT-D2 \n'+\ 'i: DFT-D3 \n'+\ 'j: VDW-DF \n'+\ 'k: opt-B86 \n'+\ 'l: opt-B88 \n'+\ 'm: LDA+U \n'+\ '\nFor exmaple: aai means one optimization by condsidering SPIN and \n'+\ 'DFT-D3 correction. \n' warn_tip(1, tip) sepline(ch=' generate INCAR file ', sp='-') print("your choice?") print('{} >>> {}'.format('a', 'Optimization calculation')) print('{} >>> {}'.format('b', 'SCF calculation')) print('{} >>> {}'.format('c', 'BAND structure calculation')) print('{} >>> {}'.format('d', 'DOS calculation')) print('{} >>> {}'.format('e', 'ELF calculation')) print('{} >>> {}'.format('f', 'Bader charge calculation')) print('{} >>> {}'.format('g', 'AIMD NPT calculation')) print('{} >>> {}'.format('h', 'AIMD NVT calculation')) print('{} >>> {}'.format('i', 'Potential calculation')) print('{} >>> {}'.format('j', 'Partial charge calculation')) print('{} >>> {}'.format('k', 'STM image calculation')) print('{} >>> {}'.format('l', 'optical properties calculation')) print('{} >>> {}'.format('m', 'Mechanical properties calculation')) print('{} >>> {}'.format('n', 'Frequency calculation')) print('{} >>> {}'.format('o', 'Transition state calculation')) print('{} >>> {}'.format('p', 'Phonopy + vasp DFPT calculation')) print('{} >>> {}'.format('q', 'Phonopy + vasp finite difference calculation')) wait_sep() in_str = "" while in_str == "": in_str = input().strip() choice = in_str[0] in_str = ''.join(in_str.split()) # assert choice in range(1,19) ref_incar = MITRelaxSet(struct).incar #print(ref_incar) ref_incar_cite = {} spin_paras['MAGMOM'] = ref_incar['MAGMOM'] try: LDAU_paras['LDAUJ'] = ref_incar['LDAUJ'] LDAU_paras['LDAUL'] = ref_incar['LDAUL'] except: LDAU_paras['LDAUJ'] = None LDAU_paras['LDAUL'] = None elec_relax1['LREAL'] = ref_incar['LREAL'] def parse_extra_incar(in_str, modify_val=None): incar_str = '' for i in range(1, len(in_str)): if in_str[i] != ' ': incar, comment = Incar.from_dict(eval(extra_params[in_str[i]])) incar_str += incar.get_string(pretty=True, comment=comment) return incar_str incar_str = '' if choice == 'a': # Opt calculation for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'b': # SCF calculation ion_relax['NSW'] = 0 elec_relax1['EDIFF'] = ediff_oth output_paras['LCHGARG'] = True output_paras['LWAVE'] = True for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'c': # band structure calculation ion_relax['NSW'] = 0 elec_relax1['EDIFF'] = ediff_oth start_paras['ICHARG'] = 11 for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'd': # DOS calculation ion_relax['NSW'] = 0 elec_relax1['EDIFF'] = ediff_oth start_paras['ICHARG'] = 11 for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'e': # ELF calculatio ion_relax['NSW'] = 0 elec_relax1['EDIFF'] = ediff_oth output_paras['LCHGARG'] = True output_paras['LELF'] = True for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'f': # Bader charge calculation ion_relax['NSW'] = 0 elec_relax1['EDIFF'] = ediff_oth output_paras['LCHGARG'] = True output_paras['LAECHG'] = True for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'g': # AIMD NPT calculation basic_paras.append('md_NPT_paras') ion_relax['NSW'] = md_step ion_relax['IBRION'] = 0 ion_relax['POTIM'] = 1 ion_relax['ISYM'] = 0 for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'h': # AIMD NVT calculation basic_paras.append('md_NVT_paras') ion_relax['NSW'] = md_step ion_relax['IBRION'] = 0 ion_relax['POTIM'] = 1 ion_relax['ISYM'] = 0 ion_relax['ISIF'] = 2 for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'i': # Potential calculation ion_relax['NSW'] = 0 elec_relax1['EDIFF'] = ediff_oth output_paras['LCHGARG'] = True output_paras['LVTOT'] = True for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'j': # Partial charge calculation basic_paras.append('partial_paras') ion_relax['NSW'] = 0 start_paras['ISTART'] = 1 elec_relax1['EDIFF'] = ediff_oth output_paras['LCHGARG'] = True for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'k': # STM image calculation basic_paras.append('stm_paras') ion_relax['NSW'] = 0 start_paras['ISTART'] = 1 elec_relax1['EDIFF'] = ediff_oth output_paras['LCHGARG'] = True for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'l': # optical properties calculation basic_paras.append('optics_paras') ion_relax['NSW'] = 0 start_paras['ISTART'] = 1 elec_relax1['EDIFF'] = ediff_oth for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'm': # Mechanical properties calculation basic_paras.append('stm_paras') ion_relax['NSW'] = 1 ion_relax['NFREE'] = 4 ion_relax['IBRION'] = 6 ion_relax['POTIM'] = 0.015 elec_relax1['EDIFF'] = ediff_oth for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'n': # Frequency calculation ion_relax['NSW'] = 1 ion_relax['NFREE'] = 4 ion_relax['IBRION'] = 5 ion_relax['POTIM'] = 0.015 elec_relax1['EDIFF'] = ediff_oth for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'o': # Transition state calculation basic_paras.append('neb_paras') ion_relax['POTIM'] = 0 ion_relax['EDIFFG'] = ediffg_neb elec_relax1['EDIFF'] = ediff_opt for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif choice == 'p': # Phonopy + vasp DFPT calculation ion_relax['IBRION'] = 8 elec_relax1['EDIFF'] = ediff_phon basic_paras.append(grid_paras) for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) elif 'q' == choice: # Phonopy + vasp finite difference calculation ion_relax['NSW'] = 0 ion_relax['IBRION'] = -1 elec_relax1['EDIFF'] = ediff_phon basic_paras.append(grid_paras) for dict_paras in basic_paras: incar, comment = Incar.from_dict(eval(dict_paras)) incar_str += incar.get_string(pretty=True, comment=comment) if len(in_str) > 1: incar_str += parse_extra_incar(in_str) else: # left empty for extend raise Exception(f"choice '{choice}' not valid!") write_file(os.path.join(dirname, "INCAR"), incar_str)
def assimilate(self, path): """ Assimilate data in a directory path into a ComputedEntry object. Args: path: directory path Returns: ComputedEntry """ files = os.listdir(path) try: files_to_parse = {} filenames = { "INCAR", "POTCAR", "CONTCAR", "OSZICAR", "POSCAR", "DYNMAT" } if "relax1" in files and "relax2" in files: for filename in ("INCAR", "POTCAR", "POSCAR"): search_str = os.path.join(path, "relax1", filename + "*") files_to_parse[filename] = glob.glob(search_str)[0] for filename in ("CONTCAR", "OSZICAR"): search_str = os.path.join(path, "relax2", filename + "*") files_to_parse[filename] = glob.glob(search_str)[-1] else: for filename in filenames: files = sorted( glob.glob(os.path.join(path, filename + "*"))) if len(files) == 1 or filename in ("INCAR", "POTCAR", "DYNMAT"): files_to_parse[filename] = files[0] elif len(files) > 1: # Since multiple files are ambiguous, we will always # use the first one for POSCAR and the last one # alphabetically for CONTCAR and OSZICAR. files_to_parse[filename] = (files[0] if filename == "POSCAR" else files[-1]) warnings.warn("%d files found. %s is being parsed." % (len(files), files_to_parse[filename])) if not set(files_to_parse.keys()).issuperset( {"INCAR", "POTCAR", "CONTCAR", "OSZICAR", "POSCAR"}): raise ValueError( "Unable to parse %s as not all necessary files are present! " "SimpleVaspToComputedEntryDrone requires INCAR, POTCAR, CONTCAR, OSZICAR, POSCAR " "to be present. Only %s detected" % str(files_to_parse.keys())) poscar = Poscar.from_file(files_to_parse["POSCAR"]) contcar = Poscar.from_file(files_to_parse["CONTCAR"]) incar = Incar.from_file(files_to_parse["INCAR"]) potcar = Potcar.from_file(files_to_parse["POTCAR"]) oszicar = Oszicar(files_to_parse["OSZICAR"]) param = {"hubbards": {}} if "LDAUU" in incar: param["hubbards"] = dict( zip(poscar.site_symbols, incar["LDAUU"])) param["is_hubbard"] = (incar.get("LDAU", True) and sum(param["hubbards"].values()) > 0) param["run_type"] = None param["potcar_spec"] = potcar.spec energy = oszicar.final_energy structure = contcar.structure initial_vol = poscar.structure.volume final_vol = contcar.structure.volume delta_volume = final_vol / initial_vol - 1 data = {"filename": path, "delta_volume": delta_volume} if "DYNMAT" in files_to_parse: dynmat = Dynmat(files_to_parse["DYNMAT"]) data["phonon_frequencies"] = dynmat.get_phonon_frequencies() if self._inc_structure: return ComputedStructureEntry(structure, energy, parameters=param, data=data) return ComputedEntry(structure.composition, energy, parameters=param, data=data) except Exception as ex: logger.debug("error in {}: {}".format(path, ex)) return None
mag_dic = dict(zip(elements, mag_list)) magmom = [] for el in slab_sorted.get_chemical_symbols(): magmom.append(mag_dic[el]) INCAR['MAGMOM'] = magmom magm = [] for m, g in itertools.groupby(INCAR['MAGMOM'], lambda x: float(x)): magm.append("{}*{}".format(len(tuple(g)), m)) """ POTCAR """ potcar_ori = Potcar.from_file(file_path + 'POTCAR') potcar_symbols = potcar_ori.as_dict()['symbols'] potcar_symbols.sort() POTCAR = Potcar(potcar_symbols) f.writelines(['\t','POTCAR_symbols: ', str(potcar_symbols), '\n']) f.writelines(['\t', 'LDAUL: ',str(INCAR['LDAUL']),'\t', 'LDAUU: ',str(INCAR['LDAUU']),'\t', 'LDAUJ: ',str(INCAR['LDAUJ']),'\n']) f.writelines(['\t','MAGMOM: ',str(magm),'\n']) print(sorted(elements)," ",INCAR['LDAUU']," ",magm," ",potcar_symbols) """ Write files