def get_dipole_moment(self, atoms=None): '''Tries to return the dipole vector of the unit cell in atomic units. Returns None when CHG file is empty/not-present. To get the dipole moment, use this formula: dipole_moment = ((dipole_vector**2).sum())**0.5/Debye ''' if atoms is None: atoms = self.get_atoms() try: x, y, z, cd = self.get_charge_density() except (IOError, IndexError): # IOError: no CHG file, function called outside context manager # IndexError: Empty CHG file, Vasp run with lcharg=False return None n0, n1, n2 = cd.shape nelements = n0 * n1 * n2 voxel_volume = atoms.get_volume() / nelements total_electron_charge = -cd.sum() * voxel_volume electron_density_center = np.array([(cd*x).sum(), (cd*y).sum(), (cd*z).sum()]) electron_density_center *= voxel_volume electron_density_center /= total_electron_charge electron_dipole_moment = electron_density_center * total_electron_charge electron_dipole_moment *= -1.0 # now the ion charge center LOP = self.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] # make dictionary for ease of use zval = {} for sym, ppath, hash in LOP: # out a bug above. os.path.join discards the root if the # second path starts with /, which makes it look like an # absolute path. the get_pseudopotentials code returns a path # with a / in the beginning. fullpath = ppp + ppath z = get_ZVAL(fullpath) zval[sym] = z ion_charge_center = np.array([0.0, 0.0, 0.0]) total_ion_charge = 0.0 for atom in atoms: Z = zval[atom.symbol] total_ion_charge += Z pos = atom.position ion_charge_center += Z*pos ion_charge_center /= total_ion_charge ion_dipole_moment = ion_charge_center * total_ion_charge dipole_vector = (ion_dipole_moment + electron_dipole_moment) return dipole_vector
def get_dipole_vector(self, atoms=None): """Tries to return the dipole vector of the unit cell in atomic units. Returns None when CHG file is empty/not-present. """ self.update() from POTCAR import get_ZVAL if atoms is None: atoms = self.get_atoms() try: x, y, z, cd = self.get_charge_density() except (IOError, IndexError): # IOError: no CHG file, function called outside context manager # IndexError: Empty CHG file, Vasp run with lcharg=False return None n0, n1, n2 = cd.shape nelements = n0 * n1 * n2 voxel_volume = atoms.get_volume() / nelements total_electron_charge = -cd.sum() * voxel_volume electron_density_center = np.array([(cd * x).sum(), (cd * y).sum(), (cd * z).sum()]) electron_density_center *= voxel_volume electron_density_center /= total_electron_charge electron_dipole_moment = electron_density_center * total_electron_charge electron_dipole_moment *= -1.0 # now the ion charge center LOP = self.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] # make dictionary for ease of use zval = {} for sym, ppath, hash in LOP: fullpath = os.path.join(ppp, ppath) z = get_ZVAL(fullpath) zval[sym] = z ion_charge_center = np.array([0.0, 0.0, 0.0]) total_ion_charge = 0.0 for atom in atoms: Z = zval[atom.symbol] total_ion_charge += Z pos = atom.position ion_charge_center += Z * pos ion_charge_center /= total_ion_charge ion_dipole_moment = ion_charge_center * total_ion_charge dipole_vector = (ion_dipole_moment + electron_dipole_moment) return dipole_vector
def get_dipole_moment(self, atoms=None): '''Tries to return the dipole vector of the unit cell in atomic units. Returns None when CHG file is empty/not-present. To get the dipole moment, use this formula: dipole_moment = ((dipole_vector**2).sum())**0.5/Debye ''' if atoms is None: atoms = self.get_atoms() try: x, y, z, cd = self.get_charge_density() except (IOError, IndexError): # IOError: no CHG file, function called outside context manager # IndexError: Empty CHG file, Vasp run with lcharg=False return None n0, n1, n2 = cd.shape nelements = n0 * n1 * n2 voxel_volume = atoms.get_volume() / nelements total_electron_charge = -cd.sum() * voxel_volume electron_density_center = np.array([(cd * x).sum(), (cd * y).sum(), (cd * z).sum()]) electron_density_center *= voxel_volume electron_density_center /= total_electron_charge electron_dipole_moment = electron_density_center * total_electron_charge electron_dipole_moment *= -1.0 # now the ion charge center LOP = self.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] # make dictionary for ease of use zval = {} for sym, ppath, hash in LOP: # out a bug above. os.path.join discards the root if the # second path starts with /, which makes it look like an # absolute path. the get_pseudopotentials code returns a path # with a / in the beginning. fullpath = ppp + ppath z = get_ZVAL(fullpath) zval[sym] = z ion_charge_center = np.array([0.0, 0.0, 0.0]) total_ion_charge = 0.0 for atom in atoms: Z = zval[atom.symbol] total_ion_charge += Z pos = atom.position ion_charge_center += Z * pos ion_charge_center /= total_ion_charge ion_dipole_moment = ion_charge_center * total_ion_charge dipole_vector = (ion_dipole_moment + electron_dipole_moment) return dipole_vector
def get_dipole_moment(self): """Return dipole moment (vector) of unit cell in atomic units. :returns: a vector of the dipole moment :rtype: :class:`numpy.array` dipole_moment = ((dipole_vector**2).sum())**0.5/Debye """ atoms = self.get_atoms() x, y, z, cd = self.get_charge_density() n0, n1, n2 = cd.shape nelements = n0 * n1 * n2 voxel_volume = atoms.get_volume() / nelements total_electron_charge = -cd.sum() * voxel_volume electron_density_center = np.array([(cd * x).sum(), (cd * y).sum(), (cd * z).sum()]) electron_density_center *= voxel_volume electron_density_center /= total_electron_charge electron_dipole_moment = electron_density_center * total_electron_charge electron_dipole_moment *= -1.0 # now the ion charge center LOP = self.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] # make dictionary for ease of use zval = {} for sym, ppath, hash in LOP: fullpath = os.path.join(ppp, ppath) z = get_ZVAL(fullpath) zval[sym] = z ion_charge_center = np.array([0.0, 0.0, 0.0]) total_ion_charge = 0.0 for atom in atoms: Z = zval[atom.symbol] total_ion_charge += Z pos = atom.position ion_charge_center += Z*pos ion_charge_center /= total_ion_charge ion_dipole_moment = ion_charge_center * total_ion_charge dipole_vector = (ion_dipole_moment + electron_dipole_moment) return dipole_vector
def get_dipole_moment(self): """Return dipole moment (vector) of unit cell in atomic units. :returns: a vector of the dipole moment :rtype: :class:`numpy.array` dipole_moment = ((dipole_vector**2).sum())**0.5/Debye """ atoms = self.get_atoms() x, y, z, cd = self.get_charge_density() n0, n1, n2 = cd.shape nelements = n0 * n1 * n2 voxel_volume = atoms.get_volume() / nelements total_electron_charge = -cd.sum() * voxel_volume electron_density_center = np.array([(cd * x).sum(), (cd * y).sum(), (cd * z).sum()]) electron_density_center *= voxel_volume electron_density_center /= total_electron_charge electron_dipole_moment = electron_density_center * total_electron_charge electron_dipole_moment *= -1.0 # now the ion charge center LOP = self.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] # make dictionary for ease of use zval = {} for sym, ppath, hash in LOP: fullpath = os.path.join(ppp, ppath) z = get_ZVAL(fullpath) zval[sym] = z ion_charge_center = np.array([0.0, 0.0, 0.0]) total_ion_charge = 0.0 for atom in atoms: Z = zval[atom.symbol] total_ion_charge += Z pos = atom.position ion_charge_center += Z * pos ion_charge_center /= total_ion_charge ion_dipole_moment = ion_charge_center * total_ion_charge dipole_vector = (ion_dipole_moment + electron_dipole_moment) return dipole_vector
def get_dipole_moment(self): ''' dipole_moment = ((dipole_vector**2).sum())**0.5/Debye ''' atoms = self.get_atoms() x,y,z,cd = self.get_charge_density() n0, n1, n2 = cd.shape nelements = n0*n1*n2 voxel_volume = atoms.get_volume()/nelements total_electron_charge = -cd.sum()*voxel_volume electron_density_center = np.array([(cd*x).sum(), (cd*y).sum(), (cd*z).sum()]) electron_density_center *= voxel_volume electron_density_center /= total_electron_charge electron_dipole_moment = electron_density_center*total_electron_charge electron_dipole_moment *= -1.0 #we need the - here so the two #negatives don't cancel # now the ion charge center LOP = self.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] # make dictionary for ease of use zval = {} for sym, ppath, hash in LOP: fullpath = os.path.join(ppp, ppath) z = get_ZVAL(fullpath) zval[sym] = z ion_charge_center = np.array([0.0, 0.0, 0.0]) total_ion_charge = 0.0 for atom in atoms: Z = zval[atom.symbol] total_ion_charge += Z pos = atom.position ion_charge_center += Z*pos ion_charge_center /= total_ion_charge ion_dipole_moment = ion_charge_center*total_ion_charge dipole_vector = (ion_dipole_moment + electron_dipole_moment) return dipole_vector
def attach_charges(self, fileobj='ACF.dat', displacement=1e-4): ''' Attach the charges from the fileobj to the Atoms. This is a modified version of the attach_charges function in ase.io.bader to work better with VASP. Does not require the atom positions to be in Bohr and references the charge to the ZVAL in the POTCAR ''' calc = self.get_calculator() # Get the sorting and resorting lists sort = calc.sort resort = calc.resort if isinstance(fileobj, str): fileobj = open(fileobj) f_open = True # First get a dictionary of ZVALS from the pseudopotentials LOP = calc.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] zval = {} for sym, ppath, hash in LOP: fullpath = ppp + ppath z = get_ZVAL(fullpath) zval[sym] = z # Get sorted symbols and positions according to POSCAR and ACF.dat symbols = np.array(self.get_chemical_symbols())[sort] positions = self.get_positions()[sort] charges = [] sep = '---------------' i = 0 # Counter for the lines k = 0 # Counter of sep assume6columns = False for line in fileobj: if line[0] == '\n': # check if there is an empty line in the i -= 1 # head of ACF.dat file if i == 0: headings = line if 'BADER' in headings.split(): j = headings.split().index('BADER') elif 'CHARGE' in headings.split(): j = headings.split().index('CHARGE') else: print('Can\'t find keyword "BADER" or "CHARGE".' \ +' Assuming the ACF.dat file has 6 columns.') j = 4 assume6columns = True if sep in line: # Stop at last seperator line if k == 1: break k += 1 if not i > 1: pass else: words = line.split() if assume6columns is True: if len(words) != 6: raise IOError('Number of columns in ACF file incorrect!\n' 'Check that Bader program version >= 0.25') sym = symbols[int(words[0]) - 1] charges.append(zval[sym] - float(words[j])) if displacement is not None: # check if the atom positions match xyz = np.array([float(w) for w in words[1:4]]) assert np.linalg.norm(positions[int(words[0]) - 1] - xyz) < displacement i += 1 if f_open: fileobj.close() # Now attach the resorted charges to the atom charges = np.array(charges)[resort] for atom in self: atom.charge = charges[atom.index]
def attach_charges(self, fileobj=None, displacement=1e-4): """Attach the charges from the fileobj to the atoms on the calculator. This is a modified version of the attach_charges function in ase.io.bader to work better with VASP. Does not require the atom positions to be in Bohr and references the charge to the ZVAL in the POTCAR """ if fileobj is None: fileobj = os.path.join(self.directory, 'ACF.dat') if isinstance(fileobj, str): fileobj = open(fileobj) f_open = True # First get a dictionary of ZVALS from the pseudopotentials LOP = self.get_pseudopotentials() ppp = os.environ['VASP_PP_PATH'] zval = {} for sym, ppath, hash in LOP: fullpath = os.path.join(ppp, ppath) z = get_ZVAL(fullpath) zval[sym] = z atoms = self.atoms # Get sorted symbols and positions according to POSCAR and ACF.dat symbols = np.array(atoms.get_chemical_symbols())[self.resort] positions = atoms.get_positions()[self.resort] charges = [] sep = '---------------' i = 0 # Counter for the lines k = 0 # Counter of sep assume6columns = False for line in fileobj: if line[0] == '\n': # check if there is an empty line in the i -= 1 # head of ACF.dat file if i == 0: headings = line if 'BADER' in headings.split(): j = headings.split().index('BADER') elif 'CHARGE' in headings.split(): j = headings.split().index('CHARGE') else: print('Can\'t find keyword "BADER" or "CHARGE".' ' Assuming the ACF.dat file has 6 columns.') j = 4 assume6columns = True if sep in line: # Stop at last seperator line if k == 1: break k += 1 if not i > 1: pass else: words = line.split() if assume6columns is True: if len(words) != 6: raise IOError('Number of columns in ACF file incorrect!\n' 'Check that Bader program version >= 0.25') sym = symbols[int(words[0]) - 1] charges.append(zval[sym] - float(words[j])) if displacement is not None: # check if the atom positions match xyz = np.array([float(w) for w in words[1:4]]) assert (np.linalg.norm(positions[int(words[0]) - 1] - xyz) < displacement) i += 1 if f_open: fileobj.close() # Now attach the resorted charges to the atom charges = np.array(charges)[self.resort] for atom in self.atoms: atom.charge = charges[atom.index]