class UTGaussianWavefunctionSetup(UTDomainParallelSetup): __doc__ = UTDomainParallelSetup.__doc__ + """ The pseudo wavefunctions are moving gaussians centered around each atom.""" allocated = False dtype = None def setUp(self): UTDomainParallelSetup.setUp(self) for virtvar in ['dtype']: assert getattr(self,virtvar) is not None, 'Virtual "%s"!' % virtvar # Set up kpoint descriptor: self.kd = KPointDescriptor(self.nspins, self.nibzkpts, self.kpt_comm, \ self.gamma, self.dtype) # Choose a sufficiently small width of gaussian test functions cell_c = np.sum(self.gd.cell_cv**2, axis=1)**0.5 self.sigma = np.min((0.1+0.4*self.gd.pbc_c)*cell_c) if debug and world.rank == 0: print 'sigma=%8.5f Ang' % (self.sigma*Bohr), 'cell_c:', cell_c*Bohr, 'Ang', 'N_c:', self.gd.N_c self.atoms = create_random_atoms(self.gd, 4, 'H', 4*self.sigma) self.r_vG = None self.wf_uG = None self.laplace0_uG = None self.allocate() def tearDown(self): UTDomainParallelSetup.tearDown(self) del self.phase_ucd, self.atoms, self.r_vG, self.wf_uG, self.laplace0_uG self.allocated = False def allocate(self): if self.allocated: raise RuntimeError('Already allocated!') # Calculate complex phase factors: self.phase_ucd = np.ones((self.kd.mynks, 3, 2), complex) if not self.gamma: for myu, phase_cd in enumerate(self.phase_ucd): u = self.kd.global_index(myu) s, k = self.kd.what_is(u) phase_cd[:] = np.exp(2j * np.pi * self.gd.sdisp_cd * \ self.ibzk_kc[k,:,np.newaxis]) assert self.dtype == complex, 'Complex wavefunctions are required.' self.r_vG = self.gd.get_grid_point_coordinates() self.wf_uG = self.gd.zeros(self.kd.mynks, dtype=self.dtype) self.laplace0_uG = self.gd.zeros(self.kd.mynks, dtype=self.dtype) buf_G = self.gd.empty(dtype=self.dtype) sdisp_Ac = [] for a,spos_c in enumerate(self.atoms.get_scaled_positions() % 1.0): for sdisp_x in range(-1*self.gd.pbc_c[0],self.gd.pbc_c[0]+1): for sdisp_y in range(-1*self.gd.pbc_c[1],self.gd.pbc_c[1]+1): for sdisp_z in range(-1*self.gd.pbc_c[2],self.gd.pbc_c[2]+1): sdisp_c = np.array([sdisp_x, sdisp_y, sdisp_z]) if debug and world.rank == 0: print 'a=%d, spos=%s, sdisp_c=%s' % (a,spos_c,sdisp_c) sdisp_Ac.append((a,spos_c,sdisp_c)) for a,spos_c,sdisp_c in sdisp_Ac: if debug and world.rank == 0: print 'Adding gaussian at a=%d, spos=%s, sigma=%8.5f Ang' % (a,spos_c+sdisp_c,self.sigma*Bohr) r0_v = np.dot(spos_c+sdisp_c, self.gd.cell_cv) for myu in range(self.kd.mynks): u = self.kd.global_index(myu) s, k = self.kd.what_is(u) ibzk_v = self.ibzk_kv[k] # f(r) = sum_a A exp(-|r-R^a|^2 / 2sigma^2) exp(i k.r) gaussian_wave(self.r_vG, r0_v, self.sigma, ibzk_v, A=1.0, dtype=self.dtype, out_G=buf_G) self.wf_uG[myu] += buf_G # d^2/dx^2 exp(ikx-(x-x0)^2/2sigma^2) # ((ik-(x-x0)/sigma^2)^2 - 1/sigma^2) exp(ikx-(x-x0)^2/2sigma^2) dr2_G = np.sum((1j*ibzk_v[:,np.newaxis,np.newaxis,np.newaxis] \ - (self.r_vG-r0_v[:,np.newaxis,np.newaxis,np.newaxis]) \ / self.sigma**2)**2, axis=0) self.laplace0_uG[myu] += (dr2_G - 3/self.sigma**2) * buf_G self.allocated = True # ================================= def test_something(self): laplace_uG = np.empty_like(self.laplace0_uG) op = Laplace(self.gd, dtype=self.dtype) for myu, laplace_G in enumerate(laplace_uG): phase_cd = {float:None, complex:self.phase_ucd[myu]}[self.dtype] op.apply(self.wf_uG[myu], laplace_G, phase_cd) print 'myu:', myu, 'diff:', np.std(laplace_G-self.laplace0_uG[myu]), '/', np.abs(laplace_G-self.laplace0_uG[myu]).max()