def load(fname): with open(fname, 'rb') as fl: f = pickleload(fl) if not hasattr(f, 'shape'): # output from InfraRed return f[0] return f
def readbee(fname, all=False): if not fname.endswith('.bee'): fname += '.bee' with open(fname, 'rb') as f: e, de, contribs, seed, xc = pickleload(f) if all: return e, de, contribs, seed, xc else: return e + de
def check_eq_forces(self): """Check maximum size of forces in the equilibrium structure.""" fname = '%s.eq.pckl' % self.name feq_av = pickleload(open(fname, 'rb')) fmin = feq_av.max() fmax = feq_av.min() i_min = np.where(feq_av == fmin) i_max = np.where(feq_av == fmax) return fmin, fmax, i_min, i_max
def check_eq_forces(self): """Check maximum size of forces in the equilibrium structure.""" fname = '%s.eq.pckl' % self.name with open(fname, 'rb') as fd: feq_av = pickleload(fd) fmin = feq_av.max() fmax = feq_av.min() i_min = np.where(feq_av == fmin) i_max = np.where(feq_av == fmax) return fmin, fmax, i_min, i_max
def load(fname, combined_data=None): if combined_data is None: with open(fname, 'rb') as fl: f = pickleload(fl) else: try: f = combined_data[op.basename(fname)] except KeyError: f = combined_data[fname] # Old version if not hasattr(f, 'shape') and not hasattr(f, 'keys'): # output from InfraRed return f[0] return f
def read_born_charges(self, name=None, neutrality=True): r"""Read Born charges and dieletric tensor from pickle file. The charge neutrality sum-rule:: _ _ \ a ) Z = 0 /__ ij a Parameters: neutrality: bool Restore charge neutrality condition on calculated Born effective charges. """ # Load file with Born charges and dielectric tensor for atoms in the # unit cell if name is None: filename = '%s.born.pckl' % self.name else: filename = name with open(filename, 'rb') as fd: Z_avv, eps_vv = pickleload(fd) # Neutrality sum-rule if neutrality: Z_mean = Z_avv.sum(0) / len(Z_avv) Z_avv -= Z_mean self.Z_avv = Z_avv[self.indices] self.eps_vv = eps_vv
def read_born_charges(self, name=None, neutrality=True): """Read Born charges and dieletric tensor from pickle file. The charge neutrality sum-rule:: _ _ \ a ) Z = 0 /__ ij a Parameters: neutrality: bool Restore charge neutrality condition on calculated Born effective charges. """ # Load file with Born charges and dielectric tensor for atoms in the # unit cell if name is None: filename = '%s.born.pckl' % self.name else: filename = name with open(filename, 'rb') as fd: Z_avv, eps_vv = pickleload(fd) # Neutrality sum-rule if neutrality: Z_mean = Z_avv.sum(0) / len(Z_avv) Z_avv -= Z_mean self.Z_avv = Z_avv[self.indices] self.eps_vv = eps_vv
def load(fname, combined_data=None): if combined_data is not None: return combined_data[fname] return pickleload(open(fname, 'rb'))
def read(self, method='Frederiksen', symmetrize=3, acoustic=True, cutoff=None, born=False, **kwargs): """Read forces from pickle files and calculate force constants. Extra keyword arguments will be passed to ``read_born_charges``. Parameters: method: str Specify method for evaluating the atomic forces. symmetrize: int Symmetrize force constants (see doc string at top) when ``symmetrize != 0`` (default: 3). Since restoring the acoustic sum rule breaks the symmetry, the symmetrization must be repeated a few times until the changes a insignificant. The integer gives the number of iterations that will be carried out. acoustic: bool Restore the acoustic sum rule on the force constants. cutoff: None or float Zero elements in the dynamical matrix between atoms with an interatomic distance larger than the cutoff. born: bool Read in Born effective charge tensor and high-frequency static dielelctric tensor from file. """ method = method.lower() assert method in ['standard', 'frederiksen'] if cutoff is not None: cutoff = float(cutoff) # Read Born effective charges and optical dielectric tensor if born: self.read_born_charges(**kwargs) # Number of atoms natoms = len(self.indices) # Number of unit cells N = np.prod(self.N_c) # Matrix of force constants as a function of unit cell index in units # of eV / Ang**2 C_xNav = np.empty((natoms * 3, N, natoms, 3), dtype=float) # Loop over all atomic displacements and calculate force constants for i, a in enumerate(self.indices): for j, v in enumerate('xyz'): # Atomic forces for a displacement of atom a in direction v basename = '%s.%d%s' % (self.name, a, v) fminus_av = pickleload(open(basename + '-.pckl', 'rb')) fplus_av = pickleload(open(basename + '+.pckl', 'rb')) if method == 'frederiksen': fminus_av[a] -= fminus_av.sum(0) fplus_av[a] -= fplus_av.sum(0) # Finite difference derivative C_av = fminus_av - fplus_av C_av /= 2 * self.delta # Slice out included atoms C_Nav = C_av.reshape((N, len(self.atoms), 3))[:, self.indices] index = 3 * i + j C_xNav[index] = C_Nav # Make unitcell index the first and reshape C_N = C_xNav.swapaxes(0, 1).reshape((N, ) + (3 * natoms, 3 * natoms)) # Cut off before symmetry and acoustic sum rule are imposed if cutoff is not None: self.apply_cutoff(C_N, cutoff) # Symmetrize force constants if symmetrize: for i in range(symmetrize): # Symmetrize C_N = self.symmetrize(C_N) # Restore acoustic sum-rule if acoustic: self.acoustic(C_N) else: break # Store force constants and dynamical matrix self.C_N = C_N self.D_N = C_N.copy() # Add mass prefactor m_a = self.atoms.get_masses() self.m_inv_x = np.repeat(m_a[self.indices]**-0.5, 3) M_inv = np.outer(self.m_inv_x, self.m_inv_x) for D in self.D_N: D *= M_inv
def read(self, method='standard', direction='central'): self.method = method.lower() self.direction = direction.lower() assert self.method in ['standard', 'frederiksen'] if direction != 'central': raise NotImplementedError( 'Only central difference is implemented at the moment.') # Get "static" dipole moment and forces name = '%s.eq.pckl' % self.name [forces_zero, dipole_zero] = pickleload(open(name, 'rb')) self.dipole_zero = (sum(dipole_zero**2)**0.5) / units.Debye self.force_zero = max( [sum((forces_zero[j])**2)**0.5 for j in self.indices]) ndof = 3 * len(self.indices) H = np.empty((ndof, ndof)) dpdx = np.empty((ndof, 3)) r = 0 for a in self.indices: for i in 'xyz': name = '%s.%d%s' % (self.name, a, i) [fminus, dminus] = pickleload(open(name + '-.pckl', 'rb')) [fplus, dplus] = pickleload(open(name + '+.pckl', 'rb')) if self.nfree == 4: [fminusminus, dminusminus] = pickleload(open(name + '--.pckl', 'rb')) [fplusplus, dplusplus] = pickleload(open(name + '++.pckl', 'rb')) if self.method == 'frederiksen': fminus[a] += -fminus.sum(0) fplus[a] += -fplus.sum(0) if self.nfree == 4: fminusminus[a] += -fminus.sum(0) fplusplus[a] += -fplus.sum(0) if self.nfree == 2: H[r] = (fminus - fplus)[self.indices].ravel() / 2.0 dpdx[r] = (dminus - dplus) if self.nfree == 4: H[r] = (-fminusminus + 8 * fminus - 8 * fplus + fplusplus)[self.indices].ravel() / 12.0 dpdx[r] = (-dplusplus + 8 * dplus - 8 * dminus + dminusminus) / 6.0 H[r] /= 2 * self.delta dpdx[r] /= 2 * self.delta for n in range(3): if n not in self.directions: dpdx[r][n] = 0 dpdx[r][n] = 0 r += 1 # Calculate eigenfrequencies and eigenvectors m = self.atoms.get_masses() H += H.copy().T self.H = H m = self.atoms.get_masses() self.im = np.repeat(m[self.indices]**-0.5, 3) omega2, modes = np.linalg.eigh(self.im[:, None] * H * self.im) self.modes = modes.T.copy() # Calculate intensities dpdq = np.array([ dpdx[j] / sqrt(m[self.indices[j // 3]] * units._amu / units._me) for j in range(ndof) ]) dpdQ = np.dot(dpdq.T, modes) dpdQ = dpdQ.T intensities = np.array([sum(dpdQ[j]**2) for j in range(ndof)]) # Conversion factor: s = units._hbar * 1e10 / sqrt(units._e * units._amu) self.hnu = s * omega2.astype(complex)**0.5 # Conversion factor from atomic units to (D/Angstrom)^2/amu. conv = (1.0 / units.Debye)**2 * units._amu / units._me self.intensities = intensities * conv
def read(self, method='Frederiksen', symmetrize=3, acoustic=True, cutoff=None, born=False, **kwargs): """Read forces from pickle files and calculate force constants. Extra keyword arguments will be passed to ``read_born_charges``. Parameters: method: str Specify method for evaluating the atomic forces. symmetrize: int Symmetrize force constants (see doc string at top) when ``symmetrize != 0`` (default: 3). Since restoring the acoustic sum rule breaks the symmetry, the symmetrization must be repeated a few times until the changes a insignificant. The integer gives the number of iterations that will be carried out. acoustic: bool Restore the acoustic sum rule on the force constants. cutoff: None or float Zero elements in the dynamical matrix between atoms with an interatomic distance larger than the cutoff. born: bool Read in Born effective charge tensor and high-frequency static dielelctric tensor from file. """ method = method.lower() assert method in ['standard', 'frederiksen'] if cutoff is not None: cutoff = float(cutoff) # Read Born effective charges and optical dielectric tensor if born: self.read_born_charges(**kwargs) # Number of atoms natoms = len(self.indices) # Number of unit cells N = np.prod(self.N_c) # Matrix of force constants as a function of unit cell index in units # of eV / Ang**2 C_xNav = np.empty((natoms * 3, N, natoms, 3), dtype=float) # Loop over all atomic displacements and calculate force constants for i, a in enumerate(self.indices): for j, v in enumerate('xyz'): # Atomic forces for a displacement of atom a in direction v basename = '%s.%d%s' % (self.name, a, v) fminus_av = pickleload(open(basename + '-.pckl', 'rb')) fplus_av = pickleload(open(basename + '+.pckl', 'rb')) if method == 'frederiksen': fminus_av[a] -= fminus_av.sum(0) fplus_av[a] -= fplus_av.sum(0) # Finite difference derivative C_av = fminus_av - fplus_av C_av /= 2 * self.delta # Slice out included atoms C_Nav = C_av.reshape((N, len(self.atoms), 3))[:, self.indices] index = 3 * i + j C_xNav[index] = C_Nav # Make unitcell index the first and reshape C_N = C_xNav.swapaxes(0, 1).reshape((N,) + (3 * natoms, 3 * natoms)) # Cut off before symmetry and acoustic sum rule are imposed if cutoff is not None: self.apply_cutoff(C_N, cutoff) # Symmetrize force constants if symmetrize: for i in range(symmetrize): # Symmetrize C_N = self.symmetrize(C_N) # Restore acoustic sum-rule if acoustic: self.acoustic(C_N) else: break # Store force constants and dynamical matrix self.C_N = C_N self.D_N = C_N.copy() # Add mass prefactor m_a = self.atoms.get_masses() print(m_a.shape, self.indices) self.m_inv_x = np.repeat(m_a[self.indices]**-0.5, 3) M_inv = np.outer(self.m_inv_x, self.m_inv_x) for D in self.D_N: D *= M_inv